Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use dropbar menu for ui.select (opt-in) #120

Merged
merged 3 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- [Utility Functions](#utility-functions)
- [Bar Utility Functions](#bar-utility-functions)
- [Menu Utility Functions](#menu-utility-functions)
- [Usage with `vim.ui.select`](#usage-with-vimuiselect)
- [Highlighting](#highlighting)
- [Developers](#developers)
- [Architecture](#architecture)
Expand All @@ -48,6 +49,7 @@
- [`dropbar_menu_entry_t`](#dropbar_menu_entry_t)
- [`dropbar_menu_hl_info_t`](#dropbar_menu_hl_info_t)
- [`dropbar_source_t`](#dropbar_source_t)
- [`dropbar_select_opts_t`](#dropbar_select_opts_t)
- [Making a New Source](#making-a-new-source)
- [Making a Source With Drop-Down Menus](#making-a-source-with-drop-down-menus)
- [Default `on_click()` Callback](#default-on_click-callback)
Expand Down Expand Up @@ -1602,6 +1604,19 @@ Defined in [`lua/dropbar/utils/menu.lua`](https://github.com/Bekaboo/dropbar.nvi
- If `opts.win` is not specified, return all opened dropbar menus
- `utils.menu.get_current(): dropbar_menu_t?`
- Get current dropbar menu
- utils.menu.select(items: any[], opts: table, on_choice: function(item, idx))
- Opt-in replacement for `vim.ui.select`
- Supports non-string items by formatting via the `opts.format_item` callback

### Usage with `vim.ui.select`

Dropbar can be used as a drop-in replacement for Neovim's builtin `vim.ui.select` menu.

To enable this functionality, simply replace `vim.ui.select` with `dropbar.utils.menu.select`:

```lua
vim.ui.select = require('dropbar.utils.menu').select
```

### Highlighting

Expand Down Expand Up @@ -2042,6 +2057,21 @@ Declared in [`lua/dropbar/sources/init.lua`](https://github.com/Bekaboo/dropbar.
| ------ | ------ | ------ |
| `get_symbols` | `function(buf: integer, win: integer, cursor: integer[]): dropbar_symbol_t[]` | returns the symbols<sub>[`dropbar_symbol_t[]`](#dropbar_symbol_t)</sub> to show in the winbar given buffer number `buf` and cursor position `cursor` |

#### `dropbar_select_opts_t`

Declared in [`lua/dropbar/utils/menu.lua`](https://github.com/Bekaboo/dropbar.nvim/blob/master/lua/dropbar/utils/menu.lua).

---

`dropbar_select_opts_t` is a class that represents the options passed to `utils.menu.select` (`vim.ui.select` with some extensions).

`dropbar_select_opts_t` has the following fields:

| Field | Type | Description |
| ------ | ------ | ------ |
| `prompt` | `string?` | determines what will be shown at the top of the select menu. |
| `format_item` | `fun(item: any): string, string[][]?` | formats the list items for display in the menu, and optionally formats virtual text chunks to be shown below the item. |

### Making a New Source

A [`dropbar_source_t`](#dropbar_source_t) instance is just a table with
Expand Down
38 changes: 37 additions & 1 deletion doc/dropbar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ CONTENTS *dropbar-table-of-contents*
5.3 Utility Functions |dropbar-configuration-utility-functions|
5.3.1 Bar Utility Functions |dropbar-configuration-utility-functions-bar|
5.3.2 Menu Utility Functions |dropbar-configuration-utility-functions-menu|
5.4 Highlighting |dropbar-configuration-highlighting|
5.4 Usage with `vim.ui.select` |dropbar-configuration-usage-with-ui-select|
5.5 Highlighting |dropbar-configuration-highlighting|
6. Developers |dropbar-developers|
6.1 Architecture |dropbar-developers-architecture|
6.2 Classes |dropbar-developers-classes|
Expand All @@ -40,6 +41,7 @@ CONTENTS *dropbar-table-of-contents*
6.2.5 `dropbar_menu_entry_t` |dropbar-developers-classes-dropbar_menu_entry_t|
6.2.6 `dropbar_menu_hl_info_t` |dropbar-developers-classes-dropbar_menu_hl_info_t|
6.2.7 `dropbar_source_t` |dropbar-developers-classes-dropbar_source_t|
6.2.8 `dropbar_select_opts_t` |dropbar-developers-classes-dropbar_select_opts_t|
6.3 Making a new source |dropbar-developers-making-a-new-source|
6.3.1 Making a source with drop-down menus |dropbar-developers-making-a-source-with-drop-down-menus|
6.3.2 Default `on_click()` callback |dropbar-developers-default-on_click-callback|
Expand Down Expand Up @@ -1023,6 +1025,18 @@ utils.menu.get_current() *dropbar-utility-functions-utils.menu.get_current()*
Returns ~
`dropbar_menu_t` or `nil`

------------------------------------------------------------------------------
USAGE WITH `vim.ui.select` *dropbar-configuration-usage-with-ui-select*

Dropbar can be used as a drop-in replacement for Neovim's builtin
`vim.ui.select` menu.

To enable this functionality, simply replace `vim.ui.select` with
`dropbar.utils.menu.select`: >lua

vim.ui.select = require('dropbar.utils.menu').select
<

------------------------------------------------------------------------------
HIGHLIGHTING *dropbar-configuration-highlighting*

Expand Down Expand Up @@ -2190,6 +2204,28 @@ dropbar_source_t.get_symbols({buf}, {win}, {cursor})
Returns ~
(`dropbar_symbol_t`[]): the symbols to show in the winbar

..............................................................................
DROPBAR_SELECT_OPTS_T *dropbar_select_opts_t*

Declared in `lua/dropbar/utils/menu.lua`.

`dropbar_select_opts_t` is a class that represents the options passed to `utils.menu.select` (`vim.ui.select` with some extensions).

`dropbar_select_opts_t` has the following field:

*dropbar_select_opts_t.format_item*
dropbar_select_opts_t.format_item({item})

Format an item in the list of items passed to `utils.menu.select` into a
string.

Parameters ~
• {item} (any): item in the list of items passed to `utils.menu.select`

Returns ~
(`string`): the text to display for the item
(`string`[][]?): optional virtual text to display below the item

------------------------------------------------------------------------------
MAKING A NEW SOURCE *dropbar-developers-making-a-source*

Expand Down
83 changes: 83 additions & 0 deletions lua/dropbar/utils/menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,87 @@ function M.update_preview(mouse)
last_previewed_menu = menu
end

---@class dropbar_select_opts_t
---Text to be displayed at the top of the menu
---@field prompt? string
---Function to format each item in the menu.
---Required if `items` is not a list of strings.
---The second return value is a list of virtual text chunks to be displayed below the item. If
---nothing is returned for the second value, no virtual text will be displayed.
---@field format_item? fun(item: any): string, string[][]?

---@param items string[]|table[] list of items to be selected
---@param opts dropbar_select_opts_t
function M.select(items, opts, on_choice)
if not items then
return
end

opts = opts or {}

local entries = vim
.iter(items)
:enumerate()
:map(function(idx, item)
local text = item
local virt_text

-- support custom formats for items like some
-- other ui-select plugins do
if opts.format_item then
text, virt_text = opts.format_item(item)
end

return require('dropbar.menu').dropbar_menu_entry_t:new({
-- virt_text will only be shown if returned from `format_item`
virt_text = virt_text,
components = {
require('dropbar.bar').dropbar_symbol_t:new({
icon = '',
icon_hl = 'Special',
name = text,
on_click = function(self)
self.entry.menu:close()
if on_choice then
on_choice(item, idx)
end
end,
}),
},
})
end)
:totable()

local border, title_pos
if opts.prompt then
border = require('dropbar.configs').opts.menu.win_configs.border
title_pos = 'center'
end

local menu = require('dropbar.menu').dropbar_menu_t:new({
entries = entries,
prev_win = vim.api.nvim_get_current_win(),
win_configs = {
relative = 'cursor',
title = opts.prompt,
row = 1,
col = 1,
border = border,
title_pos = title_pos,
},
})

menu:open()

vim.api.nvim_create_autocmd('CursorMoved', {
buffer = menu.buf,
callback = function()
local cursor = { vim.api.nvim_win_get_cursor(menu.win)[1], 1 }
vim.api.nvim_win_set_cursor(menu.win, cursor)
menu:update_hover_hl(cursor)
end,
desc = 'Lock cursor to the first column of the menu',
})
end

return M