diff --git a/.github/workflows/nvim.yaml b/.github/workflows/nvim.yaml index d937ba9..7cdb54a 100644 --- a/.github/workflows/nvim.yaml +++ b/.github/workflows/nvim.yaml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - nvim-version: ["v0.11.0"] + nvim-version: ["v0.11.5"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -34,8 +34,9 @@ jobs: # Try to start nvim, source the config, and quit timeout 30s nvim --headless -c 'quit' 2>&1 | tee nvim_startup.log - # Check if there were any errors - if grep -i "error" nvim_startup.log; then + # Check for actual Neovim errors (E123: style or "Error detected" messages) + # Excludes false positives from plugin git output containing "error" in commit messages + if grep -P "^E\d+:|^Error|error:" nvim_startup.log; then echo "Errors found in Neovim startup" exit 1 fi diff --git a/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua b/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua new file mode 100644 index 0000000..a28182f --- /dev/null +++ b/hammerspoon/Spoons/ClaudeRewriter.spoon/init.lua @@ -0,0 +1,120 @@ +local obj = {} +obj.__index = obj + +obj.name = "ClaudeRewriter" +obj.version = "1.0" +obj.author = "Daniel Abeles" +obj.homepage = "https://github.com/Den1al/dotfiles" +obj.license = "MIT - https://opensource.org/licenses/MIT" + +obj.claudePath = os.getenv("HOME") .. "/.local/bin/claude" +obj.model = "sonnet" +obj.systemPrompt = + "Rewrite the following text for clarity and correct grammar. Preserve the original tone, intent, and meaning. Return ONLY the rewritten text with no preamble or explanation. Don't use emdashes." +obj.alertDuration = 1.5 + +local hotkeys = {} +local rewriting = false + +local function getSelectedText() + local systemElement = hs.axuielement.systemWideElement() + local focusedElement = systemElement:attributeValue("AXFocusedUIElement") + if not focusedElement then + return nil + end + return focusedElement:attributeValue("AXSelectedText") +end + +function obj:init() + return self +end + +function obj:bindHotkeys(mapping) + for action, bind in pairs(mapping) do + local mods, key = bind[1], bind[2] + local paste = action == "rewrite" + hotkeys[#hotkeys + 1] = hs.hotkey.new(mods, key, function() + self:rewrite(paste) + end) + end + return self +end + +function obj:start() + for _, hk in ipairs(hotkeys) do + hk:enable() + end + return self +end + +function obj:stop() + for _, hk in ipairs(hotkeys) do + hk:disable() + end + return self +end + +function obj:rewrite(pasteInPlace) + if rewriting then + hs.alert.show("Rewrite in progress", self.alertDuration) + return + end + + local selected = getSelectedText() + if not selected or selected == "" then + hs.alert.show("No text selected", self.alertDuration) + return + end + + if not hs.fs.attributes(self.claudePath) then + hs.alert.show("Claude CLI not found", self.alertDuration) + return + end + + rewriting = true + local savedClipboard = hs.pasteboard.readAllData() + local progressAlert = hs.alert.show("Rewriting...", 30) + + local args = { + "-p", + selected, + "--model", + self.model, + "--output-format", + "text", + "--system-prompt", + self.systemPrompt, + } + + local task = hs.task.new(self.claudePath, function(exitCode, stdout, stderr) + hs.alert.closeSpecific(progressAlert) + rewriting = false + + if exitCode ~= 0 then + hs.alert.show("Rewrite failed", self.alertDuration) + return + end + + local result = stdout and stdout:gsub("^%s+", ""):gsub("%s+$", "") or "" + if result == "" then + hs.alert.show("Empty response", self.alertDuration) + return + end + + hs.pasteboard.setContents(result) + + if pasteInPlace then + hs.eventtap.keyStroke({ "cmd" }, "v") + hs.timer.doAfter(0.2, function() + hs.pasteboard.writeAllData(savedClipboard) + hs.alert.show("Rewritten", self.alertDuration) + end) + else + hs.alert.show("Copied to clipboard", self.alertDuration) + end + end, args) + + task:start() +end + +return obj diff --git a/hammerspoon/init.lua b/hammerspoon/init.lua index 64fe047..30666e6 100644 --- a/hammerspoon/init.lua +++ b/hammerspoon/init.lua @@ -26,4 +26,11 @@ hs.hotkey.bind({ "alt" }, "R", function() hs.reload() end) +hs.loadSpoon("ClaudeRewriter") +spoon.ClaudeRewriter.model = "sonnet" +spoon.ClaudeRewriter:bindHotkeys({ + rewrite = { { "alt" }, "c" }, + clipboard = { { "alt", "shift" }, "c" }, +}):start() + hs.alert.show("🔮 Config loaded") diff --git a/nvim/lua/plugins/lsp/lsp-config.lua b/nvim/lua/plugins/lsp/lsp-config.lua index 98a1c72..59fed5d 100644 --- a/nvim/lua/plugins/lsp/lsp-config.lua +++ b/nvim/lua/plugins/lsp/lsp-config.lua @@ -1,158 +1,162 @@ return { - { - "williamboman/mason.nvim", - config = function() - require("mason").setup() - end, - }, - { - "williamboman/mason-lspconfig.nvim", - config = function() - require("mason-lspconfig").setup({ - ensure_installed = { - "lua_ls", - "ts_ls", - "gopls", - "golangci_lint_ls", - "ocamllsp", - "marksman", - "pylsp", - "bashls", - "java_language_server", - "jinja_lsp", - "dockerls", - }, - }) - end, - }, - { - "neovim/nvim-lspconfig", - config = function() - -- Helper to find venv pylsp - local function find_venv_pylsp() - local root = vim.fn.getcwd() - local venv_paths = { - root .. "/.venv/bin/pylsp", - root .. "/venv/bin/pylsp", - root .. "/.env/bin/pylsp", - } - - for _, path in ipairs(venv_paths) do - if vim.fn.filereadable(path) == 1 then - return path - end - end - return "pylsp" -- Fallback to system pylsp - end - - -- Configure LSP servers using NeoVim 0.11+ vim.lsp.config API - - -- java_language_server configuration - vim.lsp.config.java_language_server = { - cmd = { "java-language-server" }, - } - - -- lua_ls configuration - vim.lsp.config.lua_ls = { - settings = { - Lua = { - diagnostics = { - globals = { "vim" }, - }, - }, - }, - } - - -- pylsp configuration - auto-detects venv pylsp - vim.lsp.config.pylsp = { - cmd = { find_venv_pylsp() }, - settings = { - pylsp = { - plugins = { - jedi_completion = { enabled = true }, - jedi_hover = { enabled = true }, - jedi_references = { enabled = true }, - jedi_signature_help = { enabled = true }, - jedi_symbols = { enabled = true }, - pycodestyle = { enabled = false }, - pyflakes = { enabled = false }, - pylint = { enabled = false }, - rope_autoimport = { enabled = false }, - type_definition = { enabled = false }, -- Disable missing plugin in older pylsp - }, - }, - }, - } - - -- marksman configuration - vim.lsp.config.marksman = {} - - -- ts_ls configuration - vim.lsp.config.ts_ls = {} - - -- bashls configuration - vim.lsp.config.bashls = {} - - -- ocamllsp configuration - vim.lsp.config.ocamllsp = { - cmd = { "ocamllsp" }, - filetypes = { "ocaml", "ocaml.menhir", "ocaml.interface", "ocaml.ocamllex", "reason", "dune" }, - root_markers = { "*.opam", "esy.json", "package.json", ".git", "dune-project", "dune-workspace" }, - } - - -- gopls configuration - vim.lsp.config.gopls = { - cmd = { "gopls" }, - filetypes = { "go", "gomod", "gowork", "gotmpl" }, - root_markers = { "go.work", "go.mod", ".git" }, - settings = { - gopls = { - completeUnimported = true, - usePlaceholders = true, - analyses = { - unusedparams = true, - }, - }, - }, - } - - -- jinja_lsp configuration - vim.lsp.config.jinja_lsp = {} - - -- dockerls configuration - vim.lsp.config.dockerls = {} - - -- golangci_lint_ls configuration - vim.lsp.config.golangci_lint_ls = {} - - -- Enable the LSP servers - vim.lsp.enable("java_language_server") - vim.lsp.enable("lua_ls") - vim.lsp.enable("pylsp") - vim.lsp.enable("marksman") - vim.lsp.enable("ts_ls") - vim.lsp.enable("bashls") - vim.lsp.enable("ocamllsp") - vim.lsp.enable("gopls") - vim.lsp.enable("jinja_lsp") - vim.lsp.enable("dockerls") - vim.lsp.enable("golangci_lint_ls") - - -- Keymaps (using consistent vim.keymap.set) - local nmap = function(keys, func, desc) - vim.keymap.set("n", keys, func, { desc = "LSP: " .. desc }) - end - - nmap("rn", vim.lsp.buf.rename, "[R]e[n]ame") - nmap("ca", vim.lsp.buf.code_action, "[C]ode [A]ction") - nmap("gd", vim.lsp.buf.definition, "[G]oto [D]efinition") - nmap("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") - nmap("gI", vim.lsp.buf.implementation, "[G]oto [I]mplementation") - nmap("D", vim.lsp.buf.type_definition, "Type [D]efinition") - nmap("ds", require("telescope.builtin").lsp_document_symbols, "[D]ocument [S]ymbols") - nmap("ws", require("telescope.builtin").lsp_dynamic_workspace_symbols, "[W]orkspace [S]ymbols") - nmap("K", vim.lsp.buf.hover, "Hover documentation") - nmap("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") - end, - }, + { + "williamboman/mason.nvim", + config = function() + require("mason").setup() + end, + }, + { + "williamboman/mason-lspconfig.nvim", + config = function() + require("mason-lspconfig").setup({ + ensure_installed = { + "lua_ls", + "ts_ls", + "gopls", + "golangci_lint_ls", + "ocamllsp", + "marksman", + "pylsp", + "bashls", + "java_language_server", + "jinja_lsp", + "dockerls", + }, + }) + end, + }, + { + "neovim/nvim-lspconfig", + config = function() + -- Helper to find venv pylsp + local function find_venv_pylsp() + local root = vim.fn.getcwd() + local venv_paths = { + root .. "/.venv/bin/pylsp", + root .. "/venv/bin/pylsp", + root .. "/.env/bin/pylsp", + } + + for _, path in ipairs(venv_paths) do + if vim.fn.filereadable(path) == 1 then + return path + end + end + return "pylsp" -- Fallback to system pylsp + end + + -- Configure LSP servers using NeoVim 0.11+ vim.lsp.config API + + -- java_language_server configuration + vim.lsp.config.java_language_server = { + cmd = { "java-language-server" }, + } + + -- lua_ls configuration + vim.lsp.config.lua_ls = { + settings = { + Lua = { + diagnostics = { + globals = { "vim" }, + }, + }, + }, + } + + -- pylsp configuration - auto-detects venv pylsp + vim.lsp.config.pylsp = { + cmd = { find_venv_pylsp() }, + settings = { + pylsp = { + plugins = { + jedi_completion = { enabled = true }, + jedi_hover = { enabled = true }, + jedi_references = { enabled = true }, + jedi_signature_help = { enabled = true }, + jedi_symbols = { enabled = true }, + pycodestyle = { enabled = false }, + pyflakes = { enabled = false }, + pylint = { enabled = false }, + rope_autoimport = { enabled = false }, + type_definition = { enabled = false }, -- Disable missing plugin in older pylsp + }, + }, + }, + } + + -- marksman configuration + vim.lsp.config.marksman = {} + + -- ts_ls configuration + vim.lsp.config.ts_ls = {} + + -- bashls configuration + vim.lsp.config.bashls = {} + + -- ocamllsp configuration + vim.lsp.config.ocamllsp = { + cmd = { "ocamllsp" }, + filetypes = { "ocaml", "ocaml.menhir", "ocaml.interface", "ocaml.ocamllex", "reason", "dune" }, + root_markers = { "*.opam", "esy.json", "package.json", ".git", "dune-project", "dune-workspace" }, + } + + -- gopls configuration + vim.lsp.config.gopls = { + cmd = { "gopls" }, + filetypes = { "go", "gomod", "gowork", "gotmpl" }, + root_markers = { "go.work", "go.mod", ".git" }, + settings = { + gopls = { + completeUnimported = true, + usePlaceholders = true, + analyses = { + unusedparams = true, + }, + }, + }, + } + + -- jinja_lsp configuration + vim.lsp.config.jinja_lsp = {} + + -- dockerls configuration + vim.lsp.config.dockerls = {} + + -- golangci_lint_ls configuration + vim.lsp.config.golangci_lint_ls = {} + + -- golangci_lint_ls configuration + vim.lsp.config.ruby_lsp = {} + + -- Enable the LSP servers + vim.lsp.enable("java_language_server") + vim.lsp.enable("lua_ls") + vim.lsp.enable("pylsp") + vim.lsp.enable("marksman") + vim.lsp.enable("ts_ls") + vim.lsp.enable("bashls") + vim.lsp.enable("ocamllsp") + vim.lsp.enable("gopls") + vim.lsp.enable("jinja_lsp") + vim.lsp.enable("dockerls") + vim.lsp.enable("golangci_lint_ls") + vim.lsp.enable("ruby_lsp") + + -- Keymaps (using consistent vim.keymap.set) + local nmap = function(keys, func, desc) + vim.keymap.set("n", keys, func, { desc = "LSP: " .. desc }) + end + + nmap("rn", vim.lsp.buf.rename, "[R]e[n]ame") + nmap("ca", vim.lsp.buf.code_action, "[C]ode [A]ction") + nmap("gd", vim.lsp.buf.definition, "[G]oto [D]efinition") + nmap("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") + nmap("gI", vim.lsp.buf.implementation, "[G]oto [I]mplementation") + nmap("D", vim.lsp.buf.type_definition, "Type [D]efinition") + nmap("ds", require("telescope.builtin").lsp_document_symbols, "[D]ocument [S]ymbols") + nmap("ws", require("telescope.builtin").lsp_dynamic_workspace_symbols, "[W]orkspace [S]ymbols") + nmap("K", vim.lsp.buf.hover, "Hover documentation") + nmap("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") + end, + }, } diff --git a/zsh/.zshrc b/zsh/.zshrc index 83568b8..65eaa30 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -53,12 +53,13 @@ alias tm="$HOME/.config/wezterm/start-tmux.sh" # NVIM alias vim=nvim +alias v=nvim # Rust . "$HOME/.cargo/env" -# Eza +# Eza alias ll='eza -l -F=always --color=always --icons=always --all --octal-permissions --git --sort=modified --reverse' alias l='eza -l -F=always --color=always --icons=always --all --octal-permissions --git' @@ -86,7 +87,7 @@ alias oo="cd '$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents/Second alias lg="lazygit" -# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh. +# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh. [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh @@ -99,5 +100,9 @@ eval "$(zoxide init zsh)" # mise (runtime version manager) - replaces asdf/pyenv for some tools eval "$(/opt/homebrew/bin/mise activate zsh)" +# claude +alias claude="~/.claude/local/claude" +alias cc="claude --dangerously-skip-permissions" + # Local bin [[ -f "$HOME/.local/bin/env" ]] && . "$HOME/.local/bin/env"