]> git.rmz.io Git - dotfiles.git/blobdiff - nvim/lua/plugins/ui.lua
nvim: show pretty_path in inactive sections too
[dotfiles.git] / nvim / lua / plugins / ui.lua
index 1b573076837c980075dfd6d08c9b93d13c2fe88d..afe5855d1ef3188bdc15b1a4b3016636fb4b1b14 100644 (file)
----@type LazyPluginSpec
+local M = {}
+
+---@param component any -- actually a lualine.component
+---@param text string
+---@param hl_group? string
+---@return string
+function M.format(component, text, hl_group)
+  text = text:gsub("%%", "%%%%")
+  if not hl_group or hl_group == "" then
+    return text
+  end
+  --- hl_cache is added here, not modified
+  ---@type table<string, string>
+  component.hl_cache = component.hl_cache or {}
+  local lualine_hl_group = component.hl_cache[hl_group]
+  if not lualine_hl_group then
+    local utils = require("lualine.utils.utils")
+    ---@type string[]
+    local gui = vim.tbl_filter(function(x) return x end, {
+      utils.extract_highlight_colors(hl_group, "bold") and "bold",
+      utils.extract_highlight_colors(hl_group, "italic") and "italic",
+    })
+
+    lualine_hl_group = component:create_hl({
+      fg = utils.extract_highlight_colors(hl_group, "fg"),
+      gui = #gui > 0 and table.concat(gui, ",") or nil,
+    }, "LV_" .. hl_group) --[[@as string]]
+    component.hl_cache[hl_group] = lualine_hl_group
+  end
+  return component:format_hl(lualine_hl_group) .. text .. component:get_default_hl()
+end
+
+function M.pretty_path()
+  return function(self)
+    local opts = {
+      directory_hl = "",
+      filename_hl = "Bold",
+      length = 3,
+      modified_hl = "MatchParen",  -- hl group when file is modified
+      modified_sign = "",
+      readonly_icon = " 󰌾 ",
+    }
+
+    local path = vim.fn.expand("%:p") --[[@as string]]
+
+    if path == "" then
+      return ""
+    end
+
+    path = require("lazy.core.util").norm(path)
+    local cwd = vim.uv.cwd()
+
+    if path:find(cwd, 1, true) == 1 then
+      path = path:sub(#cwd + 2)
+    end
+
+    local sep = package.config:sub(1, 1)
+    local parts = vim.split(path, "[\\/]")
+
+    if opts.length == 0 then
+      parts = parts
+    elseif #parts > opts.length then
+      parts = { parts[1], "…", unpack(parts, #parts - opts.length + 2, #parts) }
+    end
+
+    if vim.bo.modified then
+      parts[#parts] = parts[#parts] .. opts.modified_sign
+      parts[#parts] = M.format(self, parts[#parts], opts.modified_hl)
+    else
+      parts[#parts] = M.format(self, parts[#parts], opts.filename_hl)
+    end
+
+    local dir = ""
+    if #parts > 1 then
+      dir = table.concat({ unpack(parts, 1, #parts - 1) }, sep)
+      dir = M.format(self, dir .. sep, opts.directory_hl)
+    end
+
+    local readonly = ""
+    if vim.bo.readonly then
+      readonly = M.format(self, opts.readonly_icon, opts.modified_hl)
+    end
+    return dir .. parts[#parts] .. readonly
+  end
+end
+
+---@type LazySpec
 return {
-  {
-    "nvim-notify",
-  },
-  {
-    "bufferline.nvim",
-    ---@type BufferlineConfig
+  { 'echasnovski/mini.clue',
+    -- NOTE: this caused some issue with unterminated mappings, i.e. <L>gc when there 
+    -- is also <L>gcc. It would simply terminate early and not allow for next mapping.
+    version = '*',
     opts = {
-      options = {
-        always_show_bufferline = false,
+      triggers = {
+        { mode = 'n', keys = '<Leader>' },
+        { mode = 'x', keys = '<Leader>' },
+        -- `g` key
+        { mode = 'n', keys = 'g' },
+        { mode = 'x', keys = 'g' },
+        -- Marks
+        { mode = 'n', keys = "'" },
+        { mode = 'n', keys = '`' },
+        { mode = 'x', keys = "'" },
+        { mode = 'x', keys = '`' },
+        -- Window commands
+        { mode = 'n', keys = '<C-w>' },
+        -- `z` key
+        { mode = 'n', keys = 'z' },
+        { mode = 'x', keys = 'z' },
+      },
+      clues = {
+        { mode = 'n', keys = '<Leader>b', desc = '+Buffers' },
+        { mode = 'n', keys = '<Leader>c', desc = '+LSP' },
       },
     },
   },
-  {
-    "noice.nvim",
-    ---@type NoiceConfig
+  { "akinsho/bufferline.nvim",
+    event = "VeryLazy",
+    keys = {
+      { "<leader>bp", "<Cmd>BufferLineTogglePin<CR>", desc = "Toggle Pin" },
+      { "<leader>bP", "<Cmd>BufferLineGroupClose ungrouped<CR>", desc = "Delete Non-Pinned Buffers" },
+      { "<leader>br", "<Cmd>BufferLineCloseRight<CR>", desc = "Delete Buffers to the Right" },
+      { "<leader>bl", "<Cmd>BufferLineCloseLeft<CR>", desc = "Delete Buffers to the Left" },
+      { "<S-h>", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev Buffer" },
+      { "<S-l>", "<cmd>BufferLineCycleNext<cr>", desc = "Next Buffer" },
+      { "[b", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev Buffer" },
+      { "]b", "<cmd>BufferLineCycleNext<cr>", desc = "Next Buffer" },
+      { "[B", "<cmd>BufferLineMovePrev<cr>", desc = "Move buffer prev" },
+      { "]B", "<cmd>BufferLineMoveNext<cr>", desc = "Move buffer next" },
+    },
+    ---@type BufferlineConfig
     opts = {
-      presets = {
-        command_palette = false, -- don't position the cmdline and popupmenu together
-        lsp_doc_border = true,
-        long_message_to_split = true,
-      },
-      cmdline = {
-        view = "cmdline",
-      },
-      routes = {
-        { -- send file written messages to mini
-          filter = {
-            event = "msg_show",
-            kind = "",
-            find = "%[w%]",
+      options = {
+        close_command = function(n) Snacks.bufdelete(n) end,
+        right_mouse_command = function(n) Snacks.bufdelete(n) end,
+        diagnostics = "nvim_lsp",
+        always_show_bufferline = false,
+        diagnostics_indicator = function(_, _, diag)
+          local icons = LazyVim.config.icons.diagnostics
+          local ret = (diag.error and icons.Error .. diag.error .. " " or "")
+            .. (diag.warning and icons.Warn .. diag.warning or "")
+          return vim.trim(ret)
+        end,
+        offsets = {
+          {
+            filetype = "man",
+            text = "Man page",
+            highlight = "Directory",
+            text_align = "left",
           },
-          opts = { skip = true },
         },
+        ---@param opts bufferline.IconFetcherOpts
+        get_element_icon = function(opts)
+          return LazyVim.config.icons.ft[opts.filetype]
+        end,
       },
     },
-    config = function(_, opts)
-      -- ensure [w] is written to msg_show so we can match it
-      vim.opt.shortmess:append("w")
-      vim.opt.shortmess:remove("W")
-
-      require("noice").setup(opts)
-    end,
   },
-  {
-    "lualine.nvim",
-    --TODO: Things that were in vim but are missing
+  { "nvim-lualine/lualine.nvim",
+    -- TODO: Things that were in vim but are missing
     -- - git line add/mod/del ar next to branch name rather on right
     -- - one status line per splits
     --   - maybe a single one is OK too?
@@ -53,59 +165,193 @@ return {
     --   - unix/dos eof markers
     --     - really I only want to know if it's not unix
     --   - filetype in text form. It's quite important to glance this quickly
+    event = "VeryLazy",
+    init = function()
+      vim.g.lualine_laststatus = vim.o.laststatus
+      if vim.fn.argc(-1) > 0 then
+        -- set an empty statusline till lualine loads
+        vim.o.statusline = " "
+      else
+        -- hide the statusline on the starter page
+        vim.o.laststatus = 0
+      end
+    end,
+    opts = function()
+      -- PERF: we don't need this lualine require madness 🤷
+      local lualine_require = require("lualine_require")
+      lualine_require.require = require
+
+      local icons = LazyVim.config.icons
+
+      vim.o.laststatus = vim.g.lualine_laststatus
+
+      local opts = {
+        options = {
+          theme = "auto",
+          globalstatus = vim.o.laststatus == 3,
+          disabled_filetypes = { statusline = { "dashboard", "alpha", "ministarter", "snacks_dashboard" } },
+        },
+        sections = {
+          lualine_a = { "mode" },
+          lualine_b = { "branch" },
+
+          lualine_c = {
+            {
+              "diagnostics",
+              symbols = {
+                error = icons.diagnostics.Error,
+                warn = icons.diagnostics.Warn,
+                info = icons.diagnostics.Info,
+                hint = icons.diagnostics.Hint,
+              },
+            },
+            { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
+            { M.pretty_path() },
+          },
+          lualine_x = {
+            Snacks.profiler.status(),
+            -- stylua: ignore
+            {
+              function() return "  " .. require("dap").status() end,
+              cond = function() return package.loaded["dap"] and require("dap").status() ~= "" end,
+              color = function() return { fg = Snacks.util.color("Debug") } end,
+            },
+            -- stylua: ignore
+            {
+              require("lazy.status").updates,
+              cond = require("lazy.status").has_updates,
+              color = function() return { fg = Snacks.util.color("Special") } end,
+            },
+            {
+              "diff",
+              symbols = {
+                added = icons.git.added,
+                modified = icons.git.modified,
+                removed = icons.git.removed,
+              },
+              source = function()
+                local gitsigns = vim.b.gitsigns_status_dict
+                if gitsigns then
+                  return {
+                    added = gitsigns.added,
+                    modified = gitsigns.changed,
+                    removed = gitsigns.removed,
+                  }
+                end
+              end,
+            },
+          },
+          lualine_y = {
+            { "progress", separator = " ", padding = { left = 1, right = 0 } },
+            { "location", padding = { left = 0, right = 1 } },
+          },
+          lualine_z = {
+            function()
+              return " " .. os.date("%R")
+            end,
+          },
+        },
+        inactive_sections = {
+          lualine_c = {
+            { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
+            { M.pretty_path() },
+          },
+        },
+        extensions = { "neo-tree", "lazy", "fzf" },
+      }
+
+      local trouble = require("trouble")
+      local symbols = trouble.statusline({
+        mode = "symbols",
+        groups = {},
+        title = false,
+        filter = { range = true },
+        format = "{kind_icon}{symbol.name:Normal}",
+        hl_group = "lualine_c_normal",
+      })
+      table.insert(opts.sections.lualine_c, {
+        symbols and symbols.get,
+        cond = function()
+          return vim.b.trouble_lualine ~= false and symbols.has()
+        end,
+      })
+
+      return opts
+    end,
   },
   {
-    "indent-blankline.nvim",
+    "echasnovski/mini.icons",
+    lazy = true,
+    opts = {
+      file = {
+        [".keep"] = { glyph = "󰊢", hl = "MiniIconsGrey" },
+        ["devcontainer.json"] = { glyph = "", hl = "MiniIconsAzure" },
+      },
+      filetype = {
+        dotenv = { glyph = "", hl = "MiniIconsYellow" },
+      },
+    },
+    init = function()
+      -- TODO: try without this
+      -- see :h MiniIcons.mock_nvim_web_devicons()
+      package.preload["nvim-web-devicons"] = function()
+        require("mini.icons").mock_nvim_web_devicons()
+        return package.loaded["nvim-web-devicons"]
+      end
+    end,
   },
-  {
-    "mini.indentscope",
+  { "MunifTanjim/nui.nvim", lazy = true },
+  { "stevearc/dressing.nvim",
+    enabled = false,  -- replaced by snacks.input
+    lazy = true,
     opts = {
-      draw = {
-        animation = require("mini.indentscope").gen_animation.linear({ duration = 10 }),
+      input = {
+        start_in_insert = false,
+        insert_only = false,
       },
     },
   },
-  {
-    "alpha-nvim",
-    opts = function()
-      local dashboard = require("alpha.themes.dashboard")
-      local logo = [[
-      ██╗      █████╗ ███████╗██╗   ██╗██╗   ██╗██╗███╗   ███╗          Z
-      ██║     ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║   ██║██║████╗ ████║      Z    
-      ██║     ███████║  ███╔╝  ╚████╔╝ ██║   ██║██║██╔████╔██║   z       
-      ██║     ██╔══██║ ███╔╝    ╚██╔╝  ╚██╗ ██╔╝██║██║╚██╔╝██║ z         
-      ███████╗██║  ██║███████╗   ██║    ╚████╔╝ ██║██║ ╚═╝ ██║
-      ╚══════╝╚═╝  ╚═╝╚══════╝   ╚═╝     ╚═══╝  ╚═╝╚═╝     ╚═╝
-      ]]
-
-      dashboard.section.header.val = vim.split(logo, "\n")
-      dashboard.section.buttons.val = {
-        dashboard.button("f", " " .. " Find file", ":Telescope find_files <CR>"),
-        dashboard.button("n", " " .. " New file", ":ene <BAR> startinsert <CR>"),
-        dashboard.button("r", " " .. " Recent files", ":Telescope oldfiles <CR>"),
-        dashboard.button("c", " " .. " Config", ":e $MYVIMRC <CR>"),
-        dashboard.button("s", " " .. " Restore Session", [[:lua require("persistence").load() <cr>]]),
-        dashboard.button("l", "󰒲 " .. " Lazy", ":Lazy<CR>"),
-        dashboard.button("q", " " .. " Close", ":bdelete<CR>"),
+  { "indent-blankline.nvim",
+    enabled = false,  -- replaced by snacks.indent
+  },
+  { "echasnovski/mini.indentscope",
+    enabled = false,  -- replaced by snacks.indent
+    version = false, -- wait till new 0.7.0 release to put it back on semver
+    event = "LazyFile",
+    opts = function (_, opts)
+      return {
+        draw = {
+          animation = require("mini.indentscope").gen_animation.linear({ duration = 10 })
+        }
       }
-      for _, button in ipairs(dashboard.section.buttons.val) do
-        button.opts.hl = "AlphaButtons"
-        button.opts.hl_shortcut = "AlphaShortcut"
-      end
-      dashboard.section.footer.opts.hl = "Type"
-      dashboard.section.header.opts.hl = "AlphaHeader"
-      dashboard.section.buttons.opts.hl = "AlphaButtons"
-      dashboard.opts.layout[1].val = 8
-      return dashboard
     end,
   },
-  {
-    "nvim-navic",
-  },
-  {
-    "nvim-web-devicons",
+  { "SmiteshP/nvim-navic",
+    lazy = true,
+    init = function()
+      vim.g.navic_silence = true
+      LazyVim.lsp.on_attach(function(client, buffer)
+        if client.supports_method("textDocument/documentSymbol") then
+          require("nvim-navic").attach(client, buffer)
+        end
+      end)
+    end,
+    opts = function()
+      return {
+        separator = " ",
+        highlight = true,
+        depth_limit = 5,
+        icons = LazyVim.config.icons.kinds,
+        lazy_update_context = true,
+      }
+    end,
   },
-  {
-    "nui.nvim",
+  { "nvim-lualine/lualine.nvim",
+    optional = true,
+    opts = function(_, opts)
+      if not vim.g.trouble_lualine then
+        table.insert(opts.sections.lualine_c, { "navic", color_correction = "dynamic" })
+      end
+    end,
   },
 }