Skip to content

Commit

Permalink
Add ability to not render UI views (#44)
Browse files Browse the repository at this point in the history
* Add ability to not show UI panes, determined by LayoutProvider. Refine error handling in treesitter context creation.

* Add guide on not rendering preview UI

* Allow for customizing the cursor character

* Add dot_index_expression to catch Lua module functions in ts context

* Add Lua method index expression to ts context triggers
  • Loading branch information
EvWilson authored Dec 14, 2024
1 parent af52342 commit 3424188
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 69 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ Here's the default mapping object for reference:
orientation = 'vertical',
-- Enable to show mark index in status column
enable_status_col_display = false,
-- The character rendered before the currently selected bookmark in the UI
cursor_character = '>',
}
```

Expand Down Expand Up @@ -263,3 +265,4 @@ Some examples are available in th [`faqs`](faqs/) directory. If there's somethin
Currently there are guides on:
- Providing a custom formatter for display filenames
- Overriding the display function altogether to show Treesitter context instead of mark location
- Not rendering the preview UI pane, which applies to all UI panes
5 changes: 4 additions & 1 deletion faqs/display_treesitter_context.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ If you'd like to change this to display the Treesitter context for the current m
local spelunk = require('spelunk')
spelunk.setup()
spelunk.display_function = function(mark)
return require('spelunk.util').get_treesitter_context(mark)
local ctx = require('spelunk.util').get_treesitter_context(mark)
ctx = (ctx == '' and ctx) or (' - ' .. ctx)
local filename = spelunk.filename_formatter(mark.file)
return string.format("%s:%d%s", filename, mark.line, ctx)
end
end
}
Expand Down
48 changes: 48 additions & 0 deletions faqs/hide_preview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Hide the Preview UI Pane

Some folks would prefer to hide the preview UI pane and just have the main bookmark stack rendered. This is possible by leaving off the dimension function for the pane you'd prefer not to render when supplying your own custom `LayoutProvider`.

Here's an example of leaving the preview UI pane un-rendered, with a sample `lazy.nvim` spec:
```lua
{
'EvWilson/spelunk.nvim',
dependencies = {
'nvim-lua/plenary.nvim',
},
config = function()
local spelunk = require('spelunk')
local function width_portion()
return math.floor(vim.o.columns / 20)
end
local function height_portion()
return math.floor(vim.o.lines / 12)
end
local base_dimensions = function()
return {
width = width_portion() * 16,
height = height_portion() * 5,
}
end
spelunk.setup({
orientation = {
bookmark_dimensions = function()
local dims = base_dimensions()
return {
base = dims,
line = height_portion() * 5,
col = width_portion() * 2,
}
end,
help_dimensions = function()
local dims = base_dimensions()
return {
base = dims,
line = height_portion() * 3,
col = width_portion() * 2,
}
end,
},
})
end
},
```
1 change: 1 addition & 0 deletions lua/spelunk/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ local default_config = {
statusline_prefix = '🔖',
orientation = 'vertical',
enable_status_col_display = false,
cursor_character = '>',
}

---@param target table
Expand Down
6 changes: 5 additions & 1 deletion lua/spelunk/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ function M.close_help()
end

function M.add_bookmark()
if ui.is_open() then
vim.notify('[spelunk.nvim] Cannot create bookmark while UI is open')
return
end
local currstack = current_stack()
table.insert(currstack.bookmarks, marks.set_mark_current_pos(#currstack.bookmarks + 1))
vim.notify(string.format("[spelunk.nvim] Bookmark added to stack '%s': %s:%d:%d",
Expand Down Expand Up @@ -429,7 +433,7 @@ function M.setup(c)
cfg.apply_base_defaults(base_config)
window_config = conf.window_mappings or {}
cfg.apply_window_defaults(window_config)
ui.setup(base_config, window_config)
ui.setup(base_config, window_config, conf.cursor_character or cfg.get_default('cursor_character'))

require('spelunk.layout').setup(conf.orientation or cfg.get_default('orientation'))

Expand Down
15 changes: 15 additions & 0 deletions lua/spelunk/layout.lua
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ local help_dimension_func = function()
end
end

---@return boolean
M.has_bookmark_dimensions = function()
return M.bookmark_dimensions ~= nil
end

---@return boolean
M.has_preview_dimensions = function()
return M.preview_dimensions ~= nil
end

---@return boolean
M.has_help_dimensions = function()
return M.help_dimensions ~= nil
end

---@param o 'vertical' | 'horizontal' | LayoutProvider
function M.setup(o)
if o ~= 'vertical' and o ~= 'horizontal' and type(o) ~= 'table' then
Expand Down
149 changes: 86 additions & 63 deletions lua/spelunk/ui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ function M.is_open()
return window_id ~= -1 or preview_window_id ~= -1 or help_window_id ~= -1
end

---@type table
local base_config
---@type table
local window_config
---@type string
local cursor_character

local focus_cb
local unfocus_cb
Expand Down Expand Up @@ -98,9 +102,17 @@ local function read_lines(filename, start_line, end_line)
return result
end

function M.setup(base_cfg, window_cfg)
---@param base_cfg table
---@param window_cfg table
---@param cursor_char string
function M.setup(base_cfg, window_cfg, cursor_char)
base_config = base_cfg
window_config = window_cfg
if type(cursor_char) ~= 'string' or string.len(cursor_char) ~= 1 then
vim.notify('[spelunk.nvim] Passed invalid cursor character, falling back to default')
cursor_char = '>'
end
cursor_character = cursor_char
end

---@param opts CreateWinOpts
Expand All @@ -120,6 +132,10 @@ local function create_window(opts)
end

function M.show_help()
if not layout.has_help_dimensions() then
return
end

unfocus_cb()

local dims = layout.help_dimensions()
Expand Down Expand Up @@ -182,72 +198,79 @@ function M.close_help()
end

---@param max_stack_size integer
function M.create_windows(max_stack_size)
local win_dims = layout.bookmark_dimensions()
local bufnr, win_id = create_window({
title = 'Bookmarks',
col = win_dims.col,
line = win_dims.line,
minwidth = win_dims.base.width,
minheight = win_dims.base.height,
})
window_id = win_id
local create_windows = function(max_stack_size)
local bufnr, win_id
if layout.has_bookmark_dimensions() then
local win_dims = layout.bookmark_dimensions()
bufnr, win_id = create_window({
title = 'Bookmarks',
col = win_dims.col,
line = win_dims.line,
minwidth = win_dims.base.width,
minheight = win_dims.base.height,
})
window_id = win_id
end

local prev_dims = layout.preview_dimensions()
local _, prev_id = create_window({
title = 'Preview',
col = prev_dims.col,
line = prev_dims.line,
minwidth = prev_dims.base.width,
minheight = prev_dims.base.height,
})
preview_window_id = prev_id

-- Set up keymaps for navigation within the window
local set = require('spelunk.config').set_buf_keymap(bufnr)
set(window_config.cursor_down, ':lua require("spelunk").move_cursor(1)<CR>', '[spelunk.nvim] Move cursor down')
set(window_config.cursor_up, ':lua require("spelunk").move_cursor(-1)<CR>', '[spelunk.nvim] Move cursor up')
set(window_config.bookmark_down, ':lua require("spelunk").move_bookmark(1)<CR>', '[spelunk.nvim] Move bookmark down')
set(window_config.bookmark_up, ':lua require("spelunk").move_bookmark(-1)<CR>', '[spelunk.nvim] Move bookmark up')
set(window_config.goto_bookmark, ':lua require("spelunk").goto_selected_bookmark()<CR>',
'[spelunk.nvim] Go to selected bookmark')
set(window_config.goto_bookmark_hsplit, ':lua require("spelunk").goto_selected_bookmark_horizontal_split()<CR>',
'[spelunk.nvim] Go to selected bookmark, in new horizontal split')
set(window_config.goto_bookmark_vsplit, ':lua require("spelunk").goto_selected_bookmark_vertical_split()<CR>',
'[spelunk.nvim] Go to selected bookmark, in new vertical split')
set(window_config.delete_bookmark, ':lua require("spelunk").delete_selected_bookmark()<CR>',
'[spelunk.nvim] Delete selected bookmark')
set(window_config.next_stack, ':lua require("spelunk").next_stack()<CR>', '[spelunk.nvim] Go to next stack')
set(window_config.previous_stack, ':lua require("spelunk").prev_stack()<CR>', '[spelunk.nvim] Go to previous stack')
set(window_config.new_stack, ':lua require("spelunk").new_stack()<CR>', '[spelunk.nvim] Create new stack')
set(window_config.delete_stack, ':lua require("spelunk").delete_current_stack()<CR>',
'[spelunk.nvim] Delete current stack')
set(window_config.edit_stack, ':lua require("spelunk").edit_current_stack()<CR>',
'[spelunk.nvim] Edit the name of the current stack')
set(window_config.close, ':lua require("spelunk").close_windows()<CR>', '[spelunk.nvim] Close UI')
set(window_config.help, ':lua require("spelunk").show_help()<CR>', '[spelunk.nvim] Show help menu')

for i = 1, max_stack_size do
set(tostring(i), string.format(':lua require("spelunk").goto_bookmark_at_index(%d)<CR>', i),
string.format('[spelunk.nvim] Go to bookmark at stack position %d', i))
if layout.has_preview_dimensions() then
local prev_dims = layout.preview_dimensions()
local _, prev_id = create_window({
title = 'Preview',
col = prev_dims.col,
line = prev_dims.line,
minwidth = prev_dims.base.width,
minheight = prev_dims.base.height,
})
preview_window_id = prev_id
end

focus_cb, unfocus_cb = persist_focus(win_id, function()
if window_ready(window_id) then
vim.api.nvim_win_close(window_id, true)
if bufnr then
-- Set up keymaps for navigation within the window
local set = require('spelunk.config').set_buf_keymap(bufnr)
set(window_config.cursor_down, ':lua require("spelunk").move_cursor(1)<CR>', '[spelunk.nvim] Move cursor down')
set(window_config.cursor_up, ':lua require("spelunk").move_cursor(-1)<CR>', '[spelunk.nvim] Move cursor up')
set(window_config.bookmark_down, ':lua require("spelunk").move_bookmark(1)<CR>',
'[spelunk.nvim] Move bookmark down')
set(window_config.bookmark_up, ':lua require("spelunk").move_bookmark(-1)<CR>', '[spelunk.nvim] Move bookmark up')
set(window_config.goto_bookmark, ':lua require("spelunk").goto_selected_bookmark()<CR>',
'[spelunk.nvim] Go to selected bookmark')
set(window_config.goto_bookmark_hsplit, ':lua require("spelunk").goto_selected_bookmark_horizontal_split()<CR>',
'[spelunk.nvim] Go to selected bookmark, in new horizontal split')
set(window_config.goto_bookmark_vsplit, ':lua require("spelunk").goto_selected_bookmark_vertical_split()<CR>',
'[spelunk.nvim] Go to selected bookmark, in new vertical split')
set(window_config.delete_bookmark, ':lua require("spelunk").delete_selected_bookmark()<CR>',
'[spelunk.nvim] Delete selected bookmark')
set(window_config.next_stack, ':lua require("spelunk").next_stack()<CR>', '[spelunk.nvim] Go to next stack')
set(window_config.previous_stack, ':lua require("spelunk").prev_stack()<CR>',
'[spelunk.nvim] Go to previous stack')
set(window_config.new_stack, ':lua require("spelunk").new_stack()<CR>', '[spelunk.nvim] Create new stack')
set(window_config.delete_stack, ':lua require("spelunk").delete_current_stack()<CR>',
'[spelunk.nvim] Delete current stack')
set(window_config.edit_stack, ':lua require("spelunk").edit_current_stack()<CR>',
'[spelunk.nvim] Edit the name of the current stack')
set(window_config.close, ':lua require("spelunk").close_windows()<CR>', '[spelunk.nvim] Close UI')
set(window_config.help, ':lua require("spelunk").show_help()<CR>', '[spelunk.nvim] Show help menu')

for i = 1, max_stack_size do
set(tostring(i), string.format(':lua require("spelunk").goto_bookmark_at_index(%d)<CR>', i),
string.format('[spelunk.nvim] Go to bookmark at stack position %d', i))
end
window_id = -1
-- Defer preview window cleanup, as running it concurrently to main window
-- causes it to not fire
vim.schedule(function()
if window_ready(preview_window_id) then
vim.api.nvim_win_close(preview_window_id, true)

focus_cb, unfocus_cb = persist_focus(win_id, function()
if window_ready(window_id) then
vim.api.nvim_win_close(window_id, true)
end
preview_window_id = -1
window_id = -1
-- Defer preview window cleanup, as running it concurrently to main window
-- causes it to not fire
vim.schedule(function()
if window_ready(preview_window_id) then
vim.api.nvim_win_close(preview_window_id, true)
end
preview_window_id = -1
end)
end)
end)

return bufnr
end
end

---@param opts UpdateWinOpts
Expand Down Expand Up @@ -288,7 +311,7 @@ function M.update_window(opts)
vim.api.nvim_set_option_value('modifiable', true, { buf = bufnr })
local content_lines = {}
for idx, line in ipairs(opts.lines) do
local prefix = idx == opts.cursor_index and '>' or ' '
local prefix = idx == opts.cursor_index and cursor_character or ' '
table.insert(content_lines, string.format('%s%2d %s', prefix, idx, line))
end
local content = { 'Current stack: ' .. opts.title, unpack(content_lines) }
Expand All @@ -312,7 +335,7 @@ function M.toggle_window(opts)
if window_ready(window_id) then
M.close_windows()
else
local _ = M.create_windows(opts.max_stack_size)
create_windows(opts.max_stack_size)
M.update_window(opts)
vim.api.nvim_set_current_win(window_id)
end
Expand Down
11 changes: 7 additions & 4 deletions lua/spelunk/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ local M = {}
M.get_treesitter_context = function(mark)
local ok, parser = pcall(vim.treesitter.get_parser, mark.bufnr)
if not ok then
return '[spelunk.nvim] get_treesitter_context failed to set up parser: ' .. parser
vim.notify('[spelunk.nvim] get_treesitter_context failed to set up parser: ' .. parser)
return ''
end
local tree = parser:parse()[1]
local root = tree:root()
local node_at_cursor = root:named_descendant_for_range(mark.line, mark.col, mark.line, mark.col)
---@param arr string[]
---@param s string
---@return boolean
Expand All @@ -22,6 +22,7 @@ M.get_treesitter_context = function(mark)
return false
end
---@param node TSNode
---@return string | nil
local get_node_name = function(node)
if not node then return nil end
---@param n TSNode | nil
Expand All @@ -48,7 +49,9 @@ M.get_treesitter_context = function(mark)
'name',
'function_name',
'class_name',
'field_identifier'
'field_identifier',
'dot_index_expression',
'method_index_expression',
}, child:type()) then
identifier = child
end
Expand All @@ -57,7 +60,7 @@ M.get_treesitter_context = function(mark)
return get_txt(identifier)
end
local node_names = {}
local current_node = node_at_cursor
local current_node = root:named_descendant_for_range(mark.line, mark.col, mark.line, mark.col)
while current_node do
local node_type = current_node:type()
if has({
Expand Down

0 comments on commit 3424188

Please sign in to comment.