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: support preview for entries in path source menus #86

Merged
merged 1 commit into from
Mar 3, 2024
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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,11 @@ vim.ui.select = require('dropbar.utils.menu').select
modified = function(sym)
return sym
end,
---@type boolean|fun(path: string): boolean?|nil
preview = function(path)
local stat = vim.uv.fs_stat(path)
return stat and stat.type == 'file' and stat.size <= 524288
end,
},
treesitter = {
-- Lua pattern used to extract a short name from the node text
Expand Down Expand Up @@ -1596,6 +1601,16 @@ each sources.
})
end
```
- `opts.sources.path.preview`: `boolean|fun(path: string): boolean?|nil`
- A boolean or a function that takes a file path and returns whether to
preview the file under cursor
- Default:
```lua
function(path)
local stat = vim.uv.fs_stat(path)
return stat and stat.type == 'file' and stat.size <= 524288
end
```

##### Treesitter

Expand Down Expand Up @@ -2139,6 +2154,7 @@ Declared and defined in [`lua/dropbar/menu.lua`](https://github.com/Bekaboo/drop
| `_win_configs` | `table?` | evaluated window configuration |
| `cursor` | `integer[]?` | initial cursor position |
| `prev_win` | `integer?` | previous window, assigned when calling new() or automatically determined in open() |
| `prev_buf` | `integer?` | previous buffer, assigned when calling new() or automatically determined in open() |
| `sub_menu` | `dropbar_menu_t?` | submenu, assigned when calling new() or automatically determined when a new menu opens |
| `prev_menu` | `dropbar_menu_t?` | previous menu, assigned when calling new() or automatically determined in open() |
| `clicked_at` | `integer[]?` | last position where the menu was clicked, 1,0-indexed |
Expand Down
19 changes: 19 additions & 0 deletions doc/dropbar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,17 @@ PATH *dropbar-configuration-options-sources-path*
-- ...
})
end
- `opts.sources.path.preview`: `boolean|fun(path: string): boolean?|nil`
- A boolean or a function that takes a file path and returns whether to
preview the file under cursor
- Default: >lua

function(path)
local stat = vim.uv.fs_stat(path)
return stat and stat.type == 'file'
and stat.size <= 524288
end
<

TREESITTER *dropbar-configuration-options-sources-treesitter*

Expand Down Expand Up @@ -1881,6 +1892,14 @@ dropbar_menu_t.win *dropbar_menu_t.win*
Type ~
integer

dropbar_menu_t.prev_buf *dropbar_menu_t.prev_buf*

Previous buffer, assigned when calling `new()` or automatically
determined in `open()`

Type ~
integer?

dropbar_menu_t.is_opened *dropbar_menu_t.is_opened*

Whether the menu is currently opened
Expand Down
5 changes: 5 additions & 0 deletions lua/dropbar/configs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,11 @@ M.opts = {
modified = function(sym)
return sym
end,
---@type boolean|fun(path: string): boolean?|nil
preview = function(path)
local stat = vim.uv.fs_stat(path)
return stat and stat.type == 'file' and stat.size <= 524288
end,
},
treesitter = {
-- Lua pattern used to extract a short name from the node text
Expand Down
15 changes: 15 additions & 0 deletions lua/dropbar/menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ end
---@field _win_configs table evaluated window configuration
---@field cursor integer[]? initial cursor position
---@field prev_win integer? previous window, assigned when calling new() or automatically determined in open()
---@field prev_buf integer? previous buffer, assigned when calling new() or automatically determined in open()
---@field sub_menu dropbar_menu_t? submenu, assigned when calling new() or automatically determined when a new menu opens
---@field prev_menu dropbar_menu_t? previous menu, assigned when calling new() or automatically determined in open()
---@field clicked_at integer[]? last position where the menu was clicked, byte-indexed, 1,0-indexed
Expand Down Expand Up @@ -303,6 +304,20 @@ function dropbar_menu_t:click_at(pos, min_width, n_clicks, button, modifiers)
end
end

---Retrieves the root window of the menu.
---If `self.prev_menu` is nil then this `self.prev_win`.
---Otherwise, it is the root window of `self.prev_menu`.
---@return integer?
function dropbar_menu_t:root_win()
local current = self
local win = self.prev_win
while current and current.prev_menu do
win = current.prev_menu.prev_win
current = current.prev_menu
end
return win
end

---"Click" the component in the dropbar menu
---Side effects: update self.clicked_at
---@param symbol dropbar_symbol_t
Expand Down
101 changes: 92 additions & 9 deletions lua/dropbar/sources/path.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ local function get_icon_and_hl(path)
local icon = icon_kind_opts.symbols.File
local icon_hl = 'DropBarIconKindFile'
local name_hl = 'DropBarKindFile'
local stat = vim.loop.fs_stat(path)
local stat = vim.uv.fs_stat(path)
if not stat then
return icon, icon_hl
elseif stat.type == 'directory' then
Expand All @@ -34,6 +34,82 @@ local function get_icon_and_hl(path)
return icon, icon_hl, name_hl
end

---@param self dropbar_symbol_t
local function preview_prepare_buf(self, path)
local stat = vim.uv.fs_stat(path)
if not stat or stat.type ~= 'file' then
self:preview_restore_view()
return
end
local buf = vim.fn.bufnr(path, false)
if buf == nil or buf == -1 then
buf = vim.fn.bufadd(path)
if not buf then
self:preview_restore_view()
return
end
if not vim.api.nvim_buf_is_loaded(buf) then
vim.fn.bufload(buf)
end
end
if buf == nil or self.entry.menu == nil or self.entry.menu.win == nil then
self:preview_restore_view()
return
end
return buf
end

---@param self dropbar_symbol_t
local function preview_open(self, path)
if not configs.eval(configs.opts.sources.path.preview, path) then
return
end
local preview_buf = preview_prepare_buf(self, path)
if not preview_buf then
return
end
local buflisted = vim.bo[preview_buf].buflisted

local preview_win = self.entry.menu:root_win()
if not preview_win then
return
end
self.entry.menu.prev_buf = self.entry.menu.prev_buf
or vim.api.nvim_win_get_buf(preview_win)

vim.api.nvim_create_autocmd('BufLeave', {
buffer = self.entry.menu.buf,
callback = function()
self:preview_restore_view()
end,
})
vim.api.nvim_win_set_buf(preview_win, preview_buf)
-- set cursor to the last exited position in buf (:h '"), if available
local last_exit = vim.api.nvim_buf_get_mark(preview_buf, '"')
if last_exit[1] ~= 0 then
vim.api.nvim_win_set_cursor(preview_win, last_exit)
end

vim.bo[preview_buf].buflisted = buflisted

-- ensure dropbar still shows then the preview buffer is opened
vim.wo[preview_win].winbar = '%{%v:lua.dropbar.get_dropbar_str()%}'
end

---@param self dropbar_symbol_t
local function preview_close(self)
if self.win then
if self.entry.menu.prev_buf then
vim.api.nvim_win_set_buf(self.win, self.entry.menu.prev_buf)
end
if self.view then
vim.api.nvim_win_call(self.win, function()
vim.fn.winrestview(self.view)
end)
end
end
end

---Convert a path to a dropbar symbol
---@param path string full path
---@param buf integer buffer handler
Expand All @@ -42,6 +118,7 @@ end
local function convert(path, buf, win)
local path_opts = configs.opts.sources.path
local icon, icon_hl, name_hl = get_icon_and_hl(path)

return bar.dropbar_symbol_t:new(setmetatable({
buf = buf,
win = win,
Expand All @@ -53,6 +130,10 @@ local function convert(path, buf, win)
jump = function(_)
vim.cmd.edit(path)
end,
preview = vim.schedule_wrap(function(self)
preview_open(self, path)
end),
preview_restore_view = preview_close,
}, {
---@param self dropbar_symbol_t
__index = function(self, k)
Expand All @@ -69,14 +150,16 @@ local function convert(path, buf, win)
local parent_dir = vim.fs.dirname(path)
self.siblings = {}
self.sibling_idx = 1
for idx, name in vim.iter(vim.fs.dir(parent_dir)):enumerate() do
if path_opts.filter(name) then
table.insert(
self.siblings,
convert(parent_dir .. '/' .. name, buf, win)
)
if name == self.name then
self.sibling_idx = idx
if parent_dir then
for idx, name in vim.iter(vim.fs.dir(parent_dir)):enumerate() do
if path_opts.filter(name) then
table.insert(
self.siblings,
convert(parent_dir .. '/' .. name, buf, win)
)
if name == self.name then
self.sibling_idx = idx
end
end
end
end
Expand Down
Loading