mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-20 16:15:43 +02:00
plugins/dropbar: init
This commit is contained in:
parent
592e9eaff0
commit
2054094544
3 changed files with 1446 additions and 0 deletions
51
plugins/by-name/dropbar/default.nix
Normal file
51
plugins/by-name/dropbar/default.nix
Normal file
|
@ -0,0 +1,51 @@
|
|||
{ lib, ... }:
|
||||
lib.nixvim.plugins.mkNeovimPlugin {
|
||||
name = "dropbar";
|
||||
packPathName = "dropbar.nvim";
|
||||
package = "dropbar-nvim";
|
||||
|
||||
maintainers = [ lib.maintainers.GaetanLepage ];
|
||||
|
||||
description = ''
|
||||
A polished, IDE-like, highly-customizable winbar for Neovim with drop-down menu support and
|
||||
multiple backends.
|
||||
'';
|
||||
|
||||
settingsOptions = import ./settings-options.nix lib;
|
||||
|
||||
settingsExample = {
|
||||
bar = {
|
||||
enable = true;
|
||||
sources.__raw = ''
|
||||
function(buf, _)
|
||||
local sources = require('dropbar.sources')
|
||||
return {
|
||||
require('dropbar.utils').source.fallback({
|
||||
sources.lsp,
|
||||
sources.treesitter,
|
||||
sources.markdown,
|
||||
})
|
||||
}
|
||||
end
|
||||
'';
|
||||
};
|
||||
menu.keymaps = {
|
||||
h = "<C-w>q";
|
||||
l.__raw = ''
|
||||
function()
|
||||
local dropbar = require('dropbar')
|
||||
local utils = require('dropbar.utils')
|
||||
local menu = utils.menu.get_current()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
local cursor = vim.api.nvim_win_get_cursor(menu.win)
|
||||
local component = menu.entries[cursor[1]]:first_clickable(cursor[2])
|
||||
if component then
|
||||
menu:click_on(component, nil, 1, 'l')
|
||||
end
|
||||
end
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
619
plugins/by-name/dropbar/settings-options.nix
Normal file
619
plugins/by-name/dropbar/settings-options.nix
Normal file
|
@ -0,0 +1,619 @@
|
|||
lib:
|
||||
let
|
||||
inherit (lib) types;
|
||||
inherit (lib.nixvim) defaultNullOpts literalLua mkNullOrOption;
|
||||
|
||||
mkPadding =
|
||||
defaultNullOpts.mkNullable
|
||||
(types.submodule {
|
||||
options = lib.genAttrs [ "left" "right" ] (
|
||||
side:
|
||||
lib.mkOption {
|
||||
type = types.ints.unsigned;
|
||||
description = "Padding for the ${side} side.";
|
||||
}
|
||||
);
|
||||
})
|
||||
{
|
||||
left = 1;
|
||||
right = 1;
|
||||
};
|
||||
in
|
||||
{
|
||||
bar = {
|
||||
enable =
|
||||
defaultNullOpts.mkBool
|
||||
(literalLua ''
|
||||
function(buf, win, _)
|
||||
if
|
||||
not vim.api.nvim_buf_is_valid(buf)
|
||||
or not vim.api.nvim_win_is_valid(win)
|
||||
or vim.fn.win_gettype(win) ~= ""
|
||||
or vim.wo[win].winbar ~= ""
|
||||
or vim.bo[buf].ft == 'help'
|
||||
then
|
||||
return false
|
||||
end
|
||||
|
||||
local stat = vim.uv.fs_stat(vim.api.nvim_buf_get_name(buf))
|
||||
if stat and stat.size > 1024 * 1024 then
|
||||
return false
|
||||
end
|
||||
|
||||
return vim.bo[buf].ft == 'markdown'
|
||||
or pcall(vim.treesitter.get_parser, buf)
|
||||
or not vim.tbl_isempty(vim.lsp.get_clients({
|
||||
bufnr = buf,
|
||||
method = 'textDocument/documentSymbol',
|
||||
}))
|
||||
end
|
||||
'')
|
||||
''
|
||||
Controls whether to enable the plugin for the current buffer and window.
|
||||
|
||||
If a function is provided, it will be called with the current `bufnr` and `winid` and
|
||||
should return a boolean.
|
||||
'';
|
||||
|
||||
attach_events =
|
||||
defaultNullOpts.mkListOf types.str
|
||||
[
|
||||
"OptionSet"
|
||||
"BufWinEnter"
|
||||
"BufWritePost"
|
||||
]
|
||||
''
|
||||
Controls when to evaluate the `enable()` function and attach the plugin to corresponding
|
||||
buffer or window.
|
||||
'';
|
||||
|
||||
update_debounce = defaultNullOpts.mkUnsignedInt 0 ''
|
||||
Wait for a short time before updating the winbar, if another update request is received within
|
||||
this time, the previous request will be cancelled.
|
||||
This improves the performance when the user is holding down a key (e.g. `'j'`) to scroll the
|
||||
window.
|
||||
|
||||
If you encounter performance issues when scrolling the window, try setting this option to a
|
||||
number slightly larger than `1000 / key_repeat_rate`.
|
||||
'';
|
||||
|
||||
update_events = {
|
||||
win =
|
||||
defaultNullOpts.mkListOf types.str
|
||||
[
|
||||
"CursorMoved"
|
||||
"WinEnter"
|
||||
"WinResized"
|
||||
]
|
||||
''
|
||||
List of events that should trigger an update on the dropbar attached to a single window.
|
||||
'';
|
||||
|
||||
buf =
|
||||
defaultNullOpts.mkListOf types.str
|
||||
[
|
||||
"BufModifiedSet"
|
||||
"FileChangedShellPost"
|
||||
"TextChanged"
|
||||
"ModeChanged"
|
||||
]
|
||||
''
|
||||
List of events that should trigger an update on all dropbars attached to a buffer.
|
||||
'';
|
||||
|
||||
global =
|
||||
defaultNullOpts.mkListOf types.str
|
||||
[
|
||||
"DirChanged"
|
||||
"VimResized"
|
||||
]
|
||||
''
|
||||
List of events that should trigger an update on all dropbars in the current nvim
|
||||
session.
|
||||
'';
|
||||
};
|
||||
|
||||
hover = defaultNullOpts.mkBool true ''
|
||||
Whether to highlight the symbol under the cursor.
|
||||
|
||||
This feature requires 'mousemoveevent' to be enabled.
|
||||
'';
|
||||
|
||||
sources =
|
||||
defaultNullOpts.mkListOf
|
||||
(types.submodule {
|
||||
freeformType = with types; attrsOf anything;
|
||||
|
||||
options = {
|
||||
get_symbols = mkNullOrOption types.rawLua ''
|
||||
```lua
|
||||
fun(buf: integer, win: integer, cursor: integer[]): dropbar_symbol_t[]
|
||||
```
|
||||
'';
|
||||
};
|
||||
})
|
||||
(literalLua ''
|
||||
function(buf, _)
|
||||
local sources = require('dropbar.sources')
|
||||
local utils = require('dropbar.utils')
|
||||
if vim.bo[buf].ft == 'markdown' then
|
||||
return {
|
||||
sources.path,
|
||||
sources.markdown,
|
||||
}
|
||||
end
|
||||
if vim.bo[buf].buftype == 'terminal' then
|
||||
return {
|
||||
sources.terminal,
|
||||
}
|
||||
end
|
||||
return {
|
||||
sources.path,
|
||||
utils.source.fallback({
|
||||
sources.lsp,
|
||||
sources.treesitter,
|
||||
}),
|
||||
}
|
||||
end
|
||||
'')
|
||||
''
|
||||
List of sources to show in the winbar.
|
||||
|
||||
If a function is provided, it will be called with the current `bufnr` and `winid` and
|
||||
should return a list of sources.
|
||||
|
||||
For more information about sources, see `|dropbar-developers-classes-dropbar_source_t|`.
|
||||
'';
|
||||
|
||||
padding = mkPadding ''
|
||||
Padding to use between the winbar and the window border.
|
||||
'';
|
||||
|
||||
pick = {
|
||||
pivots = defaultNullOpts.mkStr "abcdefghijklmnopqrstuvwxyz" ''
|
||||
Pivots to use in pick mode.
|
||||
'';
|
||||
};
|
||||
|
||||
truncate = defaultNullOpts.mkBool true ''
|
||||
Whether to truncate the winbar if it doesn’t fit in the window.
|
||||
'';
|
||||
};
|
||||
|
||||
menu = {
|
||||
quick_navigation = defaultNullOpts.mkBool true ''
|
||||
When on, automatically set the cursor to the closest previous/next clickable component in the
|
||||
direction of cursor movement on `|CursorMoved|`.
|
||||
'';
|
||||
|
||||
entry = {
|
||||
padding = mkPadding ''
|
||||
Padding to use between the menu entry and the menu border.
|
||||
'';
|
||||
};
|
||||
|
||||
preview = defaultNullOpts.mkBool true ''
|
||||
Whether to enable previewing for menu entries.
|
||||
'';
|
||||
|
||||
keymaps = mkNullOrOption (with types; attrsOf (either str (attrsOf (maybeRaw str)))) ''
|
||||
Buffer-local keymaps in the menu.
|
||||
|
||||
Use `<key> = <function|string>` to map a key in normal mode in the menu buffer, or use
|
||||
`<key> = table<mode, function|string>` to map a key in specific modes.
|
||||
|
||||
See `:h dropbar-configuration-options-menu` for the default value.
|
||||
'';
|
||||
|
||||
scrollbar =
|
||||
defaultNullOpts.mkAttrsOf types.bool
|
||||
{
|
||||
enable = true;
|
||||
background = true;
|
||||
}
|
||||
''
|
||||
Scrollbar configuration for the menu.
|
||||
'';
|
||||
|
||||
win_configs = mkNullOrOption (with types; attrsOf anything) ''
|
||||
Window configurations for the menu, see `:h nvim_open_win()`.
|
||||
|
||||
Each config key in `menu.win_configs` accepts either a plain value which will be passed
|
||||
directly to `nvim_open_win()`, or a function that takes the current `menu` (see
|
||||
`|dropbar-developers-classes-dropbar_menu_t|`) as an argument and returns a value to be
|
||||
passed to `nvim_open_win()`.
|
||||
|
||||
See `:h dropbar-configuration-options-menu` for the default value.
|
||||
'';
|
||||
};
|
||||
|
||||
fzf = {
|
||||
keymaps = mkNullOrOption (with types; attrsOf (maybeRaw str)) ''
|
||||
The keymaps that will apply in insert mode, in the fzf prompt buffer.
|
||||
|
||||
See `:h dropbar-configuration-options-fzf` for the default value.
|
||||
'';
|
||||
|
||||
win_configs = mkNullOrOption (with types; attrsOf anything) ''
|
||||
Options passed to `:h nvim_open_win`.
|
||||
|
||||
The fuzzy finder will use its parent window's config by default, but options set here will
|
||||
override those.
|
||||
Same config as `menu.win_configs`
|
||||
|
||||
See `:h dropbar-configuration-options-fzf` for the default value.
|
||||
'';
|
||||
|
||||
prompt = defaultNullOpts.mkStr "%#htmlTag# " ''
|
||||
Prompt string that will be displayed in the `statuscolumn` of the fzf input window.
|
||||
|
||||
Can include highlight groups
|
||||
'';
|
||||
|
||||
char_pattern = defaultNullOpts.mkStr "[%w%p]" ''
|
||||
Character pattern.
|
||||
'';
|
||||
|
||||
retain_inner_spaces = defaultNullOpts.mkBool true ''
|
||||
Whether to retain inner spaces.
|
||||
'';
|
||||
|
||||
fuzzy_find_on_click = defaultNullOpts.mkBool true ''
|
||||
When opening an entry with a submenu via the fuzzy finder, open the submenu in fuzzy finder
|
||||
mode.
|
||||
'';
|
||||
};
|
||||
|
||||
icons = {
|
||||
enable = defaultNullOpts.mkBool true ''
|
||||
Whether to enable icons.
|
||||
'';
|
||||
|
||||
kinds = {
|
||||
dir_icon =
|
||||
defaultNullOpts.mkStr
|
||||
(literalLua ''
|
||||
function(_)
|
||||
return M.opts.icons.kinds.symbols.Folder, 'DropBarIconKindFolder'
|
||||
end
|
||||
'')
|
||||
''
|
||||
Directory icon and highlighting getter, set to empty string to disable.
|
||||
'';
|
||||
|
||||
file_icon =
|
||||
defaultNullOpts.mkStr
|
||||
(literalLua ''
|
||||
function(path)
|
||||
return M.opts.icons.kinds.symbols.File, 'DropBarIconKindFile'
|
||||
end
|
||||
'')
|
||||
''
|
||||
File icon and highlighting getter, set to empty string to disable.
|
||||
'';
|
||||
|
||||
symbols = mkNullOrOption (with types; attrsOf str) ''
|
||||
Table mapping the different kinds of symbols to their corresponding icons.
|
||||
|
||||
See `:h dropbar-configuration-options-icons` for the default value.
|
||||
'';
|
||||
};
|
||||
|
||||
ui = {
|
||||
bar =
|
||||
defaultNullOpts.mkAttrsOf types.str
|
||||
{
|
||||
separator = " ";
|
||||
extends = "…";
|
||||
}
|
||||
''
|
||||
Controls the icons used in the winbar UI.
|
||||
'';
|
||||
|
||||
menu =
|
||||
defaultNullOpts.mkAttrsOf types.str
|
||||
{
|
||||
separator = " ";
|
||||
indicator = " ";
|
||||
}
|
||||
''
|
||||
Controls the icons used in the menu UI.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
symbol = {
|
||||
on_click = mkNullOrOption (with types; maybeRaw (enum [ false ])) ''
|
||||
function called when clicking or pressing `<CR>` on the symbol.
|
||||
|
||||
See `:h dropbar-configuration-options-symbol` for the default value.
|
||||
'';
|
||||
|
||||
preview = {
|
||||
reorient =
|
||||
defaultNullOpts.mkRaw
|
||||
''
|
||||
function(_, range)
|
||||
local invisible = range['end'].line - vim.fn.line('w$') + 1
|
||||
if invisible > 0 then
|
||||
local view = vim.fn.winsaveview() --[[@as vim.fn.winrestview.dict]]
|
||||
view.topline = math.min(
|
||||
view.topline + invisible,
|
||||
math.max(1, range.start.line - vim.wo.scrolloff + 1)
|
||||
)
|
||||
vim.fn.winrestview(view)
|
||||
end
|
||||
end
|
||||
''
|
||||
''
|
||||
Function to reorient the source window when previewing symbol given the source window
|
||||
`win` and the range of the symbol `range`.
|
||||
'';
|
||||
};
|
||||
|
||||
jump = {
|
||||
reorient =
|
||||
defaultNullOpts.mkRaw
|
||||
''
|
||||
function(win, range)
|
||||
local view = vim.fn.winsaveview()
|
||||
local win_height = vim.api.nvim_win_get_height(win)
|
||||
local topline = range.start.line - math.floor(win_height / 4)
|
||||
if
|
||||
topline > view.topline
|
||||
and topline + win_height < vim.fn.line('$')
|
||||
then
|
||||
view.topline = topline
|
||||
vim.fn.winrestview(view)
|
||||
end
|
||||
end
|
||||
''
|
||||
''
|
||||
Function to reorient the source window when jumping to symbol given the source window
|
||||
`win` and the range of the symbol `range`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
sources = {
|
||||
path = {
|
||||
max_depth = defaultNullOpts.mkUnsignedInt 16 ''
|
||||
Maximum number of symbols to return.
|
||||
|
||||
A smaller number can help to improve performance in deeply nested paths.
|
||||
'';
|
||||
|
||||
relative_to =
|
||||
defaultNullOpts.mkStr
|
||||
(literalLua ''
|
||||
function(_, win)
|
||||
-- Workaround for Vim:E5002: Cannot find window number
|
||||
local ok, cwd = pcall(vim.fn.getcwd, win)
|
||||
return ok and cwd or vim.fn.getcwd()
|
||||
end
|
||||
'')
|
||||
''
|
||||
The path to use as the root of the relative path.
|
||||
|
||||
If a function is provided, it will be called with the current buffer number and window
|
||||
id as arguments and should return a string to be used as the root of the relative path.
|
||||
|
||||
Notice: currently does not support `..` relative paths.
|
||||
'';
|
||||
|
||||
path_filter = defaultNullOpts.mkRaw "function(_) return true end" ''
|
||||
A function that takes a file name and returns whether to include it in the results shown in
|
||||
the drop-down menu.
|
||||
'';
|
||||
|
||||
modified = defaultNullOpts.mkRaw "function(sym) return sym end" ''
|
||||
A function that takes the last symbol in the result got from the path source and returns an
|
||||
alternative symbol to show if the current buffer is modified.
|
||||
|
||||
For information about dropbar symbols, see `|dropbar-developers-classes-dropbar_symbol_t|`.
|
||||
|
||||
To set a different icon, name, or highlights when the buffer is modified, you can change the
|
||||
corresponding fields in the returned symbol:
|
||||
|
||||
```lua
|
||||
function(sym)
|
||||
return sym:merge({
|
||||
name = sym.name .. ' [+]',
|
||||
icon = ' ',
|
||||
name_hl = 'DiffAdded',
|
||||
icon_hl = 'DiffAdded',
|
||||
-- ...
|
||||
})
|
||||
end
|
||||
```
|
||||
'';
|
||||
|
||||
preview =
|
||||
defaultNullOpts.mkBool
|
||||
(literalLua ''
|
||||
function(path)
|
||||
local stat = vim.uv.fs_stat(path)
|
||||
if not stat or stat.type ~= 'file' then
|
||||
return false
|
||||
end
|
||||
if stat.size > 524288 then
|
||||
vim.notify(
|
||||
string.format(
|
||||
'[dropbar.nvim] file "%s" too large to preview',
|
||||
path
|
||||
),
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
'')
|
||||
''
|
||||
A boolean or a function that takes a file path and returns whether to preview the file
|
||||
under cursor.
|
||||
'';
|
||||
};
|
||||
|
||||
treesitter = {
|
||||
max_depth = defaultNullOpts.mkUnsignedInt 16 ''
|
||||
Maximum number of symbols to return.
|
||||
|
||||
A smaller number can help to improve performance in deeply nested trees (e.g. in big nested
|
||||
json files).
|
||||
'';
|
||||
|
||||
name_regex = defaultNullOpts.mkStr "[=[[#~!@\*&.]*[[:keyword:]]\+!\?\(\(\(->\)\+\|-\+\|\.\+\|:\+\|\s\+\)\?[#~!@\*&.]*[[:keyword:]]\+!\?\)*]=]" ''
|
||||
Vim regex used to extract a short name from the node text.
|
||||
'';
|
||||
|
||||
valid_types =
|
||||
defaultNullOpts.mkListOf types.str
|
||||
[
|
||||
"array"
|
||||
"boolean"
|
||||
"break_statement"
|
||||
"call"
|
||||
"case_statement"
|
||||
"class"
|
||||
"constant"
|
||||
"constructor"
|
||||
"continue_statement"
|
||||
"delete"
|
||||
"do_statement"
|
||||
"element"
|
||||
"enum"
|
||||
"enum_member"
|
||||
"event"
|
||||
"for_statement"
|
||||
"function"
|
||||
"h1_marker"
|
||||
"h2_marker"
|
||||
"h3_marker"
|
||||
"h4_marker"
|
||||
"h5_marker"
|
||||
"h6_marker"
|
||||
"if_statement"
|
||||
"interface"
|
||||
"keyword"
|
||||
"macro"
|
||||
"method"
|
||||
"module"
|
||||
"namespace"
|
||||
"null"
|
||||
"number"
|
||||
"operator"
|
||||
"package"
|
||||
"pair"
|
||||
"property"
|
||||
"reference"
|
||||
"repeat"
|
||||
"rule_set"
|
||||
"scope"
|
||||
"specifier"
|
||||
"struct"
|
||||
"switch_statement"
|
||||
"type"
|
||||
"type_parameter"
|
||||
"unit"
|
||||
"value"
|
||||
"variable"
|
||||
"while_statement"
|
||||
"declaration"
|
||||
"field"
|
||||
"identifier"
|
||||
"object"
|
||||
"statement"
|
||||
]
|
||||
''
|
||||
A list of treesitter node types to include in the results.
|
||||
'';
|
||||
};
|
||||
|
||||
lsp = {
|
||||
max_depth = defaultNullOpts.mkUnsignedInt 16 ''
|
||||
Maximum number of symbols to return.
|
||||
|
||||
A smaller number can help to improve performance when the language server returns huge list
|
||||
of nested symbols.
|
||||
'';
|
||||
|
||||
valid_symbols =
|
||||
defaultNullOpts.mkListOf types.str
|
||||
[
|
||||
"File"
|
||||
"Module"
|
||||
"Namespace"
|
||||
"Package"
|
||||
"Class"
|
||||
"Method"
|
||||
"Property"
|
||||
"Field"
|
||||
"Constructor"
|
||||
"Enum"
|
||||
"Interface"
|
||||
"Function"
|
||||
"Variable"
|
||||
"Constant"
|
||||
"String"
|
||||
"Number"
|
||||
"Boolean"
|
||||
"Array"
|
||||
"Object"
|
||||
"Keyword"
|
||||
"Null"
|
||||
"EnumMember"
|
||||
"Struct"
|
||||
"Event"
|
||||
"Operator"
|
||||
"TypeParameter"
|
||||
]
|
||||
''
|
||||
A list of LSP document symbols to include in the results.
|
||||
'';
|
||||
|
||||
request = {
|
||||
ttl_init = defaultNullOpts.mkUnsignedInt 60 ''
|
||||
Number of times to retry a request before giving up.
|
||||
'';
|
||||
|
||||
interval = defaultNullOpts.mkUnsignedInt 1000 ''
|
||||
Number of milliseconds to wait between retries.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
markdown = {
|
||||
max_depth = defaultNullOpts.mkUnsignedInt 6 ''
|
||||
Maximum number of symbols to return.
|
||||
'';
|
||||
|
||||
parse = {
|
||||
look_ahead = defaultNullOpts.mkUnsignedInt 200 ''
|
||||
Number of lines to update when cursor moves out of the parsed range.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
terminal = {
|
||||
icon =
|
||||
defaultNullOpts.mkStr
|
||||
(literalLua ''
|
||||
function(_)
|
||||
return M.opts.icons.kinds.symbols.Terminal or ' '
|
||||
end
|
||||
'')
|
||||
''
|
||||
Icon to show before terminal names.
|
||||
'';
|
||||
|
||||
name = defaultNullOpts.mkStr (literalLua "vim.api.nvim_buf_get_name") ''
|
||||
Name for the current terminal buffer.
|
||||
'';
|
||||
|
||||
show_current = defaultNullOpts.mkBool true ''
|
||||
Show the current terminal buffer in the menu.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
776
tests/test-sources/plugins/by-name/dropbar/default.nix
Normal file
776
tests/test-sources/plugins/by-name/dropbar/default.nix
Normal file
|
@ -0,0 +1,776 @@
|
|||
{
|
||||
empty = {
|
||||
plugins.dropbar.enable = true;
|
||||
};
|
||||
|
||||
example = {
|
||||
plugins.dropbar = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
bar = {
|
||||
enable = true;
|
||||
sources.__raw = ''
|
||||
function(buf, _)
|
||||
local sources = require('dropbar.sources')
|
||||
return {
|
||||
require('dropbar.utils').source.fallback({
|
||||
sources.lsp,
|
||||
sources.treesitter,
|
||||
sources.markdown,
|
||||
})
|
||||
}
|
||||
end
|
||||
'';
|
||||
};
|
||||
menu.keymaps = {
|
||||
h = "<C-w>q";
|
||||
l.__raw = ''
|
||||
function()
|
||||
local dropbar = require('dropbar')
|
||||
local utils = require('dropbar.utils')
|
||||
local menu = utils.menu.get_current()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
local cursor = vim.api.nvim_win_get_cursor(menu.win)
|
||||
local component = menu.entries[cursor[1]]:first_clickable(cursor[2])
|
||||
if component then
|
||||
menu:click_on(component, nil, 1, 'l')
|
||||
end
|
||||
end
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
defaults = {
|
||||
plugins.dropbar = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
bar = {
|
||||
enable.__raw = ''
|
||||
function(buf, win, _)
|
||||
if
|
||||
not vim.api.nvim_buf_is_valid(buf)
|
||||
or not vim.api.nvim_win_is_valid(win)
|
||||
or vim.fn.win_gettype(win) ~= ""
|
||||
or vim.wo[win].winbar ~= ""
|
||||
or vim.bo[buf].ft == 'help'
|
||||
then
|
||||
return false
|
||||
end
|
||||
|
||||
local stat = vim.uv.fs_stat(vim.api.nvim_buf_get_name(buf))
|
||||
if stat and stat.size > 1024 * 1024 then
|
||||
return false
|
||||
end
|
||||
|
||||
return vim.bo[buf].ft == 'markdown'
|
||||
or pcall(vim.treesitter.get_parser, buf)
|
||||
or not vim.tbl_isempty(vim.lsp.get_clients({
|
||||
bufnr = buf,
|
||||
method = 'textDocument/documentSymbol',
|
||||
}))
|
||||
end
|
||||
'';
|
||||
attach_events = [
|
||||
"OptionSet"
|
||||
"BufWinEnter"
|
||||
"BufWritePost"
|
||||
];
|
||||
update_debounce = 0;
|
||||
update_events = {
|
||||
win = [
|
||||
"CursorMoved"
|
||||
"WinEnter"
|
||||
"WinResized"
|
||||
];
|
||||
buf = [
|
||||
"BufModifiedSet"
|
||||
"FileChangedShellPost"
|
||||
"TextChanged"
|
||||
"ModeChanged"
|
||||
];
|
||||
global = [
|
||||
"DirChanged"
|
||||
"VimResized"
|
||||
];
|
||||
};
|
||||
hover = true;
|
||||
sources.__raw = ''
|
||||
function(buf, _)
|
||||
local sources = require('dropbar.sources')
|
||||
local utils = require('dropbar.utils')
|
||||
if vim.bo[buf].ft == 'markdown' then
|
||||
return {
|
||||
sources.path,
|
||||
sources.markdown,
|
||||
}
|
||||
end
|
||||
if vim.bo[buf].buftype == 'terminal' then
|
||||
return {
|
||||
sources.terminal,
|
||||
}
|
||||
end
|
||||
return {
|
||||
sources.path,
|
||||
utils.source.fallback({
|
||||
sources.lsp,
|
||||
sources.treesitter,
|
||||
}),
|
||||
}
|
||||
end
|
||||
'';
|
||||
padding = {
|
||||
left = 1;
|
||||
right = 1;
|
||||
};
|
||||
pick = {
|
||||
pivots = "abcdefghijklmnopqrstuvwxyz";
|
||||
};
|
||||
truncate = true;
|
||||
};
|
||||
menu = {
|
||||
quick_navigation = true;
|
||||
entry = {
|
||||
padding = {
|
||||
left = 1;
|
||||
right = 1;
|
||||
};
|
||||
};
|
||||
preview = true;
|
||||
keymaps = {
|
||||
q = "<C-w>q";
|
||||
"<Esc>" = "<C-w>q";
|
||||
"<LeftMouse>".__raw = ''
|
||||
function()
|
||||
local menu = utils.menu.get_current()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
local mouse = vim.fn.getmousepos()
|
||||
local clicked_menu = utils.menu.get({ win = mouse.winid })
|
||||
-- If clicked on a menu, invoke the corresponding click action,
|
||||
-- else close all menus and set the cursor to the clicked window
|
||||
if clicked_menu then
|
||||
clicked_menu:click_at({
|
||||
mouse.line,
|
||||
mouse.column - 1
|
||||
}, nil, 1, 'l')
|
||||
return
|
||||
end
|
||||
utils.menu.exec('close')
|
||||
utils.bar.exec('update_current_context_hl')
|
||||
if vim.api.nvim_win_is_valid(mouse.winid) then
|
||||
vim.api.nvim_set_current_win(mouse.winid)
|
||||
end
|
||||
end
|
||||
'';
|
||||
"<CR>".__raw = ''
|
||||
function()
|
||||
local menu = utils.menu.get_current()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
local cursor = vim.api.nvim_win_get_cursor(menu.win)
|
||||
local component = menu.entries[cursor[1]]:first_clickable(cursor[2])
|
||||
if component then
|
||||
menu:click_on(component, nil, 1, 'l')
|
||||
end
|
||||
end
|
||||
'';
|
||||
"<MouseMove>".__raw = ''
|
||||
function()
|
||||
local menu = utils.menu.get_current()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
local mouse = vim.fn.getmousepos()
|
||||
utils.menu.update_hover_hl(mouse)
|
||||
if M.opts.menu.preview then
|
||||
utils.menu.update_preview(mouse)
|
||||
end
|
||||
end
|
||||
'';
|
||||
i.__raw = ''
|
||||
function()
|
||||
local menu = utils.menu.get_current()
|
||||
if not menu then
|
||||
return
|
||||
end
|
||||
menu:fuzzy_find_open()
|
||||
end
|
||||
'';
|
||||
};
|
||||
scrollbar = {
|
||||
enable = true;
|
||||
background = true;
|
||||
};
|
||||
win_configs = {
|
||||
border = "none";
|
||||
style = "minimal";
|
||||
row.__raw = ''
|
||||
function(menu)
|
||||
return menu.prev_menu
|
||||
and menu.prev_menu.clicked_at
|
||||
and menu.prev_menu.clicked_at[1] - vim.fn.line('w')
|
||||
or 0
|
||||
end
|
||||
'';
|
||||
col.__raw = ''
|
||||
---@param menu dropbar_menu_t
|
||||
function(menu)
|
||||
if menu.prev_menu then
|
||||
return menu.prev_menu._win_configs.width
|
||||
+ (menu.prev_menu.scrollbar and 1 or 0)
|
||||
end
|
||||
local mouse = vim.fn.getmousepos()
|
||||
local bar = utils.bar.get({ win = menu.prev_win })
|
||||
if not bar then
|
||||
return mouse.wincol
|
||||
end
|
||||
local _, range = bar:get_component_at(math.max(0, mouse.wincol - 1))
|
||||
return range and range.start or mouse.wincol
|
||||
end
|
||||
'';
|
||||
relative = "win";
|
||||
win.__raw = ''
|
||||
function(menu)
|
||||
return menu.prev_menu and menu.prev_menu.win
|
||||
or vim.fn.getmousepos().winid
|
||||
end
|
||||
'';
|
||||
height.__raw = ''
|
||||
function(menu)
|
||||
return math.max(
|
||||
1,
|
||||
math.min(
|
||||
#menu.entries,
|
||||
vim.go.pumheight ~= 0 and vim.go.pumheight
|
||||
or math.ceil(vim.go.lines / 4)
|
||||
)
|
||||
)
|
||||
end
|
||||
'';
|
||||
width.__raw = ''
|
||||
function(menu)
|
||||
local min_width = vim.go.pumwidth ~= 0 and vim.go.pumwidth or 8
|
||||
if vim.tbl_isempty(menu.entries) then
|
||||
return min_width
|
||||
end
|
||||
return math.max(
|
||||
min_width,
|
||||
math.max(unpack(vim.tbl_map(function(entry)
|
||||
return entry:displaywidth()
|
||||
end, menu.entries)))
|
||||
)
|
||||
end
|
||||
'';
|
||||
zindex.__raw = ''
|
||||
function(menu)
|
||||
if menu.prev_menu then
|
||||
if menu.prev_menu.scrollbar and menu.prev_menu.scrollbar.thumb then
|
||||
return vim.api.nvim_win_get_config(menu.prev_menu.scrollbar.thumb).zindex
|
||||
end
|
||||
return vim.api.nvim_win_get_config(menu.prev_win).zindex
|
||||
end
|
||||
end
|
||||
'';
|
||||
};
|
||||
};
|
||||
fzf = {
|
||||
keymaps = {
|
||||
# TODO
|
||||
};
|
||||
win_configs = {
|
||||
relative = "win";
|
||||
anchor = "NW";
|
||||
height = 1;
|
||||
win.__raw = ''
|
||||
function(menu)
|
||||
return menu.win
|
||||
end
|
||||
'';
|
||||
width.__raw = ''
|
||||
function(menu)
|
||||
local function border_width(border)
|
||||
if type(border) == 'string' then
|
||||
if border == 'none' or border == 'shadow' then
|
||||
return 0
|
||||
end
|
||||
return 2 -- left and right border
|
||||
end
|
||||
|
||||
local left, right = 1, 1
|
||||
if
|
||||
(#border == 1 and border[1] == "")
|
||||
or (#border == 4 and border[4] == "")
|
||||
or (#border == 8 and border[8] == "")
|
||||
then
|
||||
left = 0
|
||||
end
|
||||
if
|
||||
(#border == 1 and border[1] == "")
|
||||
or (#border == 4 and border[4] == "")
|
||||
or (#border == 8 and border[4] == "")
|
||||
then
|
||||
right = 0
|
||||
end
|
||||
return left + right
|
||||
end
|
||||
local menu_width = menu._win_configs.width
|
||||
+ border_width(menu._win_configs.border)
|
||||
local self_width = menu._win_configs.width
|
||||
local self_border = border_width(
|
||||
(
|
||||
M.opts.fzf.win_configs
|
||||
and M.eval(M.opts.fzf.win_configs.border, menu)
|
||||
)
|
||||
or (menu.fzf_win_configs and M.eval(
|
||||
menu.fzf_win_configs.border,
|
||||
menu
|
||||
))
|
||||
or menu._win_configs.border
|
||||
)
|
||||
|
||||
if self_width + self_border > menu_width then
|
||||
return self_width - self_border
|
||||
else
|
||||
return menu_width - self_border
|
||||
end
|
||||
end
|
||||
'';
|
||||
row.__raw = ''
|
||||
function(menu)
|
||||
local menu_border = menu._win_configs.border
|
||||
if
|
||||
type(menu_border) == 'string'
|
||||
and menu_border ~= 'shadow'
|
||||
and menu_border ~= 'none'
|
||||
then
|
||||
return menu._win_configs.height + 1
|
||||
elseif menu_border == 'none' then
|
||||
return menu._win_configs.height
|
||||
end
|
||||
local len_menu_border = #menu_border
|
||||
if
|
||||
len_menu_border == 1 and menu_border[1] ~= ""
|
||||
or (len_menu_border == 2 or len_menu_border == 4) and menu_border[2] ~= ""
|
||||
or len_menu_border == 8 and menu_border[8] ~= ""
|
||||
then
|
||||
return menu._win_configs.height + 1
|
||||
else
|
||||
return menu._win_configs.height
|
||||
end
|
||||
end
|
||||
'';
|
||||
col.__raw = ''
|
||||
function(menu)
|
||||
local menu_border = menu._win_configs.border
|
||||
if
|
||||
type(menu_border) == 'string'
|
||||
and menu_border ~= 'shadow'
|
||||
and menu_border ~= 'none'
|
||||
then
|
||||
return -1
|
||||
end
|
||||
if
|
||||
type(menu_border) == 'table' and menu_border[#menu_border] ~= ""
|
||||
then
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
'';
|
||||
};
|
||||
prompt = "%#htmlTag# ";
|
||||
char_pattern = "[%w%p]";
|
||||
retain_inner_spaces = true;
|
||||
fuzzy_find_on_click = true;
|
||||
};
|
||||
icons = {
|
||||
enable = true;
|
||||
kinds = {
|
||||
dir_icon.__raw = ''
|
||||
function(_)
|
||||
return M.opts.icons.kinds.symbols.Folder, 'DropBarIconKindFolder'
|
||||
end
|
||||
'';
|
||||
file_icon.__raw = ''
|
||||
function(path)
|
||||
return M.opts.icons.kinds.symbols.File, 'DropBarIconKindFile'
|
||||
end
|
||||
'';
|
||||
symbols = {
|
||||
Array = " ";
|
||||
Boolean = " ";
|
||||
BreakStatement = " ";
|
||||
Call = " ";
|
||||
CaseStatement = " ";
|
||||
Class = " ";
|
||||
Color = " ";
|
||||
Constant = " ";
|
||||
Constructor = " ";
|
||||
ContinueStatement = "→ ";
|
||||
Copilot = " ";
|
||||
Declaration = " ";
|
||||
Delete = " ";
|
||||
DoStatement = " ";
|
||||
Element = " ";
|
||||
Enum = " ";
|
||||
EnumMember = " ";
|
||||
Event = " ";
|
||||
Field = " ";
|
||||
File = " ";
|
||||
Folder = " ";
|
||||
ForStatement = " ";
|
||||
Function = " ";
|
||||
H1Marker = " ";
|
||||
H2Marker = " ";
|
||||
H3Marker = " ";
|
||||
H4Marker = " ";
|
||||
H5Marker = " ";
|
||||
H6Marker = " ";
|
||||
Identifier = " ";
|
||||
IfStatement = " ";
|
||||
Interface = " ";
|
||||
Keyword = " ";
|
||||
List = " ";
|
||||
Log = " ";
|
||||
Lsp = " ";
|
||||
Macro = " ";
|
||||
MarkdownH1 = " ";
|
||||
MarkdownH2 = " ";
|
||||
MarkdownH3 = " ";
|
||||
MarkdownH4 = " ";
|
||||
MarkdownH5 = " ";
|
||||
MarkdownH6 = " ";
|
||||
Method = " ";
|
||||
Module = " ";
|
||||
Namespace = " ";
|
||||
Null = " ";
|
||||
Number = " ";
|
||||
Object = " ";
|
||||
Operator = " ";
|
||||
Package = " ";
|
||||
Pair = " ";
|
||||
Property = " ";
|
||||
Reference = " ";
|
||||
Regex = " ";
|
||||
Repeat = " ";
|
||||
RuleSet = " ";
|
||||
Scope = " ";
|
||||
Snippet = " ";
|
||||
Specifier = " ";
|
||||
Statement = " ";
|
||||
String = " ";
|
||||
Struct = " ";
|
||||
SwitchStatement = " ";
|
||||
Terminal = " ";
|
||||
Text = " ";
|
||||
Type = " ";
|
||||
TypeParameter = " ";
|
||||
Unit = " ";
|
||||
Value = " ";
|
||||
Variable = " ";
|
||||
WhileStatement = " ";
|
||||
};
|
||||
};
|
||||
ui = {
|
||||
bar = {
|
||||
separator = " ";
|
||||
extends = "…";
|
||||
};
|
||||
menu = {
|
||||
separator = " ";
|
||||
indicator = " ";
|
||||
};
|
||||
};
|
||||
};
|
||||
symbol = {
|
||||
on_click.__raw = ''
|
||||
function(symbol)
|
||||
-- Update current context highlights if the symbol
|
||||
-- is shown inside a menu
|
||||
if symbol.entry and symbol.entry.menu then
|
||||
symbol.entry.menu:update_current_context_hl(symbol.entry.idx)
|
||||
elseif symbol.bar then
|
||||
symbol.bar:update_current_context_hl(symbol.bar_idx)
|
||||
end
|
||||
|
||||
-- Determine menu configs
|
||||
local prev_win = nil ---@type integer?
|
||||
local entries_source = nil ---@type dropbar_symbol_t[]?
|
||||
local init_cursor = nil ---@type integer[]?
|
||||
local win_configs = {}
|
||||
if symbol.bar then -- If symbol inside a dropbar
|
||||
prev_win = symbol.bar.win
|
||||
entries_source = symbol.opts.siblings
|
||||
init_cursor = symbol.opts.sibling_idx
|
||||
and { symbol.opts.sibling_idx, 0 }
|
||||
if symbol.bar.in_pick_mode then
|
||||
---@param tbl number[]
|
||||
local function tbl_sum(tbl)
|
||||
local sum = 0
|
||||
for _, v in ipairs(tbl) do
|
||||
sum = sum + v
|
||||
end
|
||||
return sum
|
||||
end
|
||||
win_configs.relative = 'win'
|
||||
win_configs.win = vim.api.nvim_get_current_win()
|
||||
win_configs.row = 0
|
||||
win_configs.col = symbol.bar.padding.left
|
||||
+ tbl_sum(vim.tbl_map(
|
||||
function(component)
|
||||
return component:displaywidth()
|
||||
+ symbol.bar.separator:displaywidth()
|
||||
end,
|
||||
vim.tbl_filter(function(component)
|
||||
return component.bar_idx < symbol.bar_idx
|
||||
end, symbol.bar.components)
|
||||
))
|
||||
end
|
||||
elseif symbol.entry and symbol.entry.menu then -- If inside a menu
|
||||
prev_win = symbol.entry.menu.win
|
||||
entries_source = symbol.opts.children
|
||||
end
|
||||
|
||||
-- Toggle existing menu
|
||||
if symbol.menu then
|
||||
symbol.menu:toggle({
|
||||
prev_win = prev_win,
|
||||
win_configs = win_configs,
|
||||
})
|
||||
return
|
||||
end
|
||||
|
||||
-- Create a new menu for the symbol
|
||||
if not entries_source or vim.tbl_isempty(entries_source) then
|
||||
return
|
||||
end
|
||||
|
||||
local menu = require('dropbar.menu')
|
||||
local configs = require('dropbar.configs')
|
||||
symbol.menu = menu.dropbar_menu_t:new({
|
||||
prev_win = prev_win,
|
||||
cursor = init_cursor,
|
||||
win_configs = win_configs,
|
||||
---@param sym dropbar_symbol_t
|
||||
entries = vim.tbl_map(function(sym)
|
||||
local menu_indicator_icon = configs.opts.icons.ui.menu.indicator
|
||||
local menu_indicator_on_click = nil
|
||||
if not sym.children or vim.tbl_isempty(sym.children) then
|
||||
menu_indicator_icon =
|
||||
string.rep(' ', vim.fn.strdisplaywidth(menu_indicator_icon))
|
||||
menu_indicator_on_click = false
|
||||
end
|
||||
return menu.dropbar_menu_entry_t:new({
|
||||
components = {
|
||||
sym:merge({
|
||||
name = "",
|
||||
icon = menu_indicator_icon,
|
||||
icon_hl = 'dropbarIconUIIndicator',
|
||||
on_click = menu_indicator_on_click,
|
||||
}),
|
||||
sym:merge({
|
||||
on_click = function()
|
||||
local current_menu = symbol.menu
|
||||
while current_menu and current_menu.prev_menu do
|
||||
current_menu = current_menu.prev_menu
|
||||
end
|
||||
if current_menu then
|
||||
current_menu:close(false)
|
||||
end
|
||||
sym:jump()
|
||||
end,
|
||||
}),
|
||||
},
|
||||
})
|
||||
end, entries_source),
|
||||
})
|
||||
symbol.menu:toggle()
|
||||
end
|
||||
'';
|
||||
preview = {
|
||||
reorient.__raw = ''
|
||||
function(_, range)
|
||||
local invisible = range['end'].line - vim.fn.line('w$') + 1
|
||||
if invisible > 0 then
|
||||
local view = vim.fn.winsaveview() --[[@as vim.fn.winrestview.dict]]
|
||||
view.topline = math.min(
|
||||
view.topline + invisible,
|
||||
math.max(1, range.start.line - vim.wo.scrolloff + 1)
|
||||
)
|
||||
vim.fn.winrestview(view)
|
||||
end
|
||||
end
|
||||
'';
|
||||
};
|
||||
jump = {
|
||||
reorient.__raw = ''
|
||||
function(win, range)
|
||||
local view = vim.fn.winsaveview()
|
||||
local win_height = vim.api.nvim_win_get_height(win)
|
||||
local topline = range.start.line - math.floor(win_height / 4)
|
||||
if
|
||||
topline > view.topline
|
||||
and topline + win_height < vim.fn.line('$')
|
||||
then
|
||||
view.topline = topline
|
||||
vim.fn.winrestview(view)
|
||||
end
|
||||
end
|
||||
'';
|
||||
};
|
||||
};
|
||||
sources = {
|
||||
path = {
|
||||
max_depth = 16;
|
||||
relative_to.__raw = ''
|
||||
function(_, win)
|
||||
-- Workaround for Vim:E5002: Cannot find window number
|
||||
local ok, cwd = pcall(vim.fn.getcwd, win)
|
||||
return ok and cwd or vim.fn.getcwd()
|
||||
end
|
||||
'';
|
||||
path_filter.__raw = "function(_) return true end";
|
||||
modified.__raw = "function(sym) return sym end";
|
||||
preview.__raw = ''
|
||||
function(path)
|
||||
local stat = vim.uv.fs_stat(path)
|
||||
if not stat or stat.type ~= 'file' then
|
||||
return false
|
||||
end
|
||||
if stat.size > 524288 then
|
||||
vim.notify(
|
||||
string.format(
|
||||
'[dropbar.nvim] file "%s" too large to preview',
|
||||
path
|
||||
),
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
'';
|
||||
};
|
||||
treesitter = {
|
||||
max_depth = 16;
|
||||
name_regex = "[=[[#~!@\*&.]*[[:keyword:]]\+!\?\(\(\(->\)\+\|-\+\|\.\+\|:\+\|\s\+\)\?[#~!@\*&.]*[[:keyword:]]\+!\?\)*]=]";
|
||||
valid_types = [
|
||||
"array"
|
||||
"boolean"
|
||||
"break_statement"
|
||||
"call"
|
||||
"case_statement"
|
||||
"class"
|
||||
"constant"
|
||||
"constructor"
|
||||
"continue_statement"
|
||||
"delete"
|
||||
"do_statement"
|
||||
"element"
|
||||
"enum"
|
||||
"enum_member"
|
||||
"event"
|
||||
"for_statement"
|
||||
"function"
|
||||
"h1_marker"
|
||||
"h2_marker"
|
||||
"h3_marker"
|
||||
"h4_marker"
|
||||
"h5_marker"
|
||||
"h6_marker"
|
||||
"if_statement"
|
||||
"interface"
|
||||
"keyword"
|
||||
"macro"
|
||||
"method"
|
||||
"module"
|
||||
"namespace"
|
||||
"null"
|
||||
"number"
|
||||
"operator"
|
||||
"package"
|
||||
"pair"
|
||||
"property"
|
||||
"reference"
|
||||
"repeat"
|
||||
"rule_set"
|
||||
"scope"
|
||||
"specifier"
|
||||
"struct"
|
||||
"switch_statement"
|
||||
"type"
|
||||
"type_parameter"
|
||||
"unit"
|
||||
"value"
|
||||
"variable"
|
||||
"while_statement"
|
||||
"declaration"
|
||||
"field"
|
||||
"identifier"
|
||||
"object"
|
||||
"statement"
|
||||
];
|
||||
};
|
||||
lsp = {
|
||||
max_depth = 16;
|
||||
valid_symbols = [
|
||||
"File"
|
||||
"Module"
|
||||
"Namespace"
|
||||
"Package"
|
||||
"Class"
|
||||
"Method"
|
||||
"Property"
|
||||
"Field"
|
||||
"Constructor"
|
||||
"Enum"
|
||||
"Interface"
|
||||
"Function"
|
||||
"Variable"
|
||||
"Constant"
|
||||
"String"
|
||||
"Number"
|
||||
"Boolean"
|
||||
"Array"
|
||||
"Object"
|
||||
"Keyword"
|
||||
"Null"
|
||||
"EnumMember"
|
||||
"Struct"
|
||||
"Event"
|
||||
"Operator"
|
||||
"TypeParameter"
|
||||
];
|
||||
request = {
|
||||
ttl_init = 60;
|
||||
interval = 1000;
|
||||
};
|
||||
};
|
||||
markdown = {
|
||||
max_depth = 6;
|
||||
parse = {
|
||||
look_ahead = 200;
|
||||
};
|
||||
};
|
||||
terminal = {
|
||||
icon.__raw = ''
|
||||
function(_)
|
||||
return M.opts.icons.kinds.symbols.Terminal or ' '
|
||||
end
|
||||
'';
|
||||
name.__raw = "vim.api.nvim_buf_get_name";
|
||||
show_current = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue