浏览代码

dev: automated commit - 2025-06-30 13:03:02

Mariano Z. 7 月之前
父节点
当前提交
979a043670
共有 8 个文件被更改,包括 411 次插入165 次删除
  1. 22 20
      lazy-lock.json
  2. 16 0
      lsp/tsgo.lua
  3. 1 0
      lua/plugins/format.lua
  4. 0 1
      lua/plugins/fzf.lua
  5. 143 0
      lua/plugins/git.lua
  6. 191 140
      lua/plugins/lsp/init.lua
  7. 32 4
      lua/plugins/mini.lua
  8. 6 0
      lua/plugins/typ.lua

+ 22 - 20
lazy-lock.json

@@ -1,51 +1,53 @@
 {
   "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" },
   "LuaSnip": { "branch": "master", "commit": "458560534a73f7f8d7a11a146c801db00b081df0" },
-  "blink.cmp": { "branch": "main", "commit": "022521a8910a5543b0251b21c9e1a1e989745796" },
+  "blink.cmp": { "branch": "main", "commit": "9bcb14b43852a6f2bfd5ac9ef29cb5cf09b1b39b" },
   "cloak.nvim": { "branch": "main", "commit": "648aca6d33ec011dc3166e7af3b38820d01a71e4" },
-  "conform.nvim": { "branch": "master", "commit": "6feb2f28f9a9385e401857b21eeac3c1b66dd628" },
+  "conform.nvim": { "branch": "master", "commit": "00d7e92d170139569b1887ff2be298a0cdd7d9ae" },
   "fidget.nvim": { "branch": "main", "commit": "d9ba6b7bfe29b3119a610892af67602641da778e" },
   "flash.nvim": { "branch": "main", "commit": "3c942666f115e2811e959eabbdd361a025db8b63" },
   "friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" },
-  "fzf-lua": { "branch": "main", "commit": "29e982dfc96a134fecc80853c8cb8324e43e574b" },
+  "fzf-lua": { "branch": "main", "commit": "a4404dee0a65d3c2e2b292206d10b16567d088c9" },
+  "git-worktree.nvim": { "branch": "main", "commit": "3ad8c17a3d178ac19be925284389c14114638ebb" },
   "gitlinker.nvim": { "branch": "master", "commit": "cc59f732f3d043b626c8702cb725c82e54d35c25" },
-  "gitsigns.nvim": { "branch": "main", "commit": "8b729e489f1475615dc6c9737da917b3bc163605" },
-  "go.nvim": { "branch": "master", "commit": "e1b763cab2cfd3c60207873dbc925c9be49913c0" },
+  "gitsigns.nvim": { "branch": "main", "commit": "1b0350ab707713b2bc6c236151f1a324175347b1" },
+  "go.nvim": { "branch": "master", "commit": "a3455f48cff718a86275115523dcc735535a13aa" },
   "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" },
   "lazydev.nvim": { "branch": "main", "commit": "2367a6c0a01eb9edb0464731cc0fb61ed9ab9d2c" },
   "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" },
-  "mason-lspconfig.nvim": { "branch": "main", "commit": "67da97f8c2fd12d05427bb485ce07ee6418e0a51" },
-  "mason-tool-installer.nvim": { "branch": "main", "commit": "75d60a8f928decd8b38897f80849768b7c540a5b" },
+  "mason-lspconfig.nvim": { "branch": "main", "commit": "c4c84f4521d62de595c0d0f718a9a40c1890c8ce" },
+  "mason-tool-installer.nvim": { "branch": "main", "commit": "517ef5994ef9d6b738322664d5fdd948f0fdeb46" },
   "mason.nvim": { "branch": "main", "commit": "8024d64e1330b86044fed4c8494ef3dcd483a67c" },
-  "mini.ai": { "branch": "main", "commit": "4b5348fac5912f1957f4c012c2e0ab0c4b865386" },
-  "mini.icons": { "branch": "main", "commit": "397ed3807e96b59709ef3292f0a3e253d5c1dc0a" },
-  "mini.statusline": { "branch": "main", "commit": "e331175f10d9f400b42523b3890841aba202ce16" },
-  "mini.surround": { "branch": "main", "commit": "f4307f935ad87cfe3e570dbaae485b35cce4e5ec" },
+  "mini.ai": { "branch": "main", "commit": "d172ada7b0281044a06cb9a625a862553c457b6f" },
+  "mini.icons": { "branch": "main", "commit": "94848dad1589a199f876539bd79befb0c5e3abf0" },
+  "mini.statusline": { "branch": "main", "commit": "452d27d764720cddcb9909b786598bb9e80c1ce8" },
+  "mini.surround": { "branch": "main", "commit": "1a2b59c77a0c4713a5bd8972da322f842f4821b1" },
   "nightfox.nvim": { "branch": "main", "commit": "ba47d4b4c5ec308718641ba7402c143836f35aa9" },
   "nvim-colorizer.lua": { "branch": "master", "commit": "a065833f35a3a7cc3ef137ac88b5381da2ba302e" },
   "nvim-lastplace": { "branch": "main", "commit": "0bb6103c506315044872e0f84b1f736c4172bb20" },
-  "nvim-lint": { "branch": "master", "commit": "b47cbb249351873e3a571751c3fb66ed6369852f" },
-  "nvim-lspconfig": { "branch": "master", "commit": "b8e7957bde4cbb3cb25a13a62548f7c273b026e9" },
+  "nvim-lint": { "branch": "master", "commit": "2b0039b8be9583704591a13129c600891ac2c596" },
+  "nvim-lspconfig": { "branch": "master", "commit": "1cb30b1bafe5a63a5c6ac20dc39f83487df38855" },
   "nvim-spectre": { "branch": "master", "commit": "72f56f7585903cd7bf92c665351aa585e150af0f" },
   "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
   "nvim-ts-context-commentstring": { "branch": "main", "commit": "1b212c2eee76d787bbea6aa5e92a2b534e7b4f8f" },
-  "nvim-ufo": { "branch": "main", "commit": "3c7a3570e9c9dc198a2ad4491b0b0e51c4d4ba08" },
+  "nvim-ufo": { "branch": "main", "commit": "80fe8215ba566df2fbf3bf4d25f59ff8f41bc0e1" },
   "obsidian.nvim": { "branch": "main", "commit": "ae1f76a75c7ce36866e1d9342a8f6f5b9c2caf9b" },
-  "oil.nvim": { "branch": "master", "commit": "685cdb4ffa74473d75a1b97451f8654ceeab0f4a" },
+  "oil.nvim": { "branch": "master", "commit": "08c2bce8b00fd780fb7999dbffdf7cd174e896fb" },
   "plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" },
   "presenterm.nvim": { "branch": "main", "commit": "2db942337aeeca99e33f627459df2264b3987634" },
   "promise-async": { "branch": "main", "commit": "119e8961014c9bfaf1487bf3c2a393d254f337e2" },
   "quicker.nvim": { "branch": "master", "commit": "51d3926f183c2d98fbc237cc237ae0926839af3a" },
-  "render-markdown.nvim": { "branch": "main", "commit": "0b0bec653f47d9d56cb80f426479ef0527814119" },
-  "schemastore.nvim": { "branch": "main", "commit": "a9ba109549de51e3b4594d39a1c07f14b9d0cfa5" },
+  "render-markdown.nvim": { "branch": "main", "commit": "3115ff748d6885fe1af349feb6b73de03eda8e12" },
+  "schemastore.nvim": { "branch": "main", "commit": "e4f80f37cd11ed58a6e914cc30850749f021b6a7" },
   "snacks.nvim": { "branch": "main", "commit": "bc0630e43be5699bb94dadc302c0d21615421d93" },
   "suda.vim": { "branch": "master", "commit": "9adda7d195222d4e2854efb2a88005a120296c47" },
   "todo-comments.nvim": { "branch": "main", "commit": "304a8d204ee787d2544d8bc23cd38d2f929e7cc5" },
-  "undotree": { "branch": "master", "commit": "b951b87b46c34356d44aa71886aecf9dd7f5788a" },
+  "typst-preview.nvim": { "branch": "master", "commit": "dea4525d5420b7c32eebda7de15a6beb9d6574fa" },
+  "undotree": { "branch": "master", "commit": "7a8b831e9bfb9f6fe05cc33294882648dd6801fb" },
   "vim-dadbod": { "branch": "master", "commit": "e95afed23712f969f83b4857a24cf9d59114c2e6" },
   "vim-dadbod-completion": { "branch": "master", "commit": "a8dac0b3cf6132c80dc9b18bef36d4cf7a9e1fe6" },
-  "vim-dadbod-ui": { "branch": "master", "commit": "460432301a5cb280ea265ddfa15c9f3dcd1d26b7" },
-  "vim-fugitive": { "branch": "master", "commit": "4a745ea72fa93bb15dd077109afbb3d1809383f2" },
+  "vim-dadbod-ui": { "branch": "master", "commit": "2900a1617b3df1a48683d872eadbe1101146a49a" },
+  "vim-fugitive": { "branch": "master", "commit": "593f831d6f6d779cbabb70a4d1e6b1b1936a88af" },
   "vim-hugo": { "branch": "master", "commit": "324fb8c7371d31701349c1192e25a0bdcf9898f8" },
   "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" },
   "which-key.nvim": { "branch": "main", "commit": "370ec46f710e058c9c1646273e6b225acf47cbed" },

+ 16 - 0
lsp/tsgo.lua

@@ -0,0 +1,16 @@
+return {
+  settings = {},
+  flags = {},
+  filetypes = { "typescript" },
+  cmd = {
+    "/home/forbi/local/local/tsgo",
+    "--lsp",
+    "-stdio",
+  },
+  root_markers = {
+    "tsconfig.json",
+    "package.json",
+    "jsconfig.json",
+    ".git",
+  },
+}

+ 1 - 0
lua/plugins/format.lua

@@ -28,6 +28,7 @@ return {
         cpp = { "clang-format" },
         hcl = { "hcl" },
         toml = { "taplo" },
+        typst = { "prettypst" },
       },
       formatters = {
         csharpier = {

+ 0 - 1
lua/plugins/fzf.lua

@@ -32,7 +32,6 @@ M.config = function()
   nmap("<leader>D", fzf_lua.lsp_typedefs, { desc = "Type Definition" })
   nmap("<leader>ca", fzf_lua.lsp_code_actions, { desc = "Code Action" })
   nmap("<leader>ds", fzf_lua.lsp_document_symbols, { desc = "Document Symbols" })
-  nmap("<leader>ws", fzf_lua.lsp_workspace_symbols, { desc = "Workspace Symbols" })
   nmap("<leader>ic", fzf_lua.lsp_incoming_calls, { desc = "Incoming Calls" })
   nmap("<leader>oc", fzf_lua.lsp_outgoing_calls, { desc = "Outgoing Calls" })
   nmap("<leader>gf", fzf_lua.live_grep, { desc = "Find Live Grep" })

+ 143 - 0
lua/plugins/git.lua

@@ -88,6 +88,149 @@ local M = {
       nmap("<leader>gy", "<cmd>lua require('gitlinker').get_buf_range_url('n')<cr>")
     end,
   },
+  {
+    "polarmutex/git-worktree.nvim",
+    version = "^2",
+    dependencies = { "nvim-lua/plenary.nvim", "ibhagwan/fzf-lua", "folke/snacks.nvim" },
+    config = function()
+      local fzf_lua = require("fzf-lua")
+      local git_worktree = require("git-worktree")
+
+      -- Basic hooks
+      local Hooks = require("git-worktree.hooks")
+      Hooks.register(Hooks.type.SWITCH, Hooks.builtins.update_current_buffer_on_switch)
+
+      -- Switch worktrees
+      local function switch_worktree()
+        vim.system({ "git", "worktree", "list" }, {}, function(result)
+          if result.code ~= 0 then
+            return
+          end
+
+          local items = {}
+          for line in result.stdout:gmatch("[^\n]+") do
+            local path, branch = line:match("^([^%s]+)%s+%[?([^%]]*)")
+            if path and branch then
+              table.insert(items, path .. " (" .. (branch ~= "" and branch or "detached") .. ")")
+            end
+          end
+
+          vim.schedule(function()
+            fzf_lua.fzf_exec(items, {
+              prompt = "Worktrees> ",
+              actions = {
+                default = function(selected)
+                  local path = selected[1]:match("^([^%(]+)")
+                  git_worktree.switch_worktree(path:gsub("%s+$", ""))
+                end,
+              },
+            })
+          end)
+        end)
+      end
+
+      -- Create worktree
+      local function create_worktree()
+        -- Get the git directory (works for both regular and bare repos)
+        vim.system({ "git", "rev-parse", "--git-dir" }, {}, function(result)
+          if result.code ~= 0 then
+            vim.schedule(function()
+              vim.notify("Not in a git repository", vim.log.levels.ERROR)
+            end)
+            return
+          end
+
+          local git_dir = result.stdout:gsub("\n", "")
+          -- For bare repos, git-dir is the repo itself; for regular repos, get parent
+          local repo_root = git_dir:match("%.git$") and git_dir:gsub("/%.git$", "") or git_dir
+
+          vim.system({ "git", "branch", "-a" }, { cwd = repo_root }, function(branch_result)
+            if branch_result.code ~= 0 then
+              return
+            end
+
+            local branches = {}
+            for line in branch_result.stdout:gmatch("[^\n]+") do
+              local branch = line:gsub("^%s*%*?%s*", ""):gsub("^remotes/", "")
+              if branch ~= "" and not branch:match("HEAD") then
+                table.insert(branches, branch)
+              end
+            end
+
+            vim.schedule(function()
+              fzf_lua.fzf_exec(branches, {
+                prompt = "Base Branch> ",
+                actions = {
+                  default = function(selected)
+                    if not selected or #selected == 0 then
+                      return
+                    end
+                    local base_branch = selected[1]
+                    local default_name = base_branch:gsub(".*/", "")
+
+                    require("snacks").input({
+                      prompt = "Worktree name",
+                      default = default_name,
+                      icon = "🌿",
+                    }, function(name)
+                      if name then
+                        git_worktree.create_worktree(name, base_branch, "origin")
+                      end
+                    end)
+                  end,
+                },
+              })
+            end)
+          end)
+        end)
+      end
+
+      -- Delete worktree
+      local function delete_worktree()
+        local cwd = vim.fn.getcwd() -- Get this before async call
+
+        vim.system({ "git", "worktree", "list" }, {}, function(result)
+          if result.code ~= 0 then
+            return
+          end
+
+          local items = {}
+
+          for line in result.stdout:gmatch("[^\n]+") do
+            local path, branch = line:match("^([^%s]+)%s+%[?([^%]]*)")
+            if path and path ~= cwd then
+              table.insert(items, path .. " (" .. (branch ~= "" and branch or "detached") .. ")")
+            end
+          end
+
+          vim.schedule(function()
+            fzf_lua.fzf_exec(items, {
+              prompt = "Delete> ",
+              actions = {
+                default = function(selected)
+                  local path = selected[1]:match("^([^%(]+)"):gsub("%s+$", "")
+
+                  -- Simple vim.ui.select for yes/no
+                  vim.ui.select({ "Yes", "No" }, {
+                    prompt = "Delete worktree '" .. path .. "'?",
+                  }, function(choice)
+                    if choice == "Yes" then
+                      git_worktree.delete_worktree(path, true)
+                    end
+                  end)
+                end,
+              },
+            })
+          end)
+        end)
+      end
+
+      -- Keymaps
+      vim.keymap.set("n", "<leader>ws", switch_worktree, { desc = "Switch Worktree" })
+      vim.keymap.set("n", "<leader>wc", create_worktree, { desc = "Create Worktree" })
+      vim.keymap.set("n", "<leader>wd", delete_worktree, { desc = "Delete Worktree" })
+    end,
+  },
 }
 
 return M

+ 191 - 140
lua/plugins/lsp/init.lua

@@ -1,155 +1,206 @@
-local M = {
-  "WhoIsSethDaniel/mason-tool-installer.nvim",
+return {
+  "neovim/nvim-lspconfig",
   dependencies = {
+    require("plugins.lsp.extras.lazydev"),
+    require("plugins.lsp.extras.gopher"),
     "mason-org/mason-lspconfig.nvim",
     "mason-org/mason.nvim",
     "j-hui/fidget.nvim",
     "ibhagwan/fzf-lua",
-    require("plugins.lsp.extras.lazydev"),
-    require("plugins.lsp.extras.gopher"),
+    "WhoIsSethDaniel/mason-tool-installer.nvim",
   },
-}
 
-local function setup_keymaps(bufnr)
-  local fzf = require("fzf-lua")
-  local opts = { buffer = bufnr }
-
-  -- Basic LSP
-  nmap("K", vim.lsp.buf.hover, vim.tbl_extend("force", opts, { desc = "Hover Doc" }))
-  nmap("<C-h>", vim.lsp.buf.signature_help, vim.tbl_extend("force", opts, { desc = "Signature Help" }))
-  nmap("<leader>r", vim.lsp.buf.rename, vim.tbl_extend("force", opts, { desc = "Rename" }))
-  nmap("<leader>ca", vim.lsp.buf.code_action, vim.tbl_extend("force", opts, { desc = "Code Action" }))
-
-  -- Navigation
-  nmap("gd", fzf.lsp_definitions, vim.tbl_extend("force", opts, { desc = "Go to Definition" }))
-  nmap("gr", fzf.lsp_references, vim.tbl_extend("force", opts, { desc = "Go to References" }))
-  nmap("gD", vim.lsp.buf.declaration, vim.tbl_extend("force", opts, { desc = "Go to Declaration" }))
-  nmap("gi", fzf.lsp_implementations, vim.tbl_extend("force", opts, { desc = "Go to Implementation" }))
-  nmap("gt", fzf.lsp_typedefs, vim.tbl_extend("force", opts, { desc = "Go to Type Definition" }))
-
-  -- Diagnostics
-  nmap("vd", vim.diagnostic.open_float, vim.tbl_extend("force", opts, { desc = "View Diagnostics" }))
-  nmap("<leader>dl", fzf.diagnostics_document, vim.tbl_extend("force", opts, { desc = "Document Diagnostics" }))
-  nmap("<leader>dw", fzf.diagnostics_workspace, vim.tbl_extend("force", opts, { desc = "Workspace Diagnostics" }))
-  nmap("<leader>ds", fzf.lsp_document_symbols, vim.tbl_extend("force", opts, { desc = "Document Symbols" }))
-  nmap("<leader>ws", fzf.lsp_workspace_symbols, vim.tbl_extend("force", opts, { desc = "Workspace Symbols" }))
-
-  -- LSP management
-  nmap("<leader>lr", function()
-    local clients = vim.lsp.get_clients({ bufnr = bufnr })
-    if #clients == 0 then
-      vim.notify("No LSP clients attached to buffer", vim.log.levels.WARN)
-      return
+  config = function()
+    -- Mason setup
+    require("mason").setup({ max_concurrent_installers = 4 })
+    require("fidget").setup({})
+
+    -- Enhance floating preview windows
+    local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview
+    function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)
+      opts = opts or {}
+      opts.border = opts.border or "rounded"
+      opts.max_width = opts.max_width or 80
+      opts.max_height = opts.max_height or 20
+      return orig_util_open_floating_preview(contents, syntax, opts, ...)
     end
 
-    local client_names = {}
-    for _, client in ipairs(clients) do
-      table.insert(client_names, client.name)
-      vim.cmd("LspRestart " .. client.name)
-    end
-    vim.notify("Restarted LSP clients: " .. table.concat(client_names, ", "), vim.log.levels.INFO)
-  end, vim.tbl_extend("force", opts, { desc = "Restart LSP" }))
-  nmap("<leader>li", ":LspInfo<CR>", vim.tbl_extend("force", opts, { desc = "LSP Info" }))
-end
-
-function M.config()
-  require("mason").setup({ max_concurrent_installers = 4 })
-  require("fidget").setup({})
-
-  local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview
-  function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)
-    opts = opts or {}
-    opts.border = opts.border or "rounded"
-    opts.max_width = opts.max_width or 80
-    opts.max_height = opts.max_height or 20
-    return orig_util_open_floating_preview(contents, syntax, opts, ...)
-  end
-
-  -- Diagnostics
-  vim.diagnostic.config({
-    virtual_text = { spacing = 2, source = "if_many" },
-    float = { border = "rounded", source = "if_many" },
-    severity_sort = true,
-    signs = vim.g.have_nerd_font and {
-      text = {
-        [vim.diagnostic.severity.ERROR] = "󰅚",
-        [vim.diagnostic.severity.WARN] = "󰀪",
-        [vim.diagnostic.severity.INFO] = "󰋽",
-        [vim.diagnostic.severity.HINT] = "󰌶",
-      },
-    } or {},
-  })
-
-  local servers = {
-    "gopls",
-    "jsonls",
-    "lua_ls",
-    "yamlls",
-    "graphql",
-    "html",
-    "omnisharp",
-    "svelte",
-    "vtsls",
-    "ccls",
-    "templ",
-  }
-
-  local tools = {
-    "prettierd",
-    "shfmt",
-    "stylua",
-    "latexindent",
-    "clang-format",
-    "csharpier",
-    "quick-lint-js",
-  }
-
-  local mason_unsupported = { "ccls" }
-
-  local mason_servers = vim.tbl_filter(function(server)
-    return not vim.tbl_contains(mason_unsupported, server)
-  end, servers)
-
-  require("mason-lspconfig").setup({
-    ensure_installed = mason_servers,
-    automatic_installation = true,
-    automatic_enable = true,
-  })
-  require("mason-tool-installer").setup({ ensure_installed = tools })
-
-  vim.lsp.enable(servers)
-
-  -- LSP Attach
-  vim.api.nvim_create_autocmd("LspAttach", {
-    group = vim.api.nvim_create_augroup("UserLspConfig", { clear = true }),
-    callback = function(args)
-      local client = vim.lsp.get_client_by_id(args.data.client_id)
-      if not client then
-        return
+    -- Diagnostics configuration
+    vim.diagnostic.config({
+      virtual_text = { spacing = 2, source = "if_many" },
+      float = { border = "rounded", source = "if_many" },
+      signs = vim.g.have_nerd_font and {
+        text = {
+          [vim.diagnostic.severity.ERROR] = "󰅚",
+          [vim.diagnostic.severity.WARN] = "󰀪",
+          [vim.diagnostic.severity.INFO] = "󰋽",
+          [vim.diagnostic.severity.HINT] = "󰌶",
+        },
+      } or true,
+      underline = true,
+      update_in_insert = true,
+      severity_sort = true,
+    })
+
+    -- Global floating options
+    _G.floating_options = {
+      focusable = true,
+      focus = false,
+      max_height = 50,
+      max_width = 100,
+    }
+
+    -- Auto-format on save
+    vim.api.nvim_create_autocmd("BufWritePre", {
+      callback = function()
+        if vim.lsp.buf_is_attached() then
+          vim.lsp.buf.format()
+        end
+      end,
+    })
+
+    -- Filter out unwanted code actions
+    vim.lsp.buf.code_action = (function(orig)
+      return function(opts)
+        opts = opts or {}
+        opts.filter = function(action)
+          if not action then
+            return false
+          end
+          -- Ignore gopls "Browse" actions
+          if action.title and action.title:match("Browse gopls") then
+            return false
+          end
+          return true
+        end
+        return orig(opts)
       end
+    end)(vim.lsp.buf.code_action)
 
-      setup_keymaps(args.buf)
+    -- Keymaps setup function
+    local function setup_keymaps(bufnr)
+      local fzf = require("fzf-lua")
+      local opts = { buffer = bufnr }
 
-      -- Inlay hints
-      if client:supports_method(vim.lsp.protocol.Methods.textDocument_inlayHint, args.buf) then
-        nmap("<leader>th", function()
-          vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = args.buf }), { bufnr = args.buf })
-        end, { buffer = args.buf, desc = "Toggle Inlay Hints" })
+      -- Helper function for mapping
+      local function nmap(key, func, desc_opts)
+        vim.keymap.set("n", key, func, desc_opts)
       end
 
-      -- Document highlights
-      if client.server_capabilities.documentHighlightProvider then
-        vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
-          buffer = args.buf,
-          callback = vim.lsp.buf.document_highlight,
-        })
-        vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, {
-          buffer = args.buf,
-          callback = vim.lsp.buf.clear_references,
-        })
-      end
-    end,
-  })
-end
+      -- Basic LSP
+      nmap("K", vim.lsp.buf.hover, vim.tbl_extend("force", opts, { desc = "Hover Doc" }))
+      nmap("<C-h>", vim.lsp.buf.signature_help, vim.tbl_extend("force", opts, { desc = "Signature Help" }))
+      nmap("<leader>r", vim.lsp.buf.rename, vim.tbl_extend("force", opts, { desc = "Rename" }))
+      nmap("<leader>ca", vim.lsp.buf.code_action, vim.tbl_extend("force", opts, { desc = "Code Action" }))
+
+      -- Navigation
+      nmap("gd", fzf.lsp_definitions, vim.tbl_extend("force", opts, { desc = "Go to Definition" }))
+      nmap("gr", fzf.lsp_references, vim.tbl_extend("force", opts, { desc = "Go to References" }))
+      nmap("gD", vim.lsp.buf.declaration, vim.tbl_extend("force", opts, { desc = "Go to Declaration" }))
+      nmap("gi", fzf.lsp_implementations, vim.tbl_extend("force", opts, { desc = "Go to Implementation" }))
+      nmap("gt", fzf.lsp_typedefs, vim.tbl_extend("force", opts, { desc = "Go to Type Definition" }))
+
+      -- Diagnostics
+      nmap("vd", vim.diagnostic.open_float, vim.tbl_extend("force", opts, { desc = "View Diagnostics" }))
+      nmap("<leader>dl", fzf.diagnostics_document, vim.tbl_extend("force", opts, { desc = "Document Diagnostics" }))
+      nmap("<leader>dw", fzf.diagnostics_workspace, vim.tbl_extend("force", opts, { desc = "Workspace Diagnostics" }))
+      nmap("<leader>ds", fzf.lsp_document_symbols, vim.tbl_extend("force", opts, { desc = "Document Symbols" }))
+      nmap("<leader>ws", fzf.lsp_workspace_symbols, vim.tbl_extend("force", opts, { desc = "Workspace Symbols" }))
+
+      -- LSP management
+      nmap("<leader>lr", function()
+        local clients = vim.lsp.get_clients({ bufnr = bufnr })
+        if #clients == 0 then
+          vim.notify("No LSP clients attached to buffer", vim.log.levels.WARN)
+          return
+        end
+
+        local client_names = {}
+        for _, client in ipairs(clients) do
+          table.insert(client_names, client.name)
+          vim.cmd("LspRestart " .. client.name)
+        end
+        vim.notify("Restarted LSP clients: " .. table.concat(client_names, ", "), vim.log.levels.INFO)
+      end, vim.tbl_extend("force", opts, { desc = "Restart LSP" }))
+      nmap("<leader>li", ":LspInfo<CR>", vim.tbl_extend("force", opts, { desc = "LSP Info" }))
+    end
 
-return M
+    -- LSP servers configuration
+    local servers = {
+      "gopls",
+      "jsonls",
+      "lua_ls",
+      "yamlls",
+      "graphql",
+      "html",
+      "omnisharp",
+      "svelte",
+      "vtsls",
+      "ccls",
+      "templ",
+      "tinymist",
+    }
+
+    -- Tools for mason-tool-installer
+    local tools = {
+      "prettierd",
+      "shfmt",
+      "stylua",
+      "latexindent",
+      "clang-format",
+      "csharpier",
+      "quick-lint-js",
+    }
+
+    -- Servers not supported by mason
+    local mason_unsupported = { "ccls" }
+
+    local mason_servers = vim.tbl_filter(function(server)
+      return not vim.tbl_contains(mason_unsupported, server)
+    end, servers)
+
+    -- Mason setup
+    require("mason-lspconfig").setup({
+      ensure_installed = mason_servers,
+      automatic_installation = true,
+      automatic_enable = false,
+    })
+    require("mason-tool-installer").setup({ ensure_installed = tools })
+
+    -- Enable LSP servers
+    vim.lsp.enable(servers)
+
+    -- LSP Attach autocmd
+    vim.api.nvim_create_autocmd("LspAttach", {
+      group = vim.api.nvim_create_augroup("UserLspConfig", { clear = true }),
+      callback = function(args)
+        local client = vim.lsp.get_client_by_id(args.data.client_id)
+        if not client then
+          return
+        end
+
+        -- Setup keymaps
+        setup_keymaps(args.buf)
+
+        -- Inlay hints
+        if client:supports_method(vim.lsp.protocol.Methods.textDocument_inlayHint, args.buf) then
+          vim.keymap.set("n", "<leader>th", function()
+            vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = args.buf }), { bufnr = args.buf })
+          end, { buffer = args.buf, desc = "Toggle Inlay Hints" })
+        end
+
+        -- Document highlights
+        if client.server_capabilities.documentHighlightProvider then
+          vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
+            buffer = args.buf,
+            callback = vim.lsp.buf.document_highlight,
+          })
+          vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, {
+            buffer = args.buf,
+            callback = vim.lsp.buf.clear_references,
+          })
+        end
+      end,
+    })
+  end,
+}

+ 32 - 4
lua/plugins/mini.lua

@@ -28,6 +28,7 @@ local M = {
       require("mini.surround").setup({})
     end,
   },
+
   {
     "echasnovski/mini.statusline",
     version = false,
@@ -37,17 +38,43 @@ local M = {
       MiniStatusline.section_codeium = function(args)
         args = args or {}
         local trunc_width = args.trunc_width or 75
-
         if MiniStatusline.is_truncated(trunc_width) then
           return ""
         end
-
         local status = vim.fn["codeium#GetStatusString"]()
-
         if status and status ~= "" then
           local icon = args.icon or "󰘦 "
           return icon .. status
         end
+        return ""
+      end
+
+      MiniStatusline.section_worktree = function(args)
+        args = args or {}
+        local trunc_width = args.trunc_width or 75
+        if MiniStatusline.is_truncated(trunc_width) then
+          return ""
+        end
+
+        -- Get current directory
+        local cwd = vim.fn.getcwd()
+
+        -- Run git worktree list to check if we're in a worktree
+        local handle = io.popen("git worktree list 2>/dev/null")
+        if not handle then
+          return ""
+        end
+
+        local output = handle:read("*a")
+        handle:close()
+
+        for line in output:gmatch("[^\n]+") do
+          local path, branch = line:match("^([^%s]+)%s+%[?([^%]]*)")
+          if path and path == cwd and branch and branch ~= "" then
+            local icon = args.icon or "🌿 "
+            return icon .. branch
+          end
+        end
 
         return ""
       end
@@ -63,6 +90,7 @@ local M = {
         local location = MiniStatusline.section_location({ trunc_width = 75 })
         local search = MiniStatusline.section_searchcount({ trunc_width = 75 })
         local codeium = MiniStatusline.section_codeium({ trunc_width = 75 })
+        local worktree = MiniStatusline.section_worktree({ trunc_width = 75 })
 
         return MiniStatusline.combine_groups({
           { hl = mode_hl, strings = { mode } },
@@ -70,7 +98,7 @@ local M = {
           "%<", -- Mark general truncate point
           { hl = "MiniStatuslineFilename", strings = { filename } },
           "%=", -- End left alignment
-          { hl = "MiniStatuslineFileinfo", strings = { fileinfo } },
+          { hl = "MiniStatuslineFileinfo", strings = { fileinfo, worktree } },
           { hl = mode_hl, strings = { codeium, search, location } },
         })
       end

+ 6 - 0
lua/plugins/typ.lua

@@ -0,0 +1,6 @@
+return {
+  "chomosuke/typst-preview.nvim",
+  ft = "typst",
+  version = "1.*",
+  opts = {},
+}