bufferline.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. local M = {}
  2. local function is_ft(b, ft)
  3. return vim.bo[b].filetype == ft
  4. end
  5. local function diagnostics_indicator(num, _, diagnostics, _)
  6. local result = {}
  7. local symbols = { error = "", warning = "", info = "" }
  8. if not lvim.use_icons then
  9. return "(" .. num .. ")"
  10. end
  11. for name, count in pairs(diagnostics) do
  12. if symbols[name] and count > 0 then
  13. table.insert(result, symbols[name] .. " " .. count)
  14. end
  15. end
  16. result = table.concat(result, " ")
  17. return #result > 0 and result or ""
  18. end
  19. local function custom_filter(buf, buf_nums)
  20. local logs = vim.tbl_filter(function(b)
  21. return is_ft(b, "log")
  22. end, buf_nums)
  23. if vim.tbl_isempty(logs) then
  24. return true
  25. end
  26. local tab_num = vim.fn.tabpagenr()
  27. local last_tab = vim.fn.tabpagenr "$"
  28. local is_log = is_ft(buf, "log")
  29. if last_tab == 1 then
  30. return true
  31. end
  32. -- only show log buffers in secondary tabs
  33. return (tab_num == last_tab and is_log) or (tab_num ~= last_tab and not is_log)
  34. end
  35. M.config = function()
  36. lvim.builtin.bufferline = {
  37. active = true,
  38. on_config_done = nil,
  39. keymap = {
  40. normal_mode = {},
  41. },
  42. highlights = {
  43. background = {
  44. italic = true,
  45. },
  46. buffer_selected = {
  47. bold = true,
  48. },
  49. },
  50. options = {
  51. numbers = "none", -- can be "none" | "ordinal" | "buffer_id" | "both" | function
  52. close_command = "bdelete! %d", -- can be a string | function, see "Mouse actions"
  53. right_mouse_command = "vert sbuffer %d", -- can be a string | function, see "Mouse actions"
  54. left_mouse_command = "buffer %d", -- can be a string | function, see "Mouse actions"
  55. middle_mouse_command = nil, -- can be a string | function, see "Mouse actions"
  56. -- NOTE: this plugin is designed with this icon in mind,
  57. -- and so changing this is NOT recommended, this is intended
  58. -- as an escape hatch for people who cannot bear it for whatever reason
  59. indicator_icon = "▎",
  60. buffer_close_icon = "",
  61. modified_icon = "●",
  62. close_icon = "",
  63. left_trunc_marker = "",
  64. right_trunc_marker = "",
  65. --- name_formatter can be used to change the buffer's label in the bufferline.
  66. --- Please note some names can/will break the
  67. --- bufferline so use this at your discretion knowing that it has
  68. --- some limitations that will *NOT* be fixed.
  69. name_formatter = function(buf) -- buf contains a "name", "path" and "bufnr"
  70. -- remove extension from markdown files for example
  71. if buf.name:match "%.md" then
  72. return vim.fn.fnamemodify(buf.name, ":t:r")
  73. end
  74. end,
  75. max_name_length = 18,
  76. max_prefix_length = 15, -- prefix used when a buffer is de-duplicated
  77. tab_size = 18,
  78. diagnostics = "nvim_lsp",
  79. diagnostics_update_in_insert = false,
  80. diagnostics_indicator = diagnostics_indicator,
  81. -- NOTE: this will be called a lot so don't do any heavy processing here
  82. custom_filter = custom_filter,
  83. offsets = {
  84. {
  85. filetype = "undotree",
  86. text = "Undotree",
  87. highlight = "PanelHeading",
  88. padding = 1,
  89. },
  90. {
  91. filetype = "NvimTree",
  92. text = "Explorer",
  93. highlight = "PanelHeading",
  94. padding = 1,
  95. },
  96. {
  97. filetype = "DiffviewFiles",
  98. text = "Diff View",
  99. highlight = "PanelHeading",
  100. padding = 1,
  101. },
  102. {
  103. filetype = "flutterToolsOutline",
  104. text = "Flutter Outline",
  105. highlight = "PanelHeading",
  106. },
  107. {
  108. filetype = "packer",
  109. text = "Packer",
  110. highlight = "PanelHeading",
  111. padding = 1,
  112. },
  113. },
  114. show_buffer_icons = lvim.use_icons, -- disable filetype icons for buffers
  115. show_buffer_close_icons = lvim.use_icons,
  116. show_close_icon = false,
  117. show_tab_indicators = true,
  118. persist_buffer_sort = true, -- whether or not custom sorted buffers should persist
  119. -- can also be a table containing 2 custom separators
  120. -- [focused and unfocused]. eg: { '|', '|' }
  121. separator_style = "thin",
  122. enforce_regular_tabs = false,
  123. always_show_bufferline = false,
  124. sort_by = "id",
  125. },
  126. }
  127. end
  128. M.setup = function()
  129. require("lvim.keymappings").load(lvim.builtin.bufferline.keymap)
  130. require("bufferline").setup {
  131. options = lvim.builtin.bufferline.options,
  132. highlights = lvim.builtin.bufferline.highlights,
  133. }
  134. if lvim.builtin.bufferline.on_config_done then
  135. lvim.builtin.bufferline.on_config_done()
  136. end
  137. end
  138. --stylua: ignore
  139. -- Common kill function for bdelete and bwipeout
  140. -- credits: based on bbye and nvim-bufdel
  141. ---@param kill_command? string defaults to "bd"
  142. ---@param bufnr? number defaults to the current buffer
  143. ---@param force? boolean defaults to false
  144. function M.buf_kill(kill_command, bufnr, force)
  145. kill_command = kill_command or "bd"
  146. local bo = vim.bo
  147. local api = vim.api
  148. local fmt = string.format
  149. local fnamemodify = vim.fn.fnamemodify
  150. if bufnr == 0 or bufnr == nil then
  151. bufnr = api.nvim_get_current_buf()
  152. end
  153. local bufname = api.nvim_buf_get_name(bufnr)
  154. if not force then
  155. local warning
  156. if bo[bufnr].modified then
  157. warning = fmt([[No write since last change for (%s)]], fnamemodify(bufname, ":t"))
  158. elseif api.nvim_buf_get_option(bufnr, "buftype") == "terminal" then
  159. warning = fmt([[Terminal %s will be killed]], bufname)
  160. end
  161. if warning then
  162. vim.ui.input({
  163. prompt = string.format([[%s. Close it anyway? [y]es or [n]o (default: no): ]], warning),
  164. }, function(choice)
  165. if choice:match "ye?s?" then force = true end
  166. end)
  167. if not force then return end
  168. end
  169. end
  170. -- Get list of windows IDs with the buffer to close
  171. local windows = vim.tbl_filter(function(win)
  172. return api.nvim_win_get_buf(win) == bufnr
  173. end, api.nvim_list_wins())
  174. if #windows == 0 then return end
  175. if force then
  176. kill_command = kill_command .. "!"
  177. end
  178. -- Get list of active buffers
  179. local buffers = vim.tbl_filter(function(buf)
  180. return api.nvim_buf_is_valid(buf) and bo[buf].buflisted
  181. end, api.nvim_list_bufs())
  182. -- If there is only one buffer (which has to be the current one), vim will
  183. -- create a new buffer on :bd.
  184. -- For more than one buffer, pick the previous buffer (wrapping around if necessary)
  185. if #buffers > 1 then
  186. for i, v in ipairs(buffers) do
  187. if v == bufnr then
  188. local prev_buf_idx = i == 1 and (#buffers - 1) or (i - 1)
  189. local prev_buffer = buffers[prev_buf_idx]
  190. for _, win in ipairs(windows) do
  191. api.nvim_win_set_buf(win, prev_buffer)
  192. end
  193. end
  194. end
  195. end
  196. -- Check if buffer still exists, to ensure the target buffer wasn't killed
  197. -- due to options like bufhidden=wipe.
  198. if api.nvim_buf_is_valid(bufnr) and bo[bufnr].buflisted then
  199. vim.cmd(string.format("%s %d", kill_command, bufnr))
  200. end
  201. end
  202. return M