diff --git a/README.md b/README.md index 986a8f2a..29320869 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ - [Treesitter](#treesitter) - [LSP](#lsp) - [Markdown](#markdown) + - [Terminal](#terminal) - [API](#api) - [Utility Functions](#utility-functions) - [Bar Utility Functions](#bar-utility-functions) @@ -69,7 +70,7 @@ https://github.com/Bekaboo/dropbar.nvim/assets/76579810/e8c1ac26-0321-4762-9975- - [x] Multiple backends that support fall-backs - `dropbar.nvim` comes with four builtin sources: + `dropbar.nvim` comes with five builtin sources: - [x] [lsp](https://github.com/Bekaboo/dropbar.nvim/blob/master/lua/dropbar/sources/lsp.lua): gets symbols from language servers using nvim's builtin LSP framework @@ -79,6 +80,8 @@ https://github.com/Bekaboo/dropbar.nvim/assets/76579810/e8c1ac26-0321-4762-9975- - [x] [treesitter](https://github.com/Bekaboo/dropbar.nvim/blob/master/lua/dropbar/sources/treesitter.lua): gets symbols from treesitter parsers using nvim's builtin treesitter integration + - [x] [terminal](https://github.com/Bekaboo/dropbar.nvim/blob/master/lua/dropbar/sources/terminal.lua): easily switch terminal buffers using the dropdown menu + To make a new source yourself, see [making a new source](#making-a-new-source). For source fall-backs support, see [bar options](#bar). @@ -612,6 +615,32 @@ https://github.com/Bekaboo/dropbar.nvim/assets/76579810/e8c1ac26-0321-4762-9975- look_ahead = 200, }, }, + terminal = { + ---@type string|fun(buf: integer): string + icon = function(buf) + local ok, icons = pcall(require, 'nvim-web-devicons') + if not ok then + return '$' + end + return icons.get_icon_by_filetype(vim.bo[buf].filetype) + end, + ---@type string|fun(buf: integer): string + icon_hl = function(buf) + local ok, icons = pcall(require, 'nvim-web-devicons') + if not ok then + return '$' + end + return select(2, icons.get_icon_by_filetype(vim.bo[buf].filetype)) + or 'DropBarIconKindValue' + end, + ---@type string|fun(buf: integer): string + name = vim.api.nvim_buf_get_name, + ---@type string|fun(buf: integer): string + name_hl = 'WinBar', + ---@type boolean + ---Show the current terminal buffer in the menu + show_current = true, + } }, } ``` @@ -831,7 +860,7 @@ the symbols: view.topline = topline vim.fn.winrestview(view) end - end, + end ``` #### Bar @@ -851,7 +880,6 @@ winbar: ```lua function(buf, _) local sources = require('dropbar.sources') - local utils = require('dropbar.utils') if vim.bo[buf].ft == 'markdown' then return { sources.path, @@ -862,6 +890,11 @@ winbar: }), } end + if vim.bo[buf].buftype == 'terminal' then + return { + sources.terminal, + } + end return { sources.path, utils.source.fallback({ @@ -869,7 +902,7 @@ winbar: sources.treesitter, }), } - end, + end ``` - For more information about sources, see [`dropbar_source_t`](#dropbar_source_t). - `opts.bar.padding`: `{ left: number, right: number }` @@ -1164,6 +1197,57 @@ each sources. - Number of lines to update when cursor moves out of the parsed range - Default: `200` +##### Terminal + +- `opts.sources.terminal.icon`: `string` or `fun(buf: integer): string` + - Icon to show before terminal names + - Default: + ```lua + icon = function(buf) + local ok, icons = pcall(require, 'nvim-web-devicons') + if not ok then + return '$' + end + return icons.get_icon_by_filetype(vim.bo[buf].filetype) + end + ``` + +- `opts.sources.terminal.icon_hl`: `string` or `fun(buf: integer): string` + - Default: + ```lua + function(buf) + local ok, icons = pcall(require, 'nvim-web-devicons') + if not ok then + return '$' + end + -- the second val returned is the hlgroup + return select(2, icons.get_icon_by_filetype(vim.bo[buf].filetype)) + or 'DropBarIconKindValue' + end + ``` + +- `opts.sources.terminal.name`: `string` or `fun(buf: integer): string` + - Easy to integrate with other plugins (for example, [toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim)): + ```lua + name = function(buf) + local name = vim.api.nvim_buf_get_name(buf) + local term = require("toggleterm.terminal").indentify(name) + if term then + return term.display_name or term.name + else + return name + end + end + ``` + - Default: `vim.api.nvim_buf_get_name` + +- opts.sources.terminal.name_hl: `string` or `fun(buf: integer): string` + - Default: 'WinBar' + +- `opts.sources.terminal.show_current: boolean` + - Show the current terminal buffer in the menu + - Default: `true` + ### API `dropbar.nvim` exposes a few functions in `lua/dropbar/api.lua` that can be diff --git a/lua/dropbar/configs.lua b/lua/dropbar/configs.lua index c10cef91..ee757b31 100644 --- a/lua/dropbar/configs.lua +++ b/lua/dropbar/configs.lua @@ -7,7 +7,7 @@ M.opts = { ---@type boolean|fun(buf: integer, win: integer, info: table?): boolean enable = function(buf, win, _) return not vim.api.nvim_win_get_config(win).zindex - and vim.bo[buf].buftype == '' + and (vim.bo[buf].buftype == '' or vim.bo[buf].buftype == 'terminal') and vim.api.nvim_buf_get_name(buf) ~= '' and not vim.wo[win].diff end, @@ -176,6 +176,11 @@ M.opts = { }), } end + if vim.bo[buf].buftype == 'terminal' then + return { + sources.terminal, + } + end return { sources.path, utils.source.fallback({ @@ -419,6 +424,32 @@ M.opts = { look_ahead = 200, }, }, + terminal = { + ---@type string|fun(buf: integer): string + icon = function(buf) + local ok, icons = pcall(require, 'nvim-web-devicons') + if not ok then + return '$' + end + return icons.get_icon_by_filetype(vim.bo[buf].filetype) + end, + ---@type string|fun(buf: integer): string + icon_hl = function(buf) + local ok, icons = pcall(require, 'nvim-web-devicons') + if not ok then + return '$' + end + return select(2, icons.get_icon_by_filetype(vim.bo[buf].filetype)) + or 'DropBarIconKindValue' + end, + ---@type string|fun(buf: integer): string + name = vim.api.nvim_buf_get_name, + ---@type string|fun(buf: integer): string + name_hl = 'WinBar', + ---@type boolean + ---Show the current terminal buffer in the menu + show_current = true, + }, }, } diff --git a/lua/dropbar/sources/terminal.lua b/lua/dropbar/sources/terminal.lua new file mode 100644 index 00000000..7b625b3a --- /dev/null +++ b/lua/dropbar/sources/terminal.lua @@ -0,0 +1,102 @@ +local initialized +local configs + +local function init() + initialized = true + configs = require('dropbar.configs') +end + +local function buf_info(buf) + local icon = configs.opts.sources.terminal.icon or '$' + if type(icon) == 'function' then + icon = icon(buf) + end + local icon_hl = configs.opts.sources.terminal.icon_hl or 'NormalNC' + if type(icon_hl) == 'function' then + icon_hl = icon_hl(buf) + end + local name = configs.opts.sources.terminal.name + or vim.api.nvim_buf_get_name(buf) + if type(name) == 'function' then + name = name(buf) + end + local name_hl = configs.opts.sources.terminal.name_hl or 'Keyword' + if type(name_hl) == 'function' then + name_hl = name_hl(buf) + end + + return { + icon = icon, + icon_hl = icon_hl, + name = name, + name_hl = name_hl, + } +end + +---@param sym dropbar_symbol_t +---@return dropbar_menu_entry_t[] +local function get_menu_entries(sym) + return vim + .iter(vim.api.nvim_list_bufs()) + :filter(function(buf) + return vim.bo[buf].buftype == 'terminal' + and (buf ~= sym.bar.buf or configs.opts.sources.terminal.show_current) + end) + :map(function(buf) + local entry = buf_info(buf) + entry.on_click = function() + vim.api.nvim_win_set_buf(sym.bar.win, buf) + sym.menu:close(true) + end + return require('dropbar.menu').dropbar_menu_entry_t:new({ + components = { + require('dropbar.bar').dropbar_symbol_t:new(entry), + }, + }) + end) + :totable() +end + +local function get_symbols(buf, win) + if not initialized then + init() + end + + local symbol = buf_info(buf) + symbol.on_click = function(self) + local entries = get_menu_entries(self) + if #entries > 0 then + self.menu = require('dropbar.menu').dropbar_menu_t:new({ + entries = entries, + prev_win = self.bar.win, + }) + self.menu:open({ + win_configs = { + win = win, + col = function(menu) + if menu.prev_menu then + return menu.prev_menu._win_configs.width + end + local mouse = vim.fn.getmousepos() + local bar = require('dropbar.api').get_dropbar( + vim.api.nvim_win_get_buf(menu.prev_win), + menu.prev_win + ) + if not bar then + return 0 + end + local _, range = + bar:get_component_at(math.max(0, mouse.wincol - 1)) + return range and range.start or 0 + end, + }, + }) + end + end + + return { + require('dropbar.bar').dropbar_symbol_t:new(symbol), + } +end + +return { get_symbols = get_symbols }