]> git.rmz.io Git - dotfiles.git/blob - nvim/lua/plugins/ui.lua
vim: do not set pastetoggle in nvim
[dotfiles.git] / nvim / lua / plugins / ui.lua
1 local M = {}
2
3 ---@param component any -- actually a lualine.component
4 ---@param text string
5 ---@param hl_group? string
6 ---@return string
7 function M.format(component, text, hl_group)
8 text = text:gsub("%%", "%%%%")
9 if not hl_group or hl_group == "" then
10 return text
11 end
12 --- hl_cache is added here, not modified
13 ---@type table<string, string>
14 component.hl_cache = component.hl_cache or {}
15 local lualine_hl_group = component.hl_cache[hl_group]
16 if not lualine_hl_group then
17 local utils = require("lualine.utils.utils")
18 ---@type string[]
19 local gui = vim.tbl_filter(function(x) return x end, {
20 utils.extract_highlight_colors(hl_group, "bold") and "bold",
21 utils.extract_highlight_colors(hl_group, "italic") and "italic",
22 })
23
24 lualine_hl_group = component:create_hl({
25 fg = utils.extract_highlight_colors(hl_group, "fg"),
26 gui = #gui > 0 and table.concat(gui, ",") or nil,
27 }, "LV_" .. hl_group) --[[@as string]]
28 component.hl_cache[hl_group] = lualine_hl_group
29 end
30 return component:format_hl(lualine_hl_group) .. text .. component:get_default_hl()
31 end
32
33 function M.pretty_path()
34 return function(self)
35 local opts = {
36 directory_hl = "",
37 filename_hl = "Bold",
38 length = 3,
39 modified_hl = "MatchParen", -- hl group when file is modified
40 modified_sign = "",
41 readonly_icon = " 󰌾 ",
42 }
43
44 local path = vim.fn.expand("%:p") --[[@as string]]
45
46 if path == "" then
47 return ""
48 end
49
50 path = require("lazy.core.util").norm(path)
51 local cwd = vim.uv.cwd()
52
53 if path:find(cwd, 1, true) == 1 then
54 path = path:sub(#cwd + 2)
55 end
56
57 local sep = package.config:sub(1, 1)
58 local parts = vim.split(path, "[\\/]")
59
60 if opts.length == 0 then
61 parts = parts
62 elseif #parts > opts.length then
63 parts = { parts[1], "…", unpack(parts, #parts - opts.length + 2, #parts) }
64 end
65
66 if vim.bo.modified then
67 parts[#parts] = parts[#parts] .. opts.modified_sign
68 parts[#parts] = M.format(self, parts[#parts], opts.modified_hl)
69 else
70 parts[#parts] = M.format(self, parts[#parts], opts.filename_hl)
71 end
72
73 local dir = ""
74 if #parts > 1 then
75 dir = table.concat({ unpack(parts, 1, #parts - 1) }, sep)
76 dir = M.format(self, dir .. sep, opts.directory_hl)
77 end
78
79 local readonly = ""
80 if vim.bo.readonly then
81 readonly = M.format(self, opts.readonly_icon, opts.modified_hl)
82 end
83 return dir .. parts[#parts] .. readonly
84 end
85 end
86
87 ---@type LazySpec
88 return {
89 { 'echasnovski/mini.clue',
90 -- NOTE: this caused some issue with unterminated mappings, i.e. <L>gc when there
91 -- is also <L>gcc. It would simply terminate early and not allow for next mapping.
92 version = '*',
93 lazy = true, -- NOTE: load this explicitely when needed, it blocks querying for key definitons via :Verbose map
94 opts = {
95 triggers = {
96 { mode = 'n', keys = '<Leader>' },
97 { mode = 'x', keys = '<Leader>' },
98 -- `g` key
99 { mode = 'n', keys = 'g' },
100 { mode = 'x', keys = 'g' },
101 -- Marks
102 { mode = 'n', keys = "'" },
103 { mode = 'n', keys = '`' },
104 { mode = 'x', keys = "'" },
105 { mode = 'x', keys = '`' },
106 -- Window commands
107 { mode = 'n', keys = '<C-w>' },
108 -- `z` key
109 { mode = 'n', keys = 'z' },
110 { mode = 'x', keys = 'z' },
111 },
112 clues = {
113 { mode = 'n', keys = '<Leader>b', desc = '+Buffers' },
114 { mode = 'n', keys = '<Leader>c', desc = '+LSP' },
115 },
116 },
117 },
118 { "akinsho/bufferline.nvim",
119 event = "VeryLazy",
120 keys = {
121 { "<leader>bp", "<Cmd>BufferLineTogglePin<CR>", desc = "Toggle Pin" },
122 { "<leader>bP", "<Cmd>BufferLineGroupClose ungrouped<CR>", desc = "Delete Non-Pinned Buffers" },
123 { "<leader>br", "<Cmd>BufferLineCloseRight<CR>", desc = "Delete Buffers to the Right" },
124 { "<leader>bl", "<Cmd>BufferLineCloseLeft<CR>", desc = "Delete Buffers to the Left" },
125 { "<S-h>", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev Buffer" },
126 { "<S-l>", "<cmd>BufferLineCycleNext<cr>", desc = "Next Buffer" },
127 { "[b", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev Buffer" },
128 { "]b", "<cmd>BufferLineCycleNext<cr>", desc = "Next Buffer" },
129 { "[B", "<cmd>BufferLineMovePrev<cr>", desc = "Move buffer prev" },
130 { "]B", "<cmd>BufferLineMoveNext<cr>", desc = "Move buffer next" },
131 },
132 ---@type BufferlineConfig
133 opts = {
134 options = {
135 close_command = function(n) Snacks.bufdelete(n) end,
136 right_mouse_command = function(n) Snacks.bufdelete(n) end,
137 diagnostics = "nvim_lsp",
138 always_show_bufferline = false,
139 diagnostics_indicator = function(_, _, diag)
140 local icons = rmz.ui.icons.diagnostics
141 local ret = (diag.error and icons.Error .. diag.error .. " " or "")
142 .. (diag.warning and icons.Warn .. diag.warning or "")
143 return vim.trim(ret)
144 end,
145 offsets = {
146 {
147 filetype = "man",
148 text = "Man page",
149 highlight = "Directory",
150 text_align = "left",
151 },
152 },
153 ---@param opts bufferline.IconFetcherOpts
154 get_element_icon = function(opts)
155 return rmz.ui.icons.ft[opts.filetype]
156 end,
157 },
158 },
159 },
160 { "nvim-lualine/lualine.nvim",
161 -- TODO: Things that were in vim but are missing
162 -- - git line add/mod/del ar next to branch name rather on right
163 -- - one status line per splits
164 -- - maybe a single one is OK too?
165 -- - I think I want a line stating wihch file is in the split though
166 -- - unix/dos eof markers
167 -- - really I only want to know if it's not unix
168 -- - filetype in text form. It's quite important to glance this quickly
169 event = "VeryLazy",
170 init = function()
171 vim.g.lualine_laststatus = vim.o.laststatus
172 if vim.fn.argc(-1) > 0 then
173 -- set an empty statusline till lualine loads
174 vim.o.statusline = " "
175 else
176 -- hide the statusline on the starter page
177 vim.o.laststatus = 0
178 end
179 end,
180 opts = function()
181 -- PERF: we don't need this lualine require madness 🤷
182 local lualine_require = require("lualine_require")
183 lualine_require.require = require
184
185 local icons = rmz.ui.icons
186
187 vim.o.laststatus = vim.g.lualine_laststatus
188
189 local opts = {
190 options = {
191 theme = "auto",
192 globalstatus = vim.o.laststatus == 3,
193 disabled_filetypes = { statusline = { "dashboard", "alpha", "ministarter", "snacks_dashboard" } },
194 },
195 sections = {
196 lualine_a = { "mode" },
197 lualine_b = { "branch" },
198
199 lualine_c = {
200 {
201 "diagnostics",
202 symbols = {
203 error = icons.diagnostics.Error,
204 warn = icons.diagnostics.Warn,
205 info = icons.diagnostics.Info,
206 hint = icons.diagnostics.Hint,
207 },
208 },
209 { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
210 { M.pretty_path() },
211 },
212 lualine_x = {
213 Snacks.profiler.status(),
214 -- stylua: ignore
215 {
216 function() return " " .. require("dap").status() end,
217 cond = function() return package.loaded["dap"] and require("dap").status() ~= "" end,
218 color = function() return { fg = Snacks.util.color("Debug") } end,
219 },
220 -- stylua: ignore
221 {
222 require("lazy.status").updates,
223 cond = require("lazy.status").has_updates,
224 color = function() return { fg = Snacks.util.color("Special") } end,
225 },
226 {
227 "diff",
228 symbols = {
229 added = icons.git.added,
230 modified = icons.git.modified,
231 removed = icons.git.removed,
232 },
233 source = function()
234 local gitsigns = vim.b.gitsigns_status_dict
235 if gitsigns then
236 return {
237 added = gitsigns.added,
238 modified = gitsigns.changed,
239 removed = gitsigns.removed,
240 }
241 end
242 end,
243 },
244 },
245 lualine_y = {
246 { "progress", separator = " ", padding = { left = 1, right = 0 } },
247 { "location", padding = { left = 0, right = 1 } },
248 },
249 lualine_z = {
250 function()
251 return " " .. os.date("%R")
252 end,
253 },
254 },
255 inactive_sections = {
256 lualine_c = {
257 { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
258 { M.pretty_path() },
259 },
260 },
261 extensions = { "neo-tree", "lazy", "fzf" },
262 }
263
264 local trouble = require("trouble")
265 local symbols = trouble.statusline({
266 mode = "symbols",
267 groups = {},
268 title = false,
269 filter = { range = true },
270 format = "{kind_icon}{symbol.name:Normal}",
271 hl_group = "lualine_c_normal",
272 })
273 table.insert(opts.sections.lualine_c, {
274 symbols and symbols.get,
275 cond = function()
276 return vim.b.trouble_lualine ~= false and symbols.has()
277 end,
278 })
279
280 return opts
281 end,
282 },
283 {
284 "echasnovski/mini.icons",
285 lazy = true,
286 opts = {
287 file = {
288 [".keep"] = { glyph = "󰊢", hl = "MiniIconsGrey" },
289 ["devcontainer.json"] = { glyph = "", hl = "MiniIconsAzure" },
290 },
291 filetype = {
292 dotenv = { glyph = "", hl = "MiniIconsYellow" },
293 },
294 },
295 init = function()
296 -- TODO: try without this
297 -- see :h MiniIcons.mock_nvim_web_devicons()
298 package.preload["nvim-web-devicons"] = function()
299 require("mini.icons").mock_nvim_web_devicons()
300 return package.loaded["nvim-web-devicons"]
301 end
302 end,
303 },
304 { "MunifTanjim/nui.nvim", lazy = true },
305 { "stevearc/dressing.nvim",
306 enabled = false, -- replaced by snacks.input
307 lazy = true,
308 opts = {
309 input = {
310 start_in_insert = false,
311 insert_only = false,
312 },
313 },
314 },
315 { "indent-blankline.nvim",
316 enabled = false, -- replaced by snacks.indent
317 },
318 { "echasnovski/mini.indentscope",
319 enabled = false, -- replaced by snacks.indent
320 version = false, -- wait till new 0.7.0 release to put it back on semver
321 event = { "BufReadPost", "BufNewFile", "BufWritePre" },
322 opts = function (_, opts)
323 return {
324 draw = {
325 animation = require("mini.indentscope").gen_animation.linear({ duration = 10 })
326 }
327 }
328 end,
329 },
330 { "SmiteshP/nvim-navic",
331 lazy = true,
332 init = function()
333 vim.g.navic_silence = true
334 rmz.lsp.on_attach(function(client, buffer)
335 if client.supports_method("textDocument/documentSymbol") then
336 require("nvim-navic").attach(client, buffer)
337 end
338 end)
339 end,
340 opts = function()
341 return {
342 separator = " ",
343 highlight = true,
344 depth_limit = 5,
345 icons = rmz.ui.icons.kinds,
346 lazy_update_context = true,
347 }
348 end,
349 },
350 { "nvim-lualine/lualine.nvim",
351 optional = true,
352 opts = function(_, opts)
353 if not vim.g.trouble_lualine then
354 table.insert(opts.sections.lualine_c, { "navic", color_correction = "dynamic" })
355 end
356 end,
357 },
358 }