diff --git a/.letta/settings.local.json b/.letta/settings.local.json new file mode 100644 index 0000000..7656883 --- /dev/null +++ b/.letta/settings.local.json @@ -0,0 +1,17 @@ +{ + "lastAgent": "agent-local-096f2785-09c8-4487-b71b-f8ac2b81aaaf", + "sessionsByServer": { + "api.letta.com": { + "agentId": "agent-21b21fd6-49e4-4d5c-a1b7-1c6dcd8dacc9", + "conversationId": "default" + }, + "local:/Users/daniel/.letta/lc-local-backend": { + "agentId": "agent-local-096f2785-09c8-4487-b71b-f8ac2b81aaaf", + "conversationId": "default" + } + }, + "lastSession": { + "agentId": "agent-local-096f2785-09c8-4487-b71b-f8ac2b81aaaf", + "conversationId": "default" + } +} \ No newline at end of file diff --git a/flake.lock b/flake.lock index 17fe244..195ab40 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1784796856, - "narHash": "sha256-wWFrV5/Qbm+lyt5x20E/bSbfJiGKMo4RCxZV8cl/WZI=", + "lastModified": 1785967620, + "narHash": "sha256-IItrdb7Puk05RqOBWZYFC5X6Wl1sJmCfh5MWVHw5iMM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e2587caef70cea85dd97d7daab492899902dbf5d", + "rev": "b7c2ada94fe99c15b0dbcf4d11fd7850b957a436", "type": "github" }, "original": { @@ -36,6 +36,22 @@ "type": "github" } }, + "plugins-bloocky": { + "flake": false, + "locked": { + "lastModified": 1786042339, + "narHash": "sha256-8QcoC1bS8pRcwBkW3mqD2vgP9Mu0aCdIy6umZO6mUGM=", + "owner": "atiladefreitas", + "repo": "bloocky", + "rev": "a052c3b1a8126e04b194bb3db3c4c6ca641c0e4e", + "type": "github" + }, + "original": { + "owner": "atiladefreitas", + "repo": "bloocky", + "type": "github" + } + }, "plugins-cmp-pandoc-references": { "flake": false, "locked": { @@ -52,6 +68,22 @@ "type": "github" } }, + "plugins-dooing": { + "flake": false, + "locked": { + "lastModified": 1785971574, + "narHash": "sha256-GtEC5kWcH0DmiYXkzxzNjjfYLfyEb7zpTLQWdi7n3zs=", + "owner": "atiladefreitas", + "repo": "dooing", + "rev": "6748316bc6b4601797fb952a83694cc0a5ef6da2", + "type": "github" + }, + "original": { + "owner": "atiladefreitas", + "repo": "dooing", + "type": "github" + } + }, "r-nvim-nix": { "inputs": { "nixpkgs": [ @@ -76,11 +108,11 @@ }, "rixpkgs": { "locked": { - "lastModified": 1782576256, - "narHash": "sha256-KOvpL9DJJmShb64mX9QTjhxHaxE8MizQIqNUAniuJ2E=", + "lastModified": 1785776890, + "narHash": "sha256-CzzgB1teVbroR/QhGAnsQToUYCDXEZZtFTcISAooASM=", "owner": "dwinkler1", "repo": "rixpkgs", - "rev": "815afc01bc0cc9a2eba80906645bd08f976a4401", + "rev": "a54080a58b57d5785dc85901850b817bef2aaf83", "type": "github" }, "original": { @@ -111,7 +143,9 @@ "inputs": { "fran": "fran", "nixpkgs": "nixpkgs", + "plugins-bloocky": "plugins-bloocky", "plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references", + "plugins-dooing": "plugins-dooing", "r-nvim-nix": "r-nvim-nix", "rixpkgs": "rixpkgs", "wrappers": "wrappers" diff --git a/flake.nix b/flake.nix index 2087556..00ad477 100644 --- a/flake.nix +++ b/flake.nix @@ -29,6 +29,16 @@ url = "github:jmbuhr/cmp-pandoc-references"; flake = false; }; + + "plugins-bloocky" = { + url = "github:atiladefreitas/bloocky"; + flake = false; + }; + + "plugins-dooing" = { + url = "github:atiladefreitas/dooing"; + flake = false; + }; }; outputs = { @@ -232,6 +242,12 @@ ''; smoke-test = pkgs.runCommand "smoke-test" {} '' + # The Nix build sandbox has a read-only HOME; point XDG dirs at a + # writable location so vim.lsp/shaDa can write state headlessly. + export XDG_CONFIG_HOME=$TMPDIR/xdg-config + export XDG_STATE_HOME=$TMPDIR/xdg-state + export XDG_CACHE_HOME=$TMPDIR/xdg-cache + export XDG_DATA_HOME=$TMPDIR/xdg-data BINARY_PATH="${defaultNvimPkg}/bin/vv" "$BINARY_PATH" --headless -c "luafile ${./tests/smoke.lua}" -c "qa!" touch $out diff --git a/lua/keymap/leader.lua b/lua/keymap/leader.lua index 795079f..e741c81 100644 --- a/lua/keymap/leader.lua +++ b/lua/keymap/leader.lua @@ -11,28 +11,39 @@ nmap_leader('', 'bnext', 'Next buffer') nmap_leader('', 'bprev', 'Prev buffer') -- a is for 'AI' -nmap_leader("aa", "CodeCompanion /agent", "Agent chat (@{agent} tools)") -nmap_leader("ac", "CodeCompanionChat Toggle", "Chat Toggle") -nmap_leader("aC", function() - local chat = require("codecompanion").last_chat() - if not chat then - return vim.notify("No CodeCompanion chat to compact", vim.log.levels.WARN) - end - require("codecompanion.interactions.chat.context_management.compaction").compact(chat, { min_token_savings = 0 }) -end, "Compact chat") -nmap_leader("ag", "CodeCompanion /commit", "Generate commit message") -nmap_leader("ai", "CodeCompanionActions", "Chat Action") -nmap_leader("al", "CodeCompanion /lsp", "Explain LSP Diagnostics") -nmap_leader("an", "CodeCompanionChat Add", "Chat New") -nmap_leader("as", "CodeCompanion /suggest", "Suggest Improvements") -nmap_leader("aw", "CodeCompanion /tdd", "Workflow: plan, implement, test") -nmap_leader("ax", "CodeCompanion /fixer", "Code Fixer") -xmap_leader("aa", "CodeCompanion /agent", "Agent on selection") -xmap_leader("ae", "CodeCompanion /explain", "Explain Code") -xmap_leader("af", "CodeCompanion /fix", "Fix Code") -xmap_leader("ap", "CodeCompanion /expert", "Code Expert") -xmap_leader("as", "CodeCompanion /suggest", "Suggest Improvements") -nmap_leader("ak", "CodeCompanionChat adapter=codex", "Chat with Codex") +nmap_leader("aa", function() + require("opencode").ask("@this: ") +end, "Ask OpenCode about this") +nmap_leader("ab", function() + require("opencode").prompt("Analyse @buffer") +end, "Analyse buffer") +nmap_leader("aB", function() + require("opencode").prompt("Analyse @buffers") +end, "Analyse open buffers") +nmap_leader("ad", function() + require("opencode").prompt("Explain @diagnostics and fix the underlying issue") +end, "Explain/fix diagnostics") +nmap_leader("an", function() + require("opencode").command("session.new") +end, "New OpenCode session") +nmap_leader("ap", function() + require("opencode").ask("@") +end, "Ask OpenCode with context") +nmap_leader("as", function() + require("opencode").select() +end, "Select OpenCode action") +xmap_leader("aa", function() + require("opencode").ask("@this: ") +end, "Ask OpenCode about selection") +xmap_leader("af", function() + require("opencode").prompt("Fix the selected code and preserve its surrounding API:\n@this") +end, "Fix selection") +xmap_leader("ap", function() + require("opencode").ask("@") +end, "Ask OpenCode with context") +xmap_leader("as", function() + require("opencode").select() +end, "Select OpenCode action") -- b is for 'buffer' nmap_leader('bb', 'b#', 'Alternate') @@ -214,6 +225,24 @@ nmap_leader("wh", "h", "Go to Left Window", { remap = true }) nmap_leader("wj", "j", "Go to Lower Window", { remap = true }) nmap_leader("wk", "k", "Go to Upper Window", { remap = true }) nmap_leader("wl", "l", "Go to Right Window", { remap = true }) +nmap_leader("w>", "vertical resize +5", "Increase Window Width") +nmap_leader("w", "vertical resize -5", "Decrease Window Width") + +local function set_window_width_percent(percent) + return function() + local target_width = math.max(1, math.floor(vim.o.columns * percent / 100 + 0.5)) + vim.api.nvim_win_set_width(0, target_width) + end +end + +for i = 1, 9 do + local percent = i * 10 + nmap_leader( + "w" .. i, + set_window_width_percent(percent), + string.format("Set Window Width to %d%%", percent) + ) +end nmap_leader("_", "s", "Split Window Below", { remap = true }) nmap_leader("|", "v", "Split Window Right", { remap = true }) diff --git a/modules/module/specs/plugins.nix b/modules/module/specs/plugins.nix index 2b92ef4..babb1ba 100644 --- a/modules/module/specs/plugins.nix +++ b/modules/module/specs/plugins.nix @@ -80,6 +80,8 @@ in { plenary-nvim vimtex neogit + config.nvim-lib.neovimPlugins.bloocky + config.nvim-lib.neovimPlugins.dooing { data = mini-nvim; pname = "mini.nvim"; @@ -163,10 +165,8 @@ in { pname = "nvim-treesitter"; } { - data = pkgs.codecompanion-nvim.overrideAttrs (old: { - doCheck = false; - }); - pname = "codecompanion"; + data = pkgs.vimPlugins.opencode-nvim; + pname = "opencode.nvim"; } ] ++ builtins.attrValues pkgs.vimPlugins.nvim-treesitter.queries; }; diff --git a/nvim.log b/nvim.log new file mode 100644 index 0000000..4eb4ddf --- /dev/null +++ b/nvim.log @@ -0,0 +1,13 @@ +WRN 2026-07-31T16:36:01.037 ?.50508 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/TN25Kv/nvim.50508.0 +WRN 2026-07-31T16:36:38.634 ?.50644 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/6jT8As/nvim.50644.0 +WRN 2026-07-31T16:46:12.752 ?.54395 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/zY36Oi/nvim.54395.0 +WRN 2026-07-31T17:01:43.138 ?.58656 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/nDisRA/nvim.58656.0 +WRN 2026-07-31T17:01:50.641 ?.58696 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/okDyqb/nvim.58696.0 +WRN 2026-07-31T17:02:04.773 ?.58741 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/5wxfRu/nvim.58741.0 +WRN 2026-07-31T17:02:29.644 ?.58854 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/OMTfpB/nvim.58854.0 +WRN 2026-07-31T17:02:29.644 ?.58852 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/QZvLy2/nvim.58852.0 +WRN 2026-07-31T17:14:31.289 ?.64329 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/zh9tLm/nvim.64329.0 +WRN 2026-07-31T17:14:40.017 ?.64399 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/pGaDez/nvim.64399.0 +WRN 2026-07-31T17:17:48.228 ?.64921 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/ryMpX0/nvim.64921.0 +WRN 2026-07-31T17:17:52.664 ?.64953 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/X7RmXh/nvim.64953.0 +WRN 2026-07-31T17:18:00.691 ?.64989 server_start:197: Failed to start server: operation not permitted: /tmp/nvim.daniel/C6njjq/nvim.64989.0 diff --git a/overlays/plugins.nix b/overlays/plugins.nix index 91c01aa..17d7c5f 100644 --- a/overlays/plugins.nix +++ b/overlays/plugins.nix @@ -1,22 +1,6 @@ { ... }: final: prev: { - codecompanion-nvim = prev.vimPlugins.codecompanion-nvim.overrideAttrs { - checkInputs = with prev.vimPlugins; [ - blink-cmp - mini-nvim - ]; - dependencies = [ prev.vimPlugins.plenary-nvim ]; - nvimSkipModules = [ - "codecompanion.actions.static" - "codecompanion.actions.init" - "minimal" - "codecompanion.providers.actions.fzf_lua" - "codecompanion.providers.completion.cmp.setup" - "codecompanion.providers.actions.telescope" - "codecompanion.providers.actions.snacks" - ]; - }; zk-nvim = prev.vimPlugins.zk-nvim.overrideAttrs { nvimSkipModules = [ "zk.pickers.fzf_lua" diff --git a/overlays/r.nix b/overlays/r.nix index e736b77..f03d07e 100644 --- a/overlays/r.nix +++ b/overlays/r.nix @@ -5,7 +5,7 @@ }; in { inherit rpkgs; - baseRPackages = [rpkgs.nvimcom]; + baseRPackages = [rpkgs.nvimcom rpkgs.rPackages.btw]; rWrapper = rpkgs.rWrapper.override {packages = [];}; quarto = rpkgs.quarto.override {extraRPackages = [];}; } diff --git a/plugin/03_terminal.lua b/plugin/03_terminal.lua index 95d7a29..43a53a8 100644 --- a/plugin/03_terminal.lua +++ b/plugin/03_terminal.lua @@ -18,7 +18,7 @@ local defaults = { duckdb = "duckdb", julia = "julia", python = "ipython", - shell = "echo 'Hello " .. vim.env.USER .. "!'", + shell = "echo 'Hello " .. (vim.env.USER or "user") .. "!'", } -- Registry of terminal commands diff --git a/plugin/20_startup.lua b/plugin/20_startup.lua index 36bab13..f5cc9e8 100644 --- a/plugin/20_startup.lua +++ b/plugin/20_startup.lua @@ -191,7 +191,7 @@ end) -- Treesitter now_if_args(function() - vim.treesitter.language.register("markdown", { "markdown", "codecompanion", "rmd", "quarto" }) + vim.treesitter.language.register("markdown", { "markdown", "rmd", "quarto" }) require 'treesitter-context'.setup { enable = true, @@ -216,7 +216,7 @@ now_if_args(function() "julia", "rnoweb", "latex", "gitcommit", "gitignore", "git_config", "git_rebase", "diff", "dockerfile", "make", "xml", "zig", "regex", "csv", "bash", - "markdown_inline", "quarto", "rmd", "codecompanion", + "markdown_inline", "quarto", "rmd", } local function start_treesitter(buf, filetype) local lang = vim.treesitter.language.get_lang(filetype) or filetype diff --git a/plugin/22_languages.lua b/plugin/22_languages.lua index 9eac58b..3a6282e 100644 --- a/plugin/22_languages.lua +++ b/plugin/22_languages.lua @@ -102,7 +102,7 @@ now_if_args(function() add("render-markdown.nvim") require('render-markdown').setup({ -- completions = { blink = { enabled = true } }, - file_types = { 'markdown', 'codecompanion', }, + file_types = { 'markdown', }, link = { wiki = { body = function(ctx) diff --git a/plugin/23_editor.lua b/plugin/23_editor.lua index af4c96d..362333d 100644 --- a/plugin/23_editor.lua +++ b/plugin/23_editor.lua @@ -37,7 +37,6 @@ later(function() end) later(function() - -- Keep `ga` free for CodeCompanion's "accept change" mapping. require("mini.align").setup({ mappings = { start = "gA", @@ -219,6 +218,8 @@ later(function() local minikeymap = require("mini.keymap") minikeymap.setup() local map_multistep = minikeymap.map_multistep + -- blink_next/blink_prev/blink_accept are blink.cmp actions. + -- Direct blink keymaps (C-space/C-l) are set in 24_completion.lua. local tab_steps = { "blink_next", "pmenu_next", diff --git a/plugin/24_completion.lua b/plugin/24_completion.lua index c2291c7..9e70b27 100644 --- a/plugin/24_completion.lua +++ b/plugin/24_completion.lua @@ -4,9 +4,6 @@ local later = MiniDeps.later local now = MiniDeps.now local now_if_args = Config.now_if_args --- Constants -local BLINK_VERSION = "v1.10.2" - -- Plugin sources configuration local PLUGIN_SOURCES = { "hrsh7th/cmp-cmdline", @@ -14,7 +11,7 @@ local PLUGIN_SOURCES = { "zbirenbaum/copilot.lua", "jmbuhr/cmp-pandoc-references", "fang2hou/blink-copilot", - "olimorris/codecompanion.nvim" + "nickjvandyke/opencode.nvim", } local PLUGIN_ADDS = { @@ -24,34 +21,16 @@ local PLUGIN_ADDS = { "cmp-pandoc-references", } --- Helper functions -local function create_system_prompt(role_description) - return function(context) - local lang = context.filetype or "programmer" - return "I want you to act as a senior " .. lang .. " developer. " .. role_description - end -end - -local function get_code_block(context) - local text = require("codecompanion.helpers.code").get_code(context.start_line, context.end_line) - return "```" .. context.filetype .. "\n" .. text .. "\n```" -end - local function get_mini_icons_highlight(ctx) local _, hl, _ = require("mini.icons").get("lsp", ctx.kind) return hl end local function get_blink_fuzzy_setting() - local setting = { - sorts = { "exact", "score", "sort_text" } + return { + sorts = { "exact", "score", "sort_text" }, + use_proximity = true, } - - if not Config.isNixCats then - setting.prebuilt_binaries = { force_version = BLINK_VERSION } - end - - return setting end -- Plugin loading @@ -62,7 +41,6 @@ if not Config.isNixCats then add({ source = "saghen/blink.cmp", depends = { "rafamadriz/friendly-snippets" }, - checkout = BLINK_VERSION, }) end) @@ -73,241 +51,6 @@ if not Config.isNixCats then end) end -local function get_codecompanion_config() - return { - adapters = { - acp = { - -- Codex = heavy agent lane (ChatGPT Edu login via `codex login`; ~/.codex/auth.json). - -- Requires `codex-acp` on PATH (~/.nix-profile/bin). ACP-only slash commands in the - -- chat buffer: /resume (restore a past session, fresh chat only), /mode (switch agent - -- mode), /command, /acp_session_options (e.g. model per session); `\` triggers ACP - -- command completion (1-5s delay after chat open). - codex = function() - return require("codecompanion.adapters").extend("codex", { - defaults = { - auth_method = "chatgpt", - }, - }) - end, - }, - }, - interactions = { - chat = { - adapter = { - name = "copilot", - model = "claude-sonnet-5", - }, - slash_commands = { - ["share"] = { - opts = { - token = os.getenv("GITHUB_GIST_TOKEN"), - }, - }, - }, - opts = { - completion_provider = "blink", - context_management = { - editing = { - trigger = 0.65, - keep_cycles = 3, - exclude_tools = { "memory" }, - }, - compaction = { - trigger = 0.85, - min_token_savings = 10000, - }, - }, - }, - }, - inline = { - adapter = { - name = "copilot", - model = "gpt-5-mini", - }, - }, - shared = { - keymaps = { - accept_change = { - modes = { n = "ga" }, - description = "Accept the suggested change", - }, - reject_change = { - modes = { n = "gr" }, - opts = { nowait = true }, - description = "Reject the suggested change", - }, - }, - }, - background = { - adapter = { - name = "copilot", - model = "gpt-5-mini", - }, - chat = { - callbacks = { - ["on_ready"] = { - actions = { "interactions.background.builtin.chat_make_title" }, - enabled = true, - }, - }, - opts = { - enabled = true, - }, - }, - }, - }, - display = { - chat = { - show_settings = false, - window = { - layout = "horizontal", - position = "bottom", - height = 0.33, - }, - }, - diff = { - enabled = true, - threshold_for_chat = 6, - }, - }, - rules = { - default = { - description = "Collection of common files for all projects", - files = { - ".clinerules", - ".cursorrules", - ".rules", - ".github/copilot-instructions.md", - "AGENT.md", - "AGENTS.md", - { path = "CLAUDE.md", parser = "claude" }, - { path = "CLAUDE.local.md", parser = "claude" }, - { path = "~/.claude/CLAUDE.md", parser = "claude" }, - }, - }, - opts = { - chat = { - autoload = "default", - enabled = true, - }, - }, - }, - prompt_library = { - ["expert"] = { - interaction = "chat", - description = "Get expert advice from an LLM", - opts = { alias = "expert" }, - prompts = { - { - role = "system", - content = create_system_prompt( - "I will ask you specific questions and I want you to return concise explanations and codeblock examples." - ), - }, - { - role = "user", - content = function(context) - return "I have the following code:\n\n" .. get_code_block(context) .. "\n\n" - end, - opts = { contains_code = true }, - }, - }, - }, - ["fixer"] = { - interaction = "chat", - description = "Fix code errors with expert guidance", - opts = { alias = "fixer" }, - prompts = { - { - role = "system", - content = create_system_prompt( - "I have a block of code that is not working and will give you a hint about the error. I want you to return the corrected code and a concise explanation of the corrections." - ), - }, - { - role = "user", - content = function(context) - return "The following code has an error:\n\n" .. get_code_block(context) .. "\n\nThe error is:" - end, - opts = { contains_code = true }, - }, - }, - }, - ["suggest"] = { - interaction = "chat", - description = "Suggest improvements to the buffer", - opts = { alias = "suggest" }, - prompts = { - { - role = "system", - content = create_system_prompt( - "When asked to improve code, follow these steps:\n" .. - "1. Identify the programming language.\n" .. - "2. Think separately for each function or significant block of code and think about possible improvements (e.g., for better readability or speed) in the context of the language.\n" .. - "3. Think about the whole document and think about possible improvements.\n" .. - "4. Provide the improved code.\n" .. - "5. Provide a concise explanation of the improvements." - ), - }, - { - role = "user", - content = function(context) - return "Please improve the following code:\n\n" .. get_code_block(context) - end, - opts = { contains_code = true }, - }, - }, - }, - ["agent"] = { - interaction = "chat", - description = "Agentic coding with the @{agent} tool group (read/edit/grep/run)", - opts = { alias = "agent" }, - prompts = { - { - role = "user", - content = function(context) - return "@{agent} Work on the following code:\n\n" .. get_code_block(context) .. "\n\n" - end, - opts = { contains_code = true }, - }, - }, - }, - ["tdd"] = { - interaction = "chat", - description = "Workflow: plan the buffer change, implement it, run the tests", - opts = { alias = "tdd", is_workflow = true }, - prompts = { - { - { - role = "user", - content = function(context) - return "Let's work test-driven. First, study #buffer and the relevant parts of the codebase, then propose a concise implementation plan (no code yet).\n\nThe code under discussion:\n\n" - .. get_code_block(context) - .. "\n\nThe task: " - end, - opts = { contains_code = true }, - }, - }, - { - { - role = "user", - content = "Implement the plan now, writing or updating tests alongside the code. @{agent}", - opts = { auto_submit = true }, - }, - }, - { - { - role = "user", - content = "Run the project's test suite with @{run_command} and fix any failures until it passes.", - opts = { auto_submit = true }, - }, - }, - }, - }, - }, - } -end - -- Batch add simple plugins later(function() for _, plugin in ipairs(PLUGIN_ADDS) do @@ -359,26 +102,33 @@ later(function() }) end) - --- CodeCompanion habit notes (chat buffer unless stated): --- /compact compact history, keep summary /fork fork the conversation --- /symbols insert symbols for a file /share export chat to a GitHub gist --- gm toggle "btw" ephemeral message gty YOLO: approve all tool calls --- gba/gbd buffer sync add/drop gd debug window (adapter/tools info) --- Codex (ACP) lane: /resume (fresh chat only), /mode, /command, /acp_session_options, --- `\` ACP command completion. Prompt library: /expert /fixer /suggest /agent /tdd (workflow). later(function() - add("codecompanion.nvim") - - -- now use function - require("codecompanion").setup(get_codecompanion_config()) - vim.cmd([[cab cc CodeCompanion]]) + vim.g.opencode_opts = { + events = { + reload = true, + permissions = { + enabled = true, + edits = { enabled = true }, + }, + }, + server = { + start = function() + vim.cmd("vsplit term://opencode --port") + vim.cmd("vertical resize " .. math.floor(vim.o.columns * 0.4)) + vim.cmd("wincmd p") + end + }, + } + add("opencode.nvim") end) now_if_args(function() add("blink.cmp") require("blink.cmp").setup({ + -- Direct blink keymaps (C-space/C-l). + -- Tab/Enter/Up/Down are handled via multistep chains in 23_editor.lua, + -- which chain blink_next/blink_prev/blink_accept with other editor actions. keymap = { preset = "default", [""] = { "show", "select_next" }, @@ -415,6 +165,7 @@ now_if_args(function() }, completion = { menu = { + border = "rounded", draw = { treesitter = { "lsp" }, components = { @@ -434,14 +185,12 @@ now_if_args(function() list = { selection = { preselect = false, auto_insert = true } }, - documentation = { auto_show = true }, + ghost_text = { enabled = true, show_with_menu = true }, + documentation = { auto_show = true, window = { border = "rounded" } }, trigger = { show_in_snippet = false }, }, snippets = { preset = "mini_snippets" }, sources = { - per_filetype = { - codecompanion = { "codecompanion" }, - }, default = { "references", "lsp", "path", "snippets", "buffer", "omni", "copilot" }, providers = { path = { @@ -467,12 +216,6 @@ now_if_args(function() score_offset = 45, async = true, }, - codecompanion = { - name = "CodeCompanion", - module = "codecompanion.providers.completion.blink", - score_offset = 45, - async = true, - }, references = { name = "pandoc_references", module = "cmp-pandoc-references.blink", diff --git a/plugin/25_lsp.lua b/plugin/25_lsp.lua index 5250cdd..6a719ca 100644 --- a/plugin/25_lsp.lua +++ b/plugin/25_lsp.lua @@ -15,7 +15,7 @@ now_if_args(function() basedpyright = {}, ruff = {}, marksman = { - filetypes = { "markdown", "markdown_inline", "codecompanion" }, + filetypes = { "markdown", "markdown_inline" }, }, harper_ls = { cmd = { "harper-ls", "--stdio" }, diff --git a/plugin/29_bloocky.lua b/plugin/29_bloocky.lua new file mode 100644 index 0000000..5e6a3ea --- /dev/null +++ b/plugin/29_bloocky.lua @@ -0,0 +1,43 @@ +-- Bloocky: timeblocking calendar (day/week/month views), persisted to JSON. +-- Loaded via the `general` cat spec (nix mode) or MiniDeps (non-nix). +-- Default global toggle is tb, which collides with the terminal map +-- (toggle bracketed paste), so it is moved to the calendar/tasks group c. +local Config = require('config') + +if not Config.isNixCats then + local later = MiniDeps.later + later(function() + MiniDeps.add({ source = 'atiladefreitas/bloocky' }) + end) +end + +local nix = require('config.nix') +local later = MiniDeps.later + +later(function() + if not nix.get_cat('general', false) then + return + end + require('bloocky').setup({ + week_start = "monday", + window = { + -- Width per view: fraction of the editor width (or absolute columns if > 1). + -- A single number applies to every view. + width = { + month = 0.99, + week = 0.99, + day = 0.8, + }, + border = "rounded", + }, + integrations = { + dooing = { + enabled = true, -- show Dooing todos on their due date + show_done = false, -- also show completed todos + }, + }, + keymaps = { + toggle = 'cb', + }, + }) +end) diff --git a/plugin/30_dooing.lua b/plugin/30_dooing.lua new file mode 100644 index 0000000..0ec1a09 --- /dev/null +++ b/plugin/30_dooing.lua @@ -0,0 +1,28 @@ +-- Dooing: minimalist todo list manager with a floating window, persisted to JSON. +-- Loaded via the `general` cat spec (nix mode) or MiniDeps (non-nix). +-- Default globals td / tN occupy the terminal group, so the +-- todo toggles are moved to the calendar/tasks group c. +local Config = require('config') + +if not Config.isNixCats then + local later = MiniDeps.later + later(function() + MiniDeps.add({ source = 'atiladefreitas/dooing' }) + end) +end + +local nix = require('config.nix') +local later = MiniDeps.later + +later(function() + if not nix.get_cat('general', false) then + return + end + require('dooing').setup({ + keymaps = { + toggle_window = 'cd', + open_project_todo = 'cD', + show_due_notification = 'cN', + }, + }) +end) \ No newline at end of file diff --git a/tests/smoke.lua b/tests/smoke.lua index e4f0aaf..2e4112e 100644 --- a/tests/smoke.lua +++ b/tests/smoke.lua @@ -55,6 +55,10 @@ local function wait_for_deferred(timeout_ms) -- Fire VimEnter so startup autocmds run, then drain the event loop so -- mini.deps' deferred setup closures have a chance to execute before we -- assert anything. + -- The headless smoke run has no start screen to display. Disabling + -- mini.starter also prevents it from replacing the current buffer and + -- trying to create a swap file in the read-only Nix sandbox. + vim.g.ministarter_disable = true vim.cmd('doautocmd VimEnter') vim.wait(timeout_ms, function() return false end, 50) end @@ -91,8 +95,12 @@ end -- --------------------------------------------------------------------------- local function has_lsp_config(name) if vim.lsp and vim.lsp.config then - -- vim.lsp.config(name) returns the merged config or {} if none registered. - local ok, cfg = pcall(vim.lsp.config, name) + -- Neovim 0.12 exposes configs through the callable `vim.lsp.config` + -- table; older versions expose a function-like API. + local ok, cfg = pcall(function() return vim.lsp.config[name] end) + if not ok or type(cfg) ~= 'table' or next(cfg) == nil then + ok, cfg = pcall(vim.lsp.config, name) + end if ok and cfg and next(cfg) ~= nil then return true end