From 1bee80f8fc142755444a210f93a4ff9a5af0820a Mon Sep 17 00:00:00 2001
From: bekaboo <18127878294@qq.com>
Date: Sun, 4 Jun 2023 22:45:48 -0500
Subject: [PATCH] fix(menu): drop-down menu position
1. This bug only occurs when 'mousemoveevent' is on
2. Steps to reproduce:
- Use mouse to click on a symbol in winbar to open a menu
- Close the menu
- Move the mouse to an arbitrary position (inside nvim)
- Use pick mode to select the same symbol
- The menu is opened under the current mouse position instead of under
the selected symbol
3. Cause: the menu is created with window configuration relative='mouse'
the first time it is opened, so when we open it the second time
the window is opened at the mouse position
4. Fix: pass window configurations to dropbar_menu_t:toggle() and
dropbar_menu_t:open() to override original configurations
if a menu is opened in pick mode
---
README.md | 6 +++---
doc/dropbar.txt | 23 ++++++++++++++++++-----
lua/dropbar/bar.lua | 42 ++++++++++++++++++++++--------------------
lua/dropbar/menu.lua | 17 +++++++++++------
4 files changed, 54 insertions(+), 34 deletions(-)
diff --git a/README.md b/README.md
index 8cf3bfea..8c18da2a 100644
--- a/README.md
+++ b/README.md
@@ -1289,7 +1289,7 @@ Declared and defined in [`lua/dropbar/menu.lua`](https://github.com/Bekaboo/drop
| ------ | ------ |
| `dropbar_menu_t:new(opts: dropbar_menu_opts_t?): dropbar_menu_t` | constructor of `dropbar_menu_t` |
| `dropbar_menu_t:del()` | destructor of `dropbar_menu_t` |
-| `dropbar_menu_t:eval_win_config()` | evaluate window configuration and store the result in `_win_configs` |
+| `dropbar_menu_t:eval_win_configs(win_configs: table?)` | evaluate window configurations (`dropbar_menu_t.win_configs` merged with param `win_configs`) and store the result in `dropbar_menu_t._win_configs` |
| `dropbar_menu_t:get_component_at(pos: integer[]): dropbar_symbol_t?, { start: integer, end: integer }?` | get the component[`dropbar_symbol_t`](#dropbar_symbol_t) at position `pos` and its range it occupies in the entry it belongs to |
| `dropbar_menu_t:click_at(pos: integer[], min_width: integer?, n_clicks: integer?, button: string?, modifiers: string?)` | simulate a click at `pos` in the menu |
| `dropbar_menu_t:click_on(symbol: dropbar_symbol_t, min_width: integer?, n_clicks: integer?, button: string?, modifiers: string?)` | simulate a click at the component `symbol`[`dropbar_symbol_t`](#dropbar_symbol_t) of the menu |
@@ -1298,9 +1298,9 @@ Declared and defined in [`lua/dropbar/menu.lua`](https://github.com/Bekaboo/drop
| `dropbar_menu_t:hl_range_single(line: integer?, range: { start: integer, end: integer }?, hlgroup: string?)` | add highlight to a single range in a single line in the menu buffer; `hlgroups` defaults to `'DropBarMenuHoverSymbol'`
*all highlights with the same hlgroup added by this functions before will be cleared |
| `dropbar_menu_t:update_hover_hl(pos: integer[])` | update the hover highlights (`DropBarMenuHover*`) assuming the cursor/mouse is hovering at `pos` in the menu |
| `dropbar_menu_t:make_buf()` | create the menu buffer from the entries[`dropbar_menu_entry_t`](#dropbar_menu_entry_t) |
-| `dropbar_menu_t:open()` | open the menu |
+| `dropbar_menu_t:open(win_configs: table?)` | open the menu with window configurations `dropbar_menu_t.win_configs` merged with param `win_configs` |
| `dropbar_menu_t:close()` | close the menu |
-| `dropbar_menu_t:toggle()` | toggle the menu |
+| `dropbar_menu_t:toggle(win_configs; table)` | toggle the menu, passing `win_configs` to `dropbar_menu_t:open()` if decide to open the menu |
#### `dropbar_menu_entry_t`
diff --git a/doc/dropbar.txt b/doc/dropbar.txt
index 2e271812..968b83fa 100644
--- a/doc/dropbar.txt
+++ b/doc/dropbar.txt
@@ -1359,9 +1359,14 @@ dropbar_menu_t:del() *dropbar_menu_t:del()*
Destructor of `dropbar_menu_t`
-dropbar_menu_t:eval_win_config() *dropbar_menu_t:eval_win_config()*
+ *dropbar_menu_t:eval_win_configs()*
+dropbar_menu_t:eval_win_configs([{win_configs}])
- Evaluate window configuration and store the result in `_win_configs`
+ Evaluate window configurations |dropbar_menu_t.win_configs| and store
+ the result in |dropbar_menu_t._win_configs|
+
+ Parameters ~
+ • {win_configs} (table?): window configurations to override
dropbar_menu_t:get_component_at({pos}) *dropbar_menu_t:get_component_at()*
@@ -1454,18 +1459,26 @@ dropbar_menu_t:make_buf() *dropbar_menu_t:make_buf()*
Create the menu buffer from the entries
|dropbar-developers-classes-dropbar_menu_entry_t|
-dropbar_menu_t:open() *dropbar_menu_t:open()*
+dropbar_menu_t:open([{win_configs}]) *dropbar_menu_t:open()*
+
+ Open the menu with window configurations |dropbar_menu_t.win_configs|
+ merged with {win_configs}
- Open the menu
+ Parameters ~
+ • {win_configs} (table?): window configurations to override
dropbar_menu_t:close() *dropbar_menu_t:close()*
Close the menu
-dropbar_menu_t:toggle() *dropbar_menu_t:toggle()*
+dropbar_menu_t:toggle([{win_configs}]) *dropbar_menu_t:toggle()*
Toggle the menu
+ Parameters ~
+ • {win_configs} (table?): window configurations passing to
+ |dropbar_menu_t:open()|
+
..............................................................................
DROPBAR_MENU_ENTRY_T *dropbar-developers-classes-dropbar_menu_entry_t*
*dropbar_menu_entry_t*
diff --git a/lua/dropbar/bar.lua b/lua/dropbar/bar.lua
index 9b3f8458..d3308603 100644
--- a/lua/dropbar/bar.lua
+++ b/lua/dropbar/bar.lua
@@ -68,17 +68,38 @@ function dropbar_symbol_t:new(opts)
name = '',
icon = '',
on_click = opts
+ ---@param this dropbar_symbol_t
and function(this, _, _, _, _)
if this.entry and this.entry.menu then
this.entry.menu:hl_line_single(this.entry.idx)
end
+
+ -- Called in pick mode, open the menu relative to the symbol
+ -- position in the winbar
+ local menu_win_configs = nil
+ if this.bar and this.bar.in_pick_mode then
+ local col = 0
+ for i, component in ipairs(this.bar.components) do
+ if i < this.bar_idx then
+ col = col
+ + component:displaywidth()
+ + this.bar.separator:displaywidth()
+ end
+ end
+ menu_win_configs = {
+ relative = 'win',
+ row = 0,
+ col = col,
+ }
+ end
+
-- Toggle menu on click, or create one if menu don't exist:
-- 1. If symbol inside a winbar, create a menu with entries
-- containing the symbol's siblings
-- 2. Else if symbol inside a menu, create menu with entries
-- containing the symbol's children
if this.menu then
- this.menu:toggle()
+ this.menu:toggle(menu_win_configs)
return
end
@@ -99,25 +120,6 @@ function dropbar_symbol_t:new(opts)
return
end
- -- Called in pick mode, open the menu relative to the symbol
- -- position in the winbar
- local menu_win_configs = nil
- if this.bar and this.bar.in_pick_mode then
- local col = 0
- for i, component in ipairs(this.bar.components) do
- if i < this.bar_idx then
- col = col
- + component:displaywidth()
- + this.bar.separator:displaywidth()
- end
- end
- menu_win_configs = {
- relative = 'win',
- row = 0,
- col = col,
- }
- end
-
local menu = require('dropbar.menu')
this.menu = menu.dropbar_menu_t:new({
prev_win = menu_prev_win,
diff --git a/lua/dropbar/menu.lua b/lua/dropbar/menu.lua
index 9d53d8cd..405a827e 100644
--- a/lua/dropbar/menu.lua
+++ b/lua/dropbar/menu.lua
@@ -220,12 +220,15 @@ end
---Evaluate window configurations
---Side effects: update self._win_configs
+---@param win_configs table? window configurations to override
---@return nil
---@see vim.api.nvim_open_win
-function dropbar_menu_t:eval_win_config()
+function dropbar_menu_t:eval_win_configs(win_configs)
-- Evaluate function-valued window configurations
self._win_configs = {}
- for k, config in pairs(self.win_configs) do
+ for k, config in
+ pairs(vim.tbl_deep_extend('force', self.win_configs, win_configs or {}))
+ do
if type(config) == 'function' then
self._win_configs[k] = config(self)
else
@@ -506,8 +509,9 @@ end
---Open the menu
---Side effect: change self.win and self.buf
+---@param win_configs table? window configurations to override
---@return nil
-function dropbar_menu_t:open()
+function dropbar_menu_t:open(win_configs)
if self.is_opened then
return
end
@@ -524,7 +528,7 @@ function dropbar_menu_t:open()
self.prev_win = parent_menu.win
end
- self:eval_win_config()
+ self:eval_win_configs(win_configs)
self:make_buf()
self.win = vim.api.nvim_open_win(self.buf, true, self._win_configs)
self.is_opened = true
@@ -561,12 +565,13 @@ function dropbar_menu_t:close()
end
---Toggle the menu
+---@param win_configs table? window configurations to override
---@return nil
-function dropbar_menu_t:toggle()
+function dropbar_menu_t:toggle(win_configs)
if self.is_opened then
self:close()
else
- self:open()
+ self:open(win_configs)
end
end