From aebbb818acd88ac233ec7b67afc7ddc60aac3aff Mon Sep 17 00:00:00 2001 From: dlond Date: Thu, 9 Apr 2026 11:45:37 +1200 Subject: [PATCH] chore: side quest --- init.lua | 4 +- lazy-lock.json | 53 +++++----- lsp/basedpyright.lua | 24 +++++ lsp/clangd.lua | 110 ++++++++++++++++++++ lsp/cmake.lua | 8 ++ lsp/lua_ls.lua | 17 ++++ lsp/ruff.lua | 19 ++++ lua/core/autocmds.lua | 28 +++-- lua/core/code.lua | 126 +++++++++++++++++++++++ lua/core/cpp_build.lua | 85 ++++++++++++++++ lua/core/float_term.lua | 69 +++++++++++++ lua/core/global.lua | 5 + lua/core/keymaps.lua | 43 ++++---- lua/core/lsp.lua | 12 +++ lua/core/options.lua | 10 +- lua/core/python_run.lua | 70 +++++++++++++ lua/core/shared-session.lua | 99 ------------------ lua/plugins/config/autopairs.lua | 73 -------------- lua/plugins/config/blink-cmp.lua | 0 lua/plugins/config/blink.lua | 157 ----------------------------- lua/plugins/config/cmake-tools.lua | 152 ++++++++++++++++++++++++++++ lua/plugins/config/completion.lua | 52 ---------- lua/plugins/config/conan.lua | 7 ++ lua/plugins/config/editor.lua | 73 ++++++++++++-- lua/plugins/config/lsp/init.lua | 46 --------- lua/plugins/config/lsp/keymaps.lua | 69 ------------- lua/plugins/config/lsp/servers.lua | 156 ---------------------------- lua/plugins/config/nvim-conan.lua | 7 ++ lua/plugins/config/overseer.lua | 7 ++ lua/plugins/config/treesitter.lua | 45 +++++++++ lua/plugins/spec/autopairs.lua | 9 -- lua/plugins/spec/blink-cmp.lua | 28 +++++ lua/plugins/spec/cmake-tools.lua | 10 ++ lua/plugins/spec/completion.lua | 26 ----- lua/plugins/spec/editor.lua | 2 +- lua/plugins/spec/lsp.lua | 26 ----- lua/plugins/spec/nvim-conan.lua | 9 ++ lua/plugins/spec/overseer.lua | 6 ++ lua/plugins/spec/treesitter.lua | 48 ++------- 39 files changed, 972 insertions(+), 818 deletions(-) create mode 100644 lsp/basedpyright.lua create mode 100644 lsp/clangd.lua create mode 100644 lsp/cmake.lua create mode 100644 lsp/lua_ls.lua create mode 100644 lsp/ruff.lua create mode 100644 lua/core/code.lua create mode 100644 lua/core/cpp_build.lua create mode 100644 lua/core/float_term.lua create mode 100644 lua/core/global.lua create mode 100644 lua/core/lsp.lua create mode 100644 lua/core/python_run.lua delete mode 100644 lua/core/shared-session.lua delete mode 100644 lua/plugins/config/autopairs.lua create mode 100644 lua/plugins/config/blink-cmp.lua delete mode 100644 lua/plugins/config/blink.lua create mode 100644 lua/plugins/config/cmake-tools.lua delete mode 100644 lua/plugins/config/completion.lua create mode 100644 lua/plugins/config/conan.lua delete mode 100644 lua/plugins/config/lsp/init.lua delete mode 100644 lua/plugins/config/lsp/keymaps.lua delete mode 100644 lua/plugins/config/lsp/servers.lua create mode 100644 lua/plugins/config/nvim-conan.lua create mode 100644 lua/plugins/config/overseer.lua create mode 100644 lua/plugins/config/treesitter.lua delete mode 100644 lua/plugins/spec/autopairs.lua create mode 100644 lua/plugins/spec/blink-cmp.lua create mode 100644 lua/plugins/spec/cmake-tools.lua delete mode 100644 lua/plugins/spec/completion.lua delete mode 100644 lua/plugins/spec/lsp.lua create mode 100644 lua/plugins/spec/nvim-conan.lua create mode 100644 lua/plugins/spec/overseer.lua diff --git a/init.lua b/init.lua index 8bd0578..5371901 100644 --- a/init.lua +++ b/init.lua @@ -1,11 +1,12 @@ -- Bootstrap lazy.nvim require 'core.bootstrap' +require 'core.global' -- Core settings (must be before plugins) require 'core.options' require 'core.keymaps' require 'core.autocmds' -require('core.shared-session').setup() +require 'core.lsp' vim.env.DEVELOPER_DIR = '/Applications/Xcode.app/Contents/Developer' @@ -15,6 +16,7 @@ require('lazy').setup('plugins.spec', { performance = { rtp = { disabled_plugins = { + 'blink.cmp', 'gzip', 'tarPlugin', 'tohtml', diff --git a/lazy-lock.json b/lazy-lock.json index 93849d6..95f970b 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -1,40 +1,41 @@ { "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, - "blink-cmp-copilot": { "branch": "main", "commit": "439cff78780c033aa23cf061d7315314b347e3c1" }, - "blink.cmp": { "branch": "main", "commit": "485c03400608cb6534bbf84da8c1c471fc4808c0" }, - "conform.nvim": { "branch": "master", "commit": "235dd79731c1dc51ec04abb4045cbc54727a172a" }, - "copilot.lua": { "branch": "master", "commit": "3123983d00ae6859f8bc987d14ebb524bb41b618" }, - "fidget.nvim": { "branch": "main", "commit": "3f5475949679953af6d78654db29b944fa826e6a" }, - "gitsigns.nvim": { "branch": "main", "commit": "20ad4419564d6e22b189f6738116b38871082332" }, - "harpoon": { "branch": "harpoon2", "commit": "ed1f853847ffd04b2b61c314865665e1dadf22c7" }, - "image.nvim": { "branch": "master", "commit": "446a8a5cc7a3eae3185ee0c697732c32a5547a0b" }, - "indent-blankline.nvim": { "branch": "master", "commit": "005b56001b2cb30bfa61b7986bc50657816ba4ba" }, - "lazy.nvim": { "branch": "main", "commit": "1ea3c4085785f460fb0e46d2fe1ee895f5f9e7c1" }, - "lazydev.nvim": { "branch": "main", "commit": "e28ce52fc7ff79fcb76f0e79ee6fb6182fca90b9" }, + "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, + "cmake-tools.nvim": { "branch": "master", "commit": "e100f40b117381dadf42a34b0718f8e4350715b2" }, + "conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" }, + "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, + "gitsigns.nvim": { "branch": "main", "commit": "8d82c240f190fc33723d48c308ccc1ed8baad69d" }, + "harpoon": { "branch": "harpoon2", "commit": "87b1a3506211538f460786c23f98ec63ad9af4e5" }, + "image.nvim": { "branch": "master", "commit": "da2be65c153ba15a14a342b05591652a6df70d58" }, + "indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" }, + "jupytext.vim": { "branch": "master", "commit": "f15aff4515eb6a09afa0d7f41eb23be53c1e2e14" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, "leetcode.nvim": { "branch": "master", "commit": "fdd3f91800b3983e27bc9fcfb99cfa7293d7f11a" }, - "mini.nvim": { "branch": "main", "commit": "cf32454e91b3d963a12fef0314811fb035b62d49" }, + "mini.nvim": { "branch": "main", "commit": "2431902e78b76f435542d1e606f08475360068ca" }, "molten-nvim": { "branch": "main", "commit": "a286aa914d9a154bc359131aab788b5a077a5a99" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, - "nvim-autopairs": { "branch": "master", "commit": "7a2c97cccd60abc559344042fefb1d5a85b3e33b" }, - "nvim-dap": { "branch": "master", "commit": "6782b097af2417a4c3e33849b0a26ae2188bd7ea" }, - "nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" }, + "nvim-conan": { "branch": "main", "commit": "7d011809660832d8402c62fbee191757b5093a75" }, + "nvim-dap": { "branch": "master", "commit": "45a69eba683a2c448dd9ecfc4de89511f0646b5f" }, + "nvim-dap-ui": { "branch": "master", "commit": "1a66cabaa4a4da0be107d5eda6d57242f0fe7e49" }, "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, - "nvim-lspconfig": { "branch": "master", "commit": "e5c61b02f33b5c6538be25b2696b33b4cc91e667" }, + "nvim-lint": { "branch": "master", "commit": "4b03656c09c1561f89b6aa0665c15d292ba9499d" }, "nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" }, - "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" }, - "nvim-treesitter-textobjects": { "branch": "master", "commit": "a9742cbc1f95db9eaf3293bf8cd0622ca36542bb" }, - "nvim-web-devicons": { "branch": "master", "commit": "b8221e42cf7287c4dcde81f232f58d7b947c210d" }, + "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e" }, + "nvim-web-devicons": { "branch": "master", "commit": "95b7a002d5dba1a42eb58f5fac5c565a485eefd0" }, + "oil.nvim": { "branch": "master", "commit": "0fcc83805ad11cf714a949c98c605ed717e0b83e" }, + "overseer.nvim": { "branch": "master", "commit": "f818eefff81f4b12fb7cf236f1b6c16768a2fcbc" }, "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "telescope-fzf-native.nvim": { "branch": "main", "commit": "1f08ed60cafc8f6168b72b80be2b2ea149813e55" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, "telescope.nvim": { "branch": "0.1.x", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" }, - "todo-comments.nvim": { "branch": "main", "commit": "19d461ddd543e938eb22505fb03fa878800270b6" }, - "tokyonight.nvim": { "branch": "main", "commit": "e63c42a42b11cd6225f009dd949b9ee0fccc15ef" }, - "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" }, + "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, "vim-illuminate": { "branch": "master", "commit": "0d1e93684da00ab7c057410fecfc24f434698898" }, "vim-ocaml": { "branch": "master", "commit": "ee14abbe433dcf5b85863e19900dea60e090b87d" }, "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" }, - "vim-slime": { "branch": "main", "commit": "67b24bf93cff3ac39db94694a7aefcdb3f44b927" }, - "vim-tmux-navigator": { "branch": "master", "commit": "c45243dc1f32ac6bcf6068e5300f3b2b237e576a" }, - "which-key.nvim": { "branch": "main", "commit": "b4177e3eaf15fe5eb8357ebac2286d488be1ed00" } + "vim-slime": { "branch": "main", "commit": "2cfdc3b24e7ebaa64f5a1a04b00555600c622b79" }, + "vim-tmux-navigator": { "branch": "master", "commit": "e41c431a0c7b7388ae7ba341f01a0d217eb3a432" }, + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } } diff --git a/lsp/basedpyright.lua b/lsp/basedpyright.lua new file mode 100644 index 0000000..3d347ab --- /dev/null +++ b/lsp/basedpyright.lua @@ -0,0 +1,24 @@ +---@type vim.lsp.Config +return { + cmd = { 'basedpyright-langserver', '--stdio' }, + filetypes = { 'python' }, + root_markers = { + 'pyproject.toml', + 'pyrightconfig.json', + '.git', + }, + settings = { + basedpyright = { + analysis = { + typeCheckingMode = 'standard', + autoSearchPaths = true, + diagnosticMode = 'openFilesOnly', + diagnosticSeverityOverrides = { + reportUnusedImport = 'none', + reportDuplicateImport = 'none', + reportUnusedVariable = 'none', + }, + }, + }, + }, +} diff --git a/lsp/clangd.lua b/lsp/clangd.lua new file mode 100644 index 0000000..cee649b --- /dev/null +++ b/lsp/clangd.lua @@ -0,0 +1,110 @@ +---@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, client) + local method_name = 'textDocument/switchSourceHeader' + ---@diagnostic disable-next-line:param-type-mismatch + if not client or not client:supports_method(method_name) 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) + ---@diagnostic disable-next-line:param-type-mismatch + 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(bufnr, client) + local method_name = 'textDocument/symbolInfo' + ---@diagnostic disable-next-line:param-type-mismatch + if not client or not client:supports_method(method_name) 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, client.offset_encoding) + ---@diagnostic disable-next-line:param-type-mismatch + client:request(method_name, params, function(err, res) + if err or #res == 0 then + -- Clangd always returns an error, there is no 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, + title = 'Symbol Info', + }) + end, bufnr) +end + +---@class ClangdInitializeResult: lsp.InitializeResult +---@field offsetEncoding? string + +---@type vim.lsp.Config +return { + cmd = { 'clangd' }, + filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' }, + root_markers = { + '.clangd', + '.clang-tidy', + '.clang-format', + 'compile_commands.json', + 'compile_flags.txt', + 'configure.ac', -- AutoTools + '.git', + }, + get_language_id = function(_, ftype) + local t = { objc = 'objective-c', objcpp = 'objective-cpp', cuda = 'cuda-cpp' } + return t[ftype] or ftype + end, + capabilities = { + textDocument = { + completion = { + editsNearCursor = true, + }, + }, + offsetEncoding = { 'utf-8', 'utf-16' }, + }, + ---@param init_result ClangdInitializeResult + on_init = function(client, init_result) + if init_result.offsetEncoding then + client.offset_encoding = init_result.offsetEncoding + end + end, + on_new_config = function(new_config, new_cwd) + local status, cmake = pcall(require, 'cmake-tools') + if status then + cmake.clangd_on_new_config(new_config) + end + end, + on_attach = function(client, bufnr) + vim.api.nvim_buf_create_user_command(bufnr, 'LspClangdSwitchSourceHeader', function() + switch_source_header(bufnr, client) + end, { desc = 'Switch between source/header' }) + + vim.api.nvim_buf_create_user_command(bufnr, 'LspClangdShowSymbolInfo', function() + symbol_info(bufnr, client) + end, { desc = 'Show symbol info' }) + end, +} diff --git a/lsp/cmake.lua b/lsp/cmake.lua new file mode 100644 index 0000000..3255edd --- /dev/null +++ b/lsp/cmake.lua @@ -0,0 +1,8 @@ +return { + cmd = { 'cmake-language-server' }, + filetypes = { 'cmake' }, + root_markers = { 'CMakePresets.json', 'CTestConfig.cmake', '.git', 'build', 'cmake' }, + init_options = { + buildDirectory = 'build', + }, +} diff --git a/lsp/lua_ls.lua b/lsp/lua_ls.lua new file mode 100644 index 0000000..a7139e7 --- /dev/null +++ b/lsp/lua_ls.lua @@ -0,0 +1,17 @@ +---@type vim.lsp.Config +return { + cmd = { 'lua-language-server' }, + filetypes = { 'lua' }, + root_markers = { { '.luarc.json', '.luarc.jsonc' }, '.git' }, + settings = { + Lua = { + runtime = { version = 'LuaJIT' }, + diagnostics = { globals = { 'vim' } }, + workspace = { + checkThirdParty = false, + library = vim.api.nvim_get_runtime_file('', true), + }, + telemetry = { enable = false }, + }, + }, +} diff --git a/lsp/ruff.lua b/lsp/ruff.lua new file mode 100644 index 0000000..014080b --- /dev/null +++ b/lsp/ruff.lua @@ -0,0 +1,19 @@ +---@type vim.lsp.Config +return { + cmd = { 'ruff', 'server' }, + filetypes = { 'python' }, + root_markers = { 'pyproject.toml', 'ruff.toml', '.ruff.toml', '.git' }, + settings = { + configurationPreference = 'filesystemFirst', + lineLength = 100, + editor = { + -- Let conform handle all format on saves + formatOnSave = false, + }, + lint = { + enable = true, + select = { 'E', 'F', 'I', 'B', 'UP' }, + extendSelect = { 'W' }, + }, + }, +} diff --git a/lua/core/autocmds.lua b/lua/core/autocmds.lua index 1380e91..a9e7c8d 100644 --- a/lua/core/autocmds.lua +++ b/lua/core/autocmds.lua @@ -12,15 +12,31 @@ vim.api.nvim_create_autocmd('TextYankPost', { end, }) +local lsp_augroup = vim.api.nvim_create_augroup('UserLspConfig', { clear = true }) + vim.api.nvim_create_autocmd('LspAttach', { + group = lsp_augroup, callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) - if client and client.server_capabilities.codeLensProvider then - vim.lsp.codelens.refresh() - vim.api.nvim_create_autocmd({ 'BufEnter', 'CursorHold', 'InsertLeave' }, { - buffer = args.buf, - callback = vim.lsp.codelens.refresh, - }) + if not client then + return + end + + -- 1. CodeLens + if client:supports_method(vim.lsp.protocol.Methods.textDocument_codeLens) then + vim.lsp.codelens.enable(true, { bufnr = args.buf }) + end + + -- 2. Native Completion + if client:supports_method(vim.lsp.protocol.Methods.textDocument_completion) then + vim.opt.completeopt = { 'menu', 'menuone', 'noinsert', 'fuzzy', 'popup' } + vim.lsp.completion.enable(true, client.id, args.buf, { autotrigger = true }) + end + + -- 3. Capability Overrides + if client.name == 'ruff' then + client.server_capabilities.hoverProvider = false + client.server_capabilities.definitionProvider = false end end, }) diff --git a/lua/core/code.lua b/lua/core/code.lua new file mode 100644 index 0000000..ec67f8f --- /dev/null +++ b/lua/core/code.lua @@ -0,0 +1,126 @@ +-- Generic code runner with pluggable backends. +-- Each backend implements: setup(), configure(), build(), run(), test(), status(), reset() +-- Dependencies are chained automatically: run → build → configure → setup + +local float_term = require('core.float_term') + +local M = {} + +local backends = {} +local active_backend = nil + +function M.register(name, backend) + backends[name] = backend + backend.name = name + backend.term = float_term +end + +local function detect_backend() + if active_backend then return active_backend end + + -- Auto-detect from project files + if vim.fn.filereadable('CMakeLists.txt') == 1 then + active_backend = backends['cpp'] + elseif vim.fn.filereadable('pyproject.toml') == 1 + or vim.fn.filereadable('setup.py') == 1 + or vim.fn.filereadable('requirements.txt') == 1 then + active_backend = backends['python'] + end + + return active_backend +end + +local function with_backend(callback) + local b = detect_backend() + if b then return callback(b) end + + local names = vim.tbl_keys(backends) + if #names == 0 then + vim.notify('No code backends registered', vim.log.levels.WARN) + return + end + + vim.ui.select(names, { prompt = 'Project type:' }, function(choice) + if not choice then return end + active_backend = backends[choice] + callback(active_backend) + end) +end + +-- Pipeline: each step ensures its dependencies +local function ensure_setup(b, callback) + if not b.setup then return callback() end + b.setup(callback) +end + +local function ensure_configure(b, callback) + ensure_setup(b, function() + if not b.configure then return callback() end + b.configure(callback) + end) +end + +local function ensure_build(b, target, callback) + ensure_configure(b, function() + if not b.build then return callback() end + b.build(target, callback) + end) +end + +function M.configure() + with_backend(function(b) + ensure_configure(b, function() end) + end) +end + +function M.build(target) + with_backend(function(b) + ensure_build(b, target, function() end) + end) +end + +function M.run() + with_backend(function(b) + if not b.run then + vim.notify(b.name .. ': run not implemented', vim.log.levels.WARN) + return + end + b.run() + end) +end + +function M.test() + with_backend(function(b) + if not b.test then + vim.notify(b.name .. ': test not implemented', vim.log.levels.WARN) + return + end + b.test() + end) +end + +function M.go() + with_backend(function(b) + if not b.go then + vim.notify(b.name .. ': interactive mode not implemented', vim.log.levels.WARN) + return + end + b.go() + end) +end + +function M.status() + with_backend(function(b) + if b.status then b.status() end + end) +end + +function M.reset() + if active_backend and active_backend.reset then + active_backend.reset() + end + active_backend = nil + vim.notify('Code runner reset', vim.log.levels.INFO) +end + +return M diff --git a/lua/core/cpp_build.lua b/lua/core/cpp_build.lua new file mode 100644 index 0000000..d06ca68 --- /dev/null +++ b/lua/core/cpp_build.lua @@ -0,0 +1,85 @@ +-- C++ backend for core.code +-- Delegates to cmake-tools.nvim and nvim-conan for the heavy lifting + +local code = require('core.code') + +local M = {} + +local state = { + conan = false, +} + +function M.status() + local conan = state.conan and 'ok' or 'pending' + -- cmake-tools tracks its own state (preset, build type, target) + vim.notify(string.format('C++ conan=%s (use :CMakeSettings for cmake state)', conan), vim.log.levels.INFO) +end + +function M.reset() + state.conan = false + vim.notify('C++ conan state reset (use :CMakeSelectConfigurePreset to reconfigure)', vim.log.levels.INFO) +end + +function M.setup(callback) + -- cmake-tools handles preset selection via :CMakeSelectConfigurePreset + -- just ensure conan has been run + if state.conan then return callback() end + vim.ui.select({ 'Yes', 'No' }, { prompt = 'Run conan install first?' }, function(choice) + if choice == 'Yes' then + vim.cmd('Conan install') + state.conan = true + end + callback() + end) +end + +function M.configure(callback) + M.setup(function() + vim.cmd('CMakeGenerate') + callback() + end) +end + +function M.build(target, callback) + if target then + vim.cmd('CMakeBuild --target ' .. target) + else + vim.cmd('CMakeBuild') + end + if callback then callback() end +end + +function M.run() + vim.cmd('CMakeRun') +end + +function M.test() + vim.cmd('CTest') +end + +function M.go() + M.setup(function() + vim.ui.select({ 'configure', 'build', 'run', 'test', 'select preset', 'select target' }, { + prompt = 'C++:', + }, function(choice) + if not choice then return end + if choice == 'configure' then + vim.cmd('CMakeGenerate') + elseif choice == 'build' then + vim.cmd('CMakeBuild') + elseif choice == 'run' then + vim.cmd('CMakeRun') + elseif choice == 'test' then + vim.cmd('CTest') + elseif choice == 'select preset' then + vim.cmd('CMakeSelectConfigurePreset') + elseif choice == 'select target' then + vim.cmd('CMakeSelectLaunchTarget') + end + end) + end) +end + +code.register('cpp', M) + +return M diff --git a/lua/core/float_term.lua b/lua/core/float_term.lua new file mode 100644 index 0000000..e6cede9 --- /dev/null +++ b/lua/core/float_term.lua @@ -0,0 +1,69 @@ +local M = {} + +local buf = nil +local win = nil +local chan = nil + +function M.open(cmd) + -- Toggle off if already visible and no command to send + if win and vim.api.nvim_win_is_valid(win) then + if not cmd then + vim.api.nvim_win_hide(win) + return + end + end + + -- Create buffer if needed + if not buf or not vim.api.nvim_buf_is_valid(buf) then + buf = vim.api.nvim_create_buf(false, true) + chan = nil + end + + -- Open window if needed + if not win or not vim.api.nvim_win_is_valid(win) then + local width = math.floor(vim.o.columns * 0.8) + local height = math.floor(vim.o.lines * 0.8) + win = vim.api.nvim_open_win(buf, true, { + relative = 'editor', + width = width, + height = height, + col = math.floor((vim.o.columns - width) / 2), + row = math.floor((vim.o.lines - height) / 2), + style = 'minimal', + border = 'rounded', + }) + end + + -- Start terminal if needed + if not chan then + vim.cmd.terminal() + chan = vim.bo[buf].channel + end + + -- Send command if provided + if cmd then + vim.api.nvim_chan_send(chan, cmd .. '\n') + end + + vim.cmd.startinsert() +end + +function M.send(cmd) + if chan then + M.open(cmd) + end +end + +function M.reset() + if buf and vim.api.nvim_buf_is_valid(buf) then + if win and vim.api.nvim_win_is_valid(win) then + vim.api.nvim_win_hide(win) + end + vim.api.nvim_buf_delete(buf, { force = true }) + end + buf = nil + win = nil + chan = nil +end + +return M diff --git a/lua/core/global.lua b/lua/core/global.lua new file mode 100644 index 0000000..cba3ede --- /dev/null +++ b/lua/core/global.lua @@ -0,0 +1,5 @@ +-- Set as the leader key +-- See `:help mapleader` +-- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used) +vim.g.mapleader = ' ' +vim.g.maplocalleader = ' ' diff --git a/lua/core/keymaps.lua b/lua/core/keymaps.lua index e5b5574..eb3d5a7 100644 --- a/lua/core/keymaps.lua +++ b/lua/core/keymaps.lua @@ -10,24 +10,6 @@ vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' } -- NOTE: Window navigation is handled by nvim-tmux-navigator plugin -- which provides seamless navigation between vim splits and tmux panes --- LSP reload function -local function reload_lsp() - local clients = vim.lsp.get_clients() - if #clients == 0 then - print 'No LSP clients running' - return - end - - for _, client in ipairs(clients) do - vim.lsp.stop_client(client.id) - end - - vim.defer_fn(function() - vim.cmd 'LspStart' - print 'LSP servers reloaded' - end, 500) -end - -- Buffer management keymaps vim.keymap.set('n', 'bb', 'Telescope buffers', { desc = '[B]rowse [B]uffers' }) vim.keymap.set('n', '[b', 'bprevious', { desc = 'Previous buffer' }) @@ -60,5 +42,30 @@ vim.keymap.set('n', 'S', ':%s//', { desc = '[S]ubstitute curre vim.keymap.set('v', 'J', ":m '>+1gv=gv") vim.keymap.set('v', 'K', ":m '<-2gv=gv") +-- Floating terminal +local float_term = require('core.float_term') + +vim.keymap.set('n', 'tf', function() float_term.open() end, { desc = '[T]erminal [F]loat' }) +vim.keymap.set('n', 'tx', function() float_term.reset() end, { desc = '[T]erminal kill/reset' }) +vim.keymap.set('n', 'tr', function() + vim.ui.input({ prompt = 'Run: ' }, function(input) + if input and input ~= '' then + float_term.open(input) + end + end) +end, { desc = '[T]erminal [R]un command' }) + +-- Code runner (auto-detects backend: cpp, python, etc.) +local code = require('core.code') +require('core.cpp_build') -- registers the cpp backend +require('core.python_run') -- registers the python backend + +vim.keymap.set('n', 'cc', function() code.go() end, { desc = '[C]ode [C]onfigure & run' }) +vim.keymap.set('n', 'cb', function() code.build() end, { desc = '[C]ode [B]uild' }) +vim.keymap.set('n', 'cr', function() code.run() end, { desc = '[C]ode [R]un' }) +vim.keymap.set('n', 'ct', function() code.test() end, { desc = '[C]ode [T]est' }) +vim.keymap.set('n', 'cs', function() code.status() end, { desc = '[C]ode [S]tatus' }) +vim.keymap.set('n', 'cx', function() code.reset() end, { desc = '[C]ode reset' }) + -- Standard practice for Lua modules that don't need to return complex data return {} diff --git a/lua/core/lsp.lua b/lua/core/lsp.lua new file mode 100644 index 0000000..87f63b9 --- /dev/null +++ b/lua/core/lsp.lua @@ -0,0 +1,12 @@ +vim.lsp.enable 'basedpyright' +vim.lsp.enable 'lua_ls' +vim.lsp.enable 'ruff' +vim.lsp.enable 'clangd' +vim.lsp.enable 'cmake' + +-- TODO enable diagnostics +vim.diagnostic.config { + virtual_lines = { + current_line = true, + }, +} diff --git a/lua/core/options.lua b/lua/core/options.lua index 3e951cb..76e7668 100644 --- a/lua/core/options.lua +++ b/lua/core/options.lua @@ -1,9 +1,3 @@ --- Set as the leader key --- See `:help mapleader` --- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used) -vim.g.mapleader = ' ' -vim.g.maplocalleader = ' ' - -- Load Nix-controlled settings if available pcall(require, 'nix-settings') @@ -64,3 +58,7 @@ vim.opt.cursorline = true -- Minimal number of screen lines to keep above and below the cursor vim.opt.scrolloff = 10 + +-- Set the default boarder for all floating windows +vim.opt.winborder = 'rounded' +vim.o.autocomplete = true diff --git a/lua/core/python_run.lua b/lua/core/python_run.lua new file mode 100644 index 0000000..105f0c9 --- /dev/null +++ b/lua/core/python_run.lua @@ -0,0 +1,70 @@ +-- Python backend for core.code +-- Projects use uv with venv already activated via nix flake + +local code = require('core.code') + +local M = {} + +local state = { + synced = false, +} + +function M.status() + local synced = state.synced and 'ok' or 'pending' + vim.notify(string.format('Python [uv] sync=%s', synced), vim.log.levels.INFO) +end + +function M.reset() + state.synced = false + vim.notify('Python state reset', vim.log.levels.INFO) +end + +function M.configure(callback) + if state.synced then return callback() end + M.term.open('uv sync') + state.synced = true + callback() +end + +function M.run() + M.configure(function() + local file = vim.fn.expand('%:p') + if file:match('%.py$') then + M.term.open('uv run python ' .. file) + else + vim.ui.input({ prompt = 'Python file: ', default = 'main.py' }, function(input) + if input and input ~= '' then + M.term.open('uv run python ' .. input) + end + end) + end + end) +end + +function M.test() + M.configure(function() + M.term.open('uv run pytest') + end) +end + +function M.go() + vim.ui.select({ 'run current file', 'run main.py', 'test', 'sync' }, { prompt = 'Python:' }, function(choice) + if not choice then return end + if choice == 'run current file' then + M.run() + elseif choice == 'run main.py' then + M.configure(function() + M.term.open('uv run python main.py') + end) + elseif choice == 'test' then + M.test() + elseif choice == 'sync' then + state.synced = false + M.configure(function() end) + end + end) +end + +code.register('python', M) + +return M diff --git a/lua/core/shared-session.lua b/lua/core/shared-session.lua deleted file mode 100644 index 02593cd..0000000 --- a/lua/core/shared-session.lua +++ /dev/null @@ -1,99 +0,0 @@ --- lua/core/shared-session.lua --- Protection for shared tmux nvim sessions - -local M = {} - --- Check if we're in a shared tmux session -local function is_shared_session() - local tmux = vim.env.TMUX - if not tmux or tmux == '' then - return false - end - - local handle = io.popen "tmux display-message -p '#{session_name}' 2>/dev/null" - if handle then - local session_name = handle:read('*a'):gsub('\n', '') - handle:close() - return session_name:match '%-nvim%-shared$' ~= nil - end - return false -end - --- Check if any buffers have unsaved changes -local function has_unsaved_changes() - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].modified then - return true - end - end - return false -end - --- Create wrapper commands that check before quitting -local function create_quit_command(cmd_name, vim_cmd) - vim.api.nvim_create_user_command(cmd_name, function(opts) - local cmd = vim_cmd .. (opts.bang and '!' or '') - - -- For non-bang quit commands, check for unsaved changes first - if not opts.bang and vim_cmd:match('^q') and has_unsaved_changes() then - -- Let Vim handle this naturally by just running the command - -- It will show the proper E37 error - vim.cmd(cmd) - return - end - - -- Only check shared session if the quit would succeed - if is_shared_session() then - local response = vim.fn.input '⚠️ Closing shared nvim session! Confirm with y/Y: ' - if response:lower() ~= 'y' then - print '\nQuit cancelled' - return - end - end - - -- Execute the command - vim.cmd(cmd) - end, { bang = true }) -end - -function M.setup() - -- Only hook into explicit session-ending commands - -- Don't override basic :q since that's often used to close windows - - -- Override only the "quit all" commands - vim.cmd [[ - cabbrev qa =(getcmdtype()==':' && getcmdpos()==1 ? 'Qa' : 'qa') - cabbrev qall =(getcmdtype()==':' && getcmdpos()==1 ? 'Qa' : 'qall') - ]] - - create_quit_command('Qa', 'qa') - - -- Override ZZ (save and quit) - this always ends the session - vim.keymap.set('n', 'ZZ', function() - -- ZZ saves then quits, so just check session - if is_shared_session() then - local response = vim.fn.input '⚠️ ZZ will close shared nvim session! Confirm with y/Y: ' - if response:lower() ~= 'y' then - print '\nQuit cancelled' - return - end - end - -- Execute normal ZZ behavior - vim.cmd 'wq' - end, { desc = 'Save and quit with shared session check' }) - - -- Override ZQ (force quit) - this always ends the session - vim.keymap.set('n', 'ZQ', function() - if is_shared_session() then - local response = vim.fn.input '⚠️ ZQ will close shared nvim session! Confirm with y/Y: ' - if response:lower() ~= 'y' then - print '\nQuit cancelled' - return - end - end - -- Execute normal ZQ behavior - vim.cmd 'q!' - end, { desc = 'Quit without saving with shared session check' }) -end - -return M \ No newline at end of file diff --git a/lua/plugins/config/autopairs.lua b/lua/plugins/config/autopairs.lua deleted file mode 100644 index f8a0647..0000000 --- a/lua/plugins/config/autopairs.lua +++ /dev/null @@ -1,73 +0,0 @@ --- Auto-pairs - Automatically close brackets, quotes, etc. -local M = {} - -function M.setup() - pcall(function() - require('vim._extui').enable {} - end) - - require('blink.pairs').setup { - mappings = { - enabled = true, - cmdline = true, - disabled_filetypes = { 'TelescopePrompt', 'spectre_panel' }, - wrap = { - [''] = 'motion', - [''] = 'motion_reverse', - [''] = 'treesitter', - [''] = 'treesitter_reverse', - }, - }, - highlights = { - enabled = true, - cmdline = true, - groups = { - 'BlinkPairsOrange', - 'BlinkPairsPurple', - 'BlinkPairsBlue', - }, - unmatched_group = 'BlinkPairsUnmatched', - - -- highlights matching pairs under the cursor - matchparen = { - enabled = true, - -- known issue where typing won't update matchparen highlight, disabled by default - cmdline = false, - -- also include pairs not on top of the cursor, but surrounding the cursor - include_surrounding = false, - group = 'BlinkPairsMatchParen', - priority = 250, - }, - }, - debug = false, - } - - -- UNIFIED KEY TO KILL AUTO-INSERTED STUFF - -- already kills auto-inserted comments (built-in) - -- Let's add to also kill auto-paired character - - vim.keymap.set('i', '', function() - local line = vim.api.nvim_get_current_line() - local col = vim.fn.col '.' - 1 - - -- Check if we're at the beginning of a line with just comment chars - local comment_pattern = '^%s*[#%-/]+%s*$' - if line:sub(1, col):match(comment_pattern) then - -- Kill the whole comment prefix (default behavior) - return '' - -- Check if cursor is between paired characters - elseif col > 0 and col < #line then - local before = line:sub(col, col) - local after = line:sub(col + 1, col + 1) - local pairs = { ['('] = ')', ['['] = ']', ['{'] = '}', ['"'] = '"', ["'"] = "'" } - if pairs[before] == after then - -- Delete the closing pair - return '' - end - end - -- Otherwise, regular (kill to start of line) - return '' - end, { expr = true, desc = 'Kill auto-insert or line to start' }) -end - -return M diff --git a/lua/plugins/config/blink-cmp.lua b/lua/plugins/config/blink-cmp.lua new file mode 100644 index 0000000..e69de29 diff --git a/lua/plugins/config/blink.lua b/lua/plugins/config/blink.lua deleted file mode 100644 index 4496226..0000000 --- a/lua/plugins/config/blink.lua +++ /dev/null @@ -1,157 +0,0 @@ --- Blink.cmp Configuration -local M = {} - -function M.setup() - require('blink.cmp').setup { - -- Keymap configuration - keymap = { - preset = 'default', - [''] = { 'show', 'show_documentation', 'hide_documentation' }, - [''] = { 'hide' }, - [''] = { 'select_and_accept' }, - - [''] = { 'select_prev', 'fallback' }, - [''] = { 'select_next', 'fallback' }, - - [''] = { 'scroll_documentation_up', 'fallback' }, - [''] = { 'scroll_documentation_down', 'fallback' }, - - [''] = { 'snippet_forward', 'fallback' }, - [''] = { 'snippet_backward', 'fallback' }, - }, - - -- Appearance configuration - appearance = { - -- use_nvim_cmp_as_default = true, - nerd_font_variant = 'mono', - kind_icons = { - Copilot = '', - Text = '', - Method = 'ƒ', - Function = 'ƒ', - Constructor = '', - Field = '', - Variable = '', - Property = '', - Class = '', - Interface = '', - Struct = '', - Module = '', - Unit = '', - Value = '', - Enum = '', - EnumMember = '', - Keyword = '', - Constant = '', - Snippet = ' ', - Color = '', - File = '', - Reference = '', - Folder = '', - Event = '', - Operator = '', - TypeParameter = '', - }, - }, - - -- Sources configuration with Copilot integration - sources = { - default = { 'lsp', 'path', 'snippets', 'buffer', 'copilot' }, - providers = { - copilot = { - name = 'copilot', - module = 'blink-cmp-copilot', - score_offset = -5, - async = true, - transform_items = function(_, items) - local CompletionItemKind = require('blink.cmp.types').CompletionItemKind - local kind_idx = #CompletionItemKind + 1 - CompletionItemKind[kind_idx] = 'Copilot' - for _, item in ipairs(items) do - item.kind = kind_idx - end - return items - end, - }, - }, - }, - - -- Command line configuration (new API) - cmdline = { - enabled = true, - }, - - -- Signature help configuration - signature = { - enabled = true, - window = { - border = 'rounded', - }, - }, - - -- Completion configuration - completion = { - keyword = { range = 'full' }, - accept = { - -- Auto-insert brackets for functions - auto_brackets = { - enabled = true, - }, - }, - menu = { - draw = { - columns = { - { 'label', 'label_description', gap = 1 }, - { 'kind_icon', 'kind' }, - }, - }, - border = 'rounded', - winblend = 0, - }, - documentation = { - auto_show = true, - auto_show_delay_ms = 500, - window = { - border = 'rounded', - }, - }, - ghost_text = { - enabled = false, -- Disabled: was showing unwanted text on Tab - }, - }, - - -- Fuzzy matching configuration - fuzzy = { - -- Use Rust implementation for better performance - implementation = 'prefer_rust_with_warning', - -- Allow typos based on keyword length - max_typos = function(keyword) - return math.floor(#keyword / 4) - end, - -- Track frequently/recently used items - use_frecency = true, - -- Boost items matching nearby words - use_proximity = true, - -- Prebuilt binaries configuration - prebuilt_binaries = { - download = true, - }, - }, - - -- Snippet configuration - snippets = { - expand = function(snippet) - -- Use native snippet expansion if available - if vim.snippet then - vim.snippet.expand(snippet) - else - -- Fallback to basic expansion - local insert = string.gsub(snippet, '%$%d+', '') - vim.api.nvim_put({ insert }, 'c', true, true) - end - end, - }, - } -end - -return M diff --git a/lua/plugins/config/cmake-tools.lua b/lua/plugins/config/cmake-tools.lua new file mode 100644 index 0000000..19a2d5d --- /dev/null +++ b/lua/plugins/config/cmake-tools.lua @@ -0,0 +1,152 @@ +local M = {} + +function M.setup() + local osys = require 'cmake-tools.osys' + require('cmake-tools'):setup { + cmake_command = 'cmake', -- this is used to specify cmake command path + ctest_command = 'ctest', -- this is used to specify ctest command path + ctest_show_labels = false, -- also show labels in the test picker + cmake_use_preset = true, + cmake_regenerate_on_save = true, -- auto generate when save CMakeLists.txt + cmake_generate_options = { '-DCMAKE_EXPORT_COMPILE_COMMANDS=1' }, -- this will be passed when invoke `CMakeGenerate` + cmake_build_options = {}, -- this will be passed when invoke `CMakeBuild` + -- support macro expansion: + -- ${kit} + -- ${kitGenerator} + -- ${variant:xx} + cmake_build_directory = function() + if osys.iswin32 then + return 'out\\${variant:buildType}' + end + return 'out/${variant:buildType}' + end, -- this is used to specify generate directory for cmake, allows macro expansion, can be a string or a function returning the string, relative to cwd. + cmake_compile_commands_options = { + action = 'none', -- available options: soft_link, copy, lsp, none + -- soft_link: this will automatically make a soft link from compile commands file to target + -- copy: this will automatically copy compile commands file to target + -- lsp: this will automatically set compile commands file location using lsp + -- none: this will make this option ignored + target = vim.loop.cwd, -- path or function returning path to directory, this is used only if action == "soft_link" or action == "copy" + }, + cmake_kits_path = nil, -- this is used to specify global cmake kits path, see CMakeKits for detailed usage + cmake_variants_message = { + short = { show = true }, -- whether to show short message + long = { show = true, max_length = 40 }, -- whether to show long message + }, + cmake_dap_configuration = { -- debug settings for cmake + name = 'cpp', + type = 'codelldb', + request = 'launch', + stopOnEntry = false, + runInTerminal = true, + console = 'integratedTerminal', + }, + cmake_executor = { -- executor to use + name = 'quickfix', -- name of the executor + opts = {}, -- the options the executor will get, possible values depend on the executor type. See `default_opts` for possible values. + default_opts = { -- a list of default and possible values for executors + quickfix = { + show = 'always', -- "always", "only_on_error" + position = 'belowright', -- "vertical", "horizontal", "leftabove", "aboveleft", "rightbelow", "belowright", "topleft", "botright", use `:h vertical` for example to see help on them + size = 10, + encoding = 'utf-8', -- if encoding is not "utf-8", it will be converted to "utf-8" using `vim.fn.iconv` + auto_close_when_success = true, -- typically, you can use it with the "always" option; it will auto-close the quickfix buffer if the execution is successful. + }, + toggleterm = { + direction = 'float', -- 'vertical' | 'horizontal' | 'tab' | 'float' + close_on_exit = false, -- whether close the terminal when exit + auto_scroll = true, -- whether auto scroll to the bottom + singleton = true, -- single instance, autocloses the opened one, if present + }, + overseer = { + new_task_opts = { + strategy = { + 'toggleterm', + direction = 'horizontal', + auto_scroll = true, + quit_on_exit = 'success', + }, + }, -- options to pass into the `overseer.new_task` command + on_new_task = function(task) + require('overseer').open { enter = false, direction = 'right' } + end, -- a function that gets overseer.Task when it is created, before calling `task:start` + }, + terminal = { + name = 'Main Terminal', + prefix_name = '[CMakeTools]: ', -- This must be included and must be unique, otherwise the terminals will not work. Do not use a simple spacebar " ", or any generic name + split_direction = 'horizontal', -- "horizontal", "vertical" + split_size = 11, + + -- Window handling + single_terminal_per_instance = true, -- Single viewport, multiple windows + single_terminal_per_tab = true, -- Single viewport per tab + keep_terminal_static_location = true, -- Static location of the viewport if avialable + auto_resize = true, -- Resize the terminal if it already exists + + -- Running Tasks + start_insert = false, -- If you want to enter terminal with :startinsert upon using :CMakeRun + focus = false, -- Focus on terminal when cmake task is launched. + do_not_add_newline = false, -- Do not hit enter on the command inserted when using :CMakeRun, allowing a chance to review or modify the command before hitting enter. + }, -- terminal executor uses the values in cmake_terminal + }, + }, + cmake_runner = { -- runner to use + name = 'terminal', -- name of the runner + opts = {}, -- the options the runner will get, possible values depend on the runner type. See `default_opts` for possible values. + default_opts = { -- a list of default and possible values for runners + quickfix = { + show = 'always', -- "always", "only_on_error" + position = 'belowright', -- "bottom", "top" + size = 10, + encoding = 'utf-8', + auto_close_when_success = true, -- typically, you can use it with the "always" option; it will auto-close the quickfix buffer if the execution is successful. + }, + toggleterm = { + direction = 'float', -- 'vertical' | 'horizontal' | 'tab' | 'float' + close_on_exit = false, -- whether close the terminal when exit + auto_scroll = true, -- whether auto scroll to the bottom + singleton = true, -- single instance, autocloses the opened one, if present + }, + overseer = { + new_task_opts = { + strategy = { + 'toggleterm', + direction = 'horizontal', + autos_croll = true, + quit_on_exit = 'success', + }, + }, -- options to pass into the `overseer.new_task` command + on_new_task = function(task) end, -- a function that gets overseer.Task when it is created, before calling `task:start` + }, + terminal = { + name = 'Main Terminal', + prefix_name = '[CMakeTools]: ', -- This must be included and must be unique, otherwise the terminals will not work. Do not use a simple spacebar " ", or any generic name + split_direction = 'horizontal', -- "horizontal", "vertical" + split_size = 11, + + -- Window handling + single_terminal_per_instance = true, -- Single viewport, multiple windows + single_terminal_per_tab = true, -- Single viewport per tab + keep_terminal_static_location = true, -- Static location of the viewport if avialable + auto_resize = true, -- Resize the terminal if it already exists + + -- Running Tasks + start_insert = false, -- If you want to enter terminal with :startinsert upon using :CMakeRun + focus = false, -- Focus on terminal when cmake task is launched. + do_not_add_newline = false, -- Do not hit enter on the command inserted when using :CMakeRun, allowing a chance to review or modify the command before hitting enter. + use_shell_alias = false, -- Hide the verbose command wrapper by using a shell alias, showing only the program's output (currently not supported on Windows) + }, + }, + }, + cmake_notifications = { + runner = { enabled = true }, + executor = { enabled = true }, + spinner = { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' }, -- icons used for progress display + refresh_rate_ms = 100, -- how often to iterate icons + }, + cmake_virtual_text_support = true, -- Show the target related to current file using virtual text (at right corner) + cmake_use_scratch_buffer = false, -- A buffer that shows what cmake-tools has done + } +end + +return M diff --git a/lua/plugins/config/completion.lua b/lua/plugins/config/completion.lua deleted file mode 100644 index 7f9b4fa..0000000 --- a/lua/plugins/config/completion.lua +++ /dev/null @@ -1,52 +0,0 @@ -local M = {} - -function M.setup_blink() - local ok, blink = pcall(require, 'blink.cmp') - if not ok then - return - end - - local opts = blink.config or {} - opts.sources = opts.sources or {} - - local default_sources = opts.sources.default or { 'lsp', 'path', 'buffer', 'snippets' } - - if vim.g.use_copilot then - local seen = {} - local new = { 'copilot' } - for _, name in ipairs(default_sources) do - if name ~= 'copilot' and not seen[name] then - table.insert(new, name) - seen[name] = true - end - end - default_sources = new - else - local new = {} - for _, name in ipairs(default_sources) do - if name ~= 'copilot' then - table.insert(new, name) - end - end - default_sources = new - end - - opts.sources.default = default_sources - blink.setup(opts) -end - -function M.setup_copilot() - require('copilot').setup { - suggestion = { enabled = false }, - panel = { enabled = false }, - } -end - -function M.setup_blink_copilot() - local ok, src = pcall(require, 'blink-cmp-copilot') - if ok and src.setup then - src.setup {} - end -end - -return M diff --git a/lua/plugins/config/conan.lua b/lua/plugins/config/conan.lua new file mode 100644 index 0000000..bac25fe --- /dev/null +++ b/lua/plugins/config/conan.lua @@ -0,0 +1,7 @@ +local M = {} + +function M.setup() + require('lua.plugins.spec.nvim-conan').setup() +end + +return M diff --git a/lua/plugins/config/editor.lua b/lua/plugins/config/editor.lua index f905e91..90d6910 100644 --- a/lua/plugins/config/editor.lua +++ b/lua/plugins/config/editor.lua @@ -1,17 +1,77 @@ -- Editor Enhancement Configuration local M = {} +function M.setup_floaterm() + vim.keymap.set('t', '', '') + + local state = { + floating = { + buf = -1, + win = -1, + }, + } + + local function create_floating_window(opts) + opts = opts or {} + local width = opts.width or math.floor(vim.o.columns * 0.8) + local height = opts.height or math.floor(vim.o.lines * 0.8) + + -- Calculate the position to center the window + local col = math.floor((vim.o.columns - width) / 2) + local row = math.floor((vim.o.lines - height) / 2) + + -- Create a buffer + local buf = nil + if vim.api.nvim_buf_is_valid(opts.buf) then + buf = opts.buf + else + buf = vim.api.nvim_create_buf(false, true) -- No file, scratch buffer + end + + -- Define window configuration + local win_config = { + relative = 'editor', + width = width, + height = height, + col = col, + row = row, + style = 'minimal', -- No borders or extra UI elements + border = 'rounded', + } + + -- Create the floating window + local win = vim.api.nvim_open_win(buf, true, win_config) + + return { buf = buf, win = win } + end + + local toggle_terminal = function() + if not vim.api.nvim_win_is_valid(state.floating.win) then + state.floating = create_floating_window { buf = state.floating.buf } + if vim.bo[state.floating.buf].buftype ~= 'terminal' then + vim.cmd.terminal() + end + else + vim.api.nvim_win_hide(state.floating.win) + end + end + + -- Example usage: + -- Create a floating window with default dimensions + vim.api.nvim_create_user_command('Floaterm', toggle_terminal, {}) +end + function M.setup_mini() -- Better Around/Inside textobjects require('mini.ai').setup { n_lines = 500 } - + -- Add/delete/replace surroundings (brackets, quotes, etc.) require('mini.surround').setup() - + -- Simple and easy statusline local statusline = require 'mini.statusline' statusline.setup { use_icons = vim.g.have_nerd_font } - + -- Custom statusline location section ---@diagnostic disable-next-line: duplicate-set-field statusline.section_location = function() @@ -20,7 +80,7 @@ function M.setup_mini() end function M.setup_illuminate() - require('illuminate').configure({ + require('illuminate').configure { delay = 200, large_file_cutoff = 2000, large_file_overrides = { @@ -48,12 +108,13 @@ function M.setup_illuminate() 'TelescopePrompt', }, under_cursor = true, - }) + } end function M.setup() + M.setup_floaterm() M.setup_mini() M.setup_illuminate() end -return M \ No newline at end of file +return M diff --git a/lua/plugins/config/lsp/init.lua b/lua/plugins/config/lsp/init.lua deleted file mode 100644 index fca3571..0000000 --- a/lua/plugins/config/lsp/init.lua +++ /dev/null @@ -1,46 +0,0 @@ --- LSP Configuration Module -local M = {} - -function M.setup() - -- Get capabilities from blink.cmp if available - local capabilities = vim.lsp.protocol.make_client_capabilities() - - local ok, blink_cmp = pcall(require, 'blink.cmp') - if ok then - capabilities = blink_cmp.get_lsp_capabilities(capabilities) - end - - -- Set global position encoding preference - capabilities.general.positionEncodings = { 'utf-16' } - - -- Load server configurations - local servers = require('plugins.config.lsp.servers').get_servers() - - -- Setup each server with capabilities - for name, config in pairs(servers) do - config.capabilities = vim.tbl_deep_extend('force', {}, capabilities, config.capabilities or {}) - vim.lsp.config(name, config) - vim.lsp.enable(name) -- Actually start the server! - end - - -- Setup LSP keymaps - require('plugins.config.lsp.keymaps').setup() - - vim.diagnostic.config { - virtual_text = { - source = true, - prefix = '●', - }, - float = { - source = true, - }, - signs = true, - underline = true, - update_in_insert = false, - severity_sort = true, - } - - vim.api.nvim_set_hl(0, 'DiagnosticUnnecessary', {}) -end - -return M diff --git a/lua/plugins/config/lsp/keymaps.lua b/lua/plugins/config/lsp/keymaps.lua deleted file mode 100644 index df774c2..0000000 --- a/lua/plugins/config/lsp/keymaps.lua +++ /dev/null @@ -1,69 +0,0 @@ --- LSP Keymaps Configuration -local M = {} - -function M.setup() - -- Setup keymaps when LSP attaches to a buffer - vim.api.nvim_create_autocmd('LspAttach', { - group = vim.api.nvim_create_augroup('lsp-attach-keymaps', { clear = true }), - callback = function(event) - -- Helper function to define keymaps - local map = function(keys, func, desc, mode) - mode = mode or 'n' - vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) - end - - -- Navigation keymaps - map('cd', require('telescope.builtin').lsp_definitions, '[C]ode [D]efinition') - map('cr', require('telescope.builtin').lsp_references, '[C]ode [R]eferences') - map('ci', require('telescope.builtin').lsp_implementations, '[C]ode [I]mplementation') - map('ct', require('telescope.builtin').lsp_type_definitions, '[C]ode [T]ype definition') - map('cD', vim.lsp.buf.declaration, '[C]ode [D]eclaration') - - -- Symbol operations - map('cf', vim.lsp.buf.rename, '[C]ode Re[f]actor') - map('ca', vim.lsp.buf.code_action, '[C]ode [A]ction', { 'n', 'x' }) - map('cs', require('telescope.builtin').lsp_document_symbols, '[C]ode [S]ymbols') - map('cS', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[C]ode workspace [S]ymbols') - - -- Documentation - map('K', vim.lsp.buf.hover, 'Hover Documentation') - -- map('', vim.lsp.buf.signature_help, 'Signature help') - map('ch', function() - vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) - end, '[C]ode [H]int toggle') - end, - }) - - -- LSP reload function - local function reload_lsp() - local clients = vim.lsp.get_clients() - if #clients == 0 then - print 'No LSP clients running' - return - end - - for _, client in ipairs(clients) do - vim.lsp.stop_client(client.id) - end - - vim.defer_fn(function() - vim.cmd 'LspStart' - print 'LSP servers reloaded' - end, 500) - end - - -- Reload LSP keybind - vim.keymap.set('n', 'cR', reload_lsp, { desc = 'LSP: [C]ode [R]eload LSP servers' }) - - -- Diagnostic keymaps (available globally, not just when LSP attaches) - vim.keymap.set('n', '[d', function() - vim.diagnostic.goto_prev { float = false } - end, { desc = 'Go to previous [D]iagnostic message' }) - vim.keymap.set('n', ']d', function() - vim.diagnostic.goto_next { float = false } - end, { desc = 'Go to next [D]iagnostic message' }) - vim.keymap.set('n', 'e', vim.diagnostic.open_float, { desc = 'Show diagnostic [E]rror messages' }) - vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' }) -end - -return M diff --git a/lua/plugins/config/lsp/servers.lua b/lua/plugins/config/lsp/servers.lua deleted file mode 100644 index 521f2e9..0000000 --- a/lua/plugins/config/lsp/servers.lua +++ /dev/null @@ -1,156 +0,0 @@ --- LSP Server Configurations -local M = {} - -function M.get_servers() - -- Build clangd command - - return { - -- C/C++ Language Server - clangd = { - cmd = { - 'clangd', - '--background-index', - '--completion-style=detailed', - '--enable-config', - '--fallback-style=llvm', - '--function-arg-placeholders=1', - '--header-insertion-decorators', - '--header-insertion=iwyu', - '--pch-storage=memory', - }, - filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' }, - -- Look for project markers - clangd will find compile_commands.json itself - root_markers = { '.clangd', 'compile_commands.json', 'CMakeLists.txt', '.git' }, - single_file_support = true, - }, - - -- Python Language Server - basedpyright = { - settings = { - basedpyright = { - analysis = { - autoSearchPaths = true, - diagnosticMode = 'openFilesOnly', - typeCheckingMode = 'basic', - useLibraryCodeForTypes = true, - autoImportCompletions = true, - - -- Help with type hints - inlayHints = { - variableTypes = true, - functionReturnTypes = true, - parameterTypes = true, - }, - - diagnosticSeverityOverrides = { - reportOptionalCall = 'none', - reportOptionalSubscript = 'none', - reportOptionalMemberAccess = 'none', - reportOptionalIterable = 'none', - reportAttributeAccessIssue = 'none', - reportUnknownMemberType = 'none', -- Changed to none for less noise - reportUnknownVariableType = 'none', -- Changed to none - reportUnknownArgumentType = 'none', -- Added - reportGeneralTypeIssues = 'none', -- Added - reportUnknownParameterType = 'none', -- Added - reportUnknownAssignmentType = 'none', -- From main - reportMissingTypeStubs = 'none', -- From main - }, - }, - }, - python = { - analysis = { - autoImportCompletions = true, - autoSearchPaths = true, - useLibraryCodeForTypes = true, - }, - }, - }, - }, - - -- Python Linter/Formatter - ruff = {}, - - -- Nix Language Server - nixd = {}, - - -- LaTeX Language Server - texlab = {}, - - -- CMake Language Server - cmake = { - cmd = { 'cmake-language-server' }, - filetypes = { 'cmake' }, - root_markers = { 'compile_commands.json', 'CMakeLists.txt', '.git' }, - }, - - -- Lua Language Server - lua_ls = { - settings = { - Lua = { - runtime = { version = 'LuaJIT' }, - diagnostics = { - globals = { 'vim' }, - unusedLocalExclude = { '_*' }, - }, - workspace = { - library = vim.api.nvim_get_runtime_file('', true), - checkThirdParty = false, - }, - telemetry = { enable = false }, - }, - }, - }, - - -- Bash Language Server - bashls = {}, - - -- YAML Language Server - yamlls = {}, - - -- JSON Language Server - jsonls = {}, - - -- Markdown Language Server (Rust-based, avoids .NET build issues) - markdown_oxide = {}, - - -- TOML Language Server - taplo = {}, - - -- SQL Language Server - sqls = {}, - - -- OCaml Language Server - ocamllsp = { - filetypes = { 'ocaml', 'ocaml.menhir', 'ocaml.interface', 'ocaml.ocamllex', 'reason', 'dune' }, - root_markers = { '*.opam', 'esy.json', 'package.json', '.git', 'dune-project', 'dune-workspace' }, - cmd_env = { - PATH = vim.env.PATH, -- Inherit PATH from Neovim's environment - }, - settings = { - ocaml = { - lens = { - enable = true, - }, - inlayHints = { - enable = true, - }, - }, - }, - }, - - -- Add more servers here as needed - -- Example: - -- rust_analyzer = { - -- settings = { - -- ['rust-analyzer'] = { - -- checkOnSave = { - -- command = 'clippy', - -- }, - -- }, - -- }, - -- }, - } -end - -return M diff --git a/lua/plugins/config/nvim-conan.lua b/lua/plugins/config/nvim-conan.lua new file mode 100644 index 0000000..6c71106 --- /dev/null +++ b/lua/plugins/config/nvim-conan.lua @@ -0,0 +1,7 @@ +local M = {} + +function M.setup() + require('conan').setup() +end + +return M diff --git a/lua/plugins/config/overseer.lua b/lua/plugins/config/overseer.lua new file mode 100644 index 0000000..f658197 --- /dev/null +++ b/lua/plugins/config/overseer.lua @@ -0,0 +1,7 @@ +local M = {} + +function M.setup() + require('overseer').setup() +end + +return M diff --git a/lua/plugins/config/treesitter.lua b/lua/plugins/config/treesitter.lua new file mode 100644 index 0000000..28e8641 --- /dev/null +++ b/lua/plugins/config/treesitter.lua @@ -0,0 +1,45 @@ +local M = {} + +function M.setup() + local treesitter = require 'nvim-treesitter' + treesitter.setup { + ensure_installed = { + 'bash', + 'c', + 'cmake', + 'cpp', + 'diff', + 'html', + 'lua', + 'luadoc', + 'make', + 'markdown', + 'markdown_inline', + 'nix', + 'python', + 'query', + 'vim', + 'vimdoc', + 'yaml', + }, + auto_install = true, + highlight = { + enable = true, + additional_vim_regex_highlighting = false, + }, + indent = { + enable = true, + }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = 'gnn', + node_incremental = 'grn', + scope_incremental = 'grc', + node_decremental = 'grm', + }, + }, + } +end + +return M diff --git a/lua/plugins/spec/autopairs.lua b/lua/plugins/spec/autopairs.lua deleted file mode 100644 index 48f8577..0000000 --- a/lua/plugins/spec/autopairs.lua +++ /dev/null @@ -1,9 +0,0 @@ --- Auto-pairs - Automatically close brackets, quotes, etc. -return { - 'saghen/blink.pairs', - version = '0.4.0', - dependencies = 'saghen/blink.download', - config = function() - require('plugins.config.autopairs').setup() - end, -} diff --git a/lua/plugins/spec/blink-cmp.lua b/lua/plugins/spec/blink-cmp.lua new file mode 100644 index 0000000..b3ed942 --- /dev/null +++ b/lua/plugins/spec/blink-cmp.lua @@ -0,0 +1,28 @@ +return { + { + 'saghen/blink.cmp', + dependencies = { 'rafamadriz/friendly-snippets' }, + + version = '1.*', + + ---@module 'blink.cmp' + ---@type blink.cmp.Config + opts = { + keymap = { preset = 'default' }, + + appearance = { + nerd_font_variant = 'mono', + }, + + completion = { documentation = { auto_show = false } }, + + sources = { + default = { 'lsp', 'path', 'snippets', 'buffer' }, + }, + + fuzzy = { implementation = 'prefer_rust_with_warning' }, + + signature = { enabled = true }, + }, + }, +} diff --git a/lua/plugins/spec/cmake-tools.lua b/lua/plugins/spec/cmake-tools.lua new file mode 100644 index 0000000..122e345 --- /dev/null +++ b/lua/plugins/spec/cmake-tools.lua @@ -0,0 +1,10 @@ +return { + 'Civitasv/cmake-tools.nvim', + dependencies = { + 'nvim-lua/plenary.nvim', + 'stevearc/overseer.nvim', + }, + config = function() + require('plugins.config.cmake-tools').setup() + end, +} diff --git a/lua/plugins/spec/completion.lua b/lua/plugins/spec/completion.lua deleted file mode 100644 index 9c1c979..0000000 --- a/lua/plugins/spec/completion.lua +++ /dev/null @@ -1,26 +0,0 @@ -return { - { - 'saghen/blink.cmp', - version = 'v0.*', -- Use stable releases - event = { 'InsertEnter', 'CmdlineEnter' }, - config = function() - require('plugins.config.completion').setup_blink() - end, - }, - { - 'zbirenbaum/copilot.lua', - enabled = vim.g.copilot_enabled, - event = 'InsertEnter', - config = function() - require('plugins.config.completion').setup_copilot() - end, - }, - { - 'saghen/blink-cmp-copilot', - enabled = vim.g.copilot_enabled, - dependencies = { 'saghen/blink.cmp', 'zbirenbaum/copilot.lua' }, - config = function() - require('plugins.config.completion').setup_blink_copilot() - end, - }, -} diff --git a/lua/plugins/spec/editor.lua b/lua/plugins/spec/editor.lua index 0a3cd5c..c285b49 100644 --- a/lua/plugins/spec/editor.lua +++ b/lua/plugins/spec/editor.lua @@ -33,4 +33,4 @@ return { require('plugins.config.editor').setup_illuminate() end, }, -} \ No newline at end of file +} diff --git a/lua/plugins/spec/lsp.lua b/lua/plugins/spec/lsp.lua deleted file mode 100644 index b83a209..0000000 --- a/lua/plugins/spec/lsp.lua +++ /dev/null @@ -1,26 +0,0 @@ --- LSP Plugin Specification -return { - { - 'neovim/nvim-lspconfig', - event = { 'BufReadPost', 'BufNewFile' }, - dependencies = { - { 'j-hui/fidget.nvim', opts = {} }, - 'folke/lazydev.nvim', - }, - config = function() - require('plugins.config.lsp').setup() - end, - }, - - -- LazyDev for better Neovim Lua development - { - 'folke/lazydev.nvim', - ft = 'lua', - opts = { - library = { - { path = 'luvit-meta/library', words = { 'vim%.uv' } }, - }, - }, - }, -} - diff --git a/lua/plugins/spec/nvim-conan.lua b/lua/plugins/spec/nvim-conan.lua new file mode 100644 index 0000000..4f9eadf --- /dev/null +++ b/lua/plugins/spec/nvim-conan.lua @@ -0,0 +1,9 @@ +return { + 'mm4cN/nvim-conan', + dependencies = { + 'nvim-telescope/telescope.nvim', + }, + config = function() + require('plugins.config.nvim-conan').setup() + end, +} diff --git a/lua/plugins/spec/overseer.lua b/lua/plugins/spec/overseer.lua new file mode 100644 index 0000000..212eeb2 --- /dev/null +++ b/lua/plugins/spec/overseer.lua @@ -0,0 +1,6 @@ +return { + 'stevearc/overseer.nvim', + config = function() + require('plugins.config.overseer').setup() + end, +} diff --git a/lua/plugins/spec/treesitter.lua b/lua/plugins/spec/treesitter.lua index 7e21f6b..b539097 100644 --- a/lua/plugins/spec/treesitter.lua +++ b/lua/plugins/spec/treesitter.lua @@ -1,46 +1,12 @@ -- Treesitter - Syntax highlighting and text objects return { 'nvim-treesitter/nvim-treesitter', - event = { 'BufReadPost', 'BufNewFile' }, + branch = 'main', + lazy = false, build = ':TSUpdate', - main = 'nvim-treesitter.configs', - opts = { - ensure_installed = { - 'bash', - 'c', - 'cmake', - 'cpp', - 'diff', - 'html', - 'lua', - 'luadoc', - 'make', - 'markdown', - 'markdown_inline', - 'nix', - 'python', - 'query', - 'vim', - 'vimdoc', - 'yaml', - }, - auto_install = true, - highlight = { - enable = true, - additional_vim_regex_highlighting = false, - }, - indent = { - enable = true, - }, - incremental_selection = { - enable = true, - keymaps = { - init_selection = 'gnn', - node_incremental = 'grn', - scope_incremental = 'grc', - node_decremental = 'grm', - }, - }, - }, + -- event = { 'BufReadPost', 'BufNewFile' }, + -- main = 'nvim-treesitter.configs', + config = function() + require('plugins.config.treesitter').setup() + end, } -