Regenerate nvim config
This commit is contained in:
@ -0,0 +1,754 @@
|
||||
local actions = {}
|
||||
|
||||
local function fix_end_character_position(bufnr, name_range_or_scope)
|
||||
if name_range_or_scope["end"].character == 0 and (name_range_or_scope["end"].line - name_range_or_scope["start"].line) > 0 then
|
||||
name_range_or_scope["end"].line = name_range_or_scope["end"].line - 1
|
||||
name_range_or_scope["end"].character = string.len(vim.api.nvim_buf_get_lines(bufnr, name_range_or_scope["end"].line - 1, name_range_or_scope["end"].line, false)[1])
|
||||
end
|
||||
end
|
||||
|
||||
function actions.close()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
vim.api.nvim_win_set_cursor(display.for_win, display.start_cursor)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Close Navbuddy"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.next_sibling()
|
||||
local callback = function(display)
|
||||
if display.focus_node.next == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for _ = 1, vim.v.count1 do
|
||||
local next_node = display.focus_node.next
|
||||
if next_node == nil then
|
||||
break
|
||||
end
|
||||
display.focus_node = next_node
|
||||
end
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move down to next node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.previous_sibling()
|
||||
local callback = function(display)
|
||||
if display.focus_node.prev == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for _ = 1, vim.v.count1 do
|
||||
local prev_node = display.focus_node.prev
|
||||
if prev_node == nil then
|
||||
break
|
||||
end
|
||||
display.focus_node = prev_node
|
||||
end
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move up to previous node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.parent()
|
||||
local callback = function(display)
|
||||
if display.focus_node.parent.is_root then
|
||||
return
|
||||
end
|
||||
|
||||
local parent_node = display.focus_node.parent
|
||||
display.focus_node = parent_node
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move left to parent level"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.children()
|
||||
local callback = function(display)
|
||||
if display.focus_node.children == nil then
|
||||
actions.select().callback(display)
|
||||
return
|
||||
end
|
||||
|
||||
local child_node
|
||||
if display.focus_node.memory then
|
||||
child_node = display.focus_node.children[display.focus_node.memory]
|
||||
else
|
||||
child_node = display.focus_node.children[1]
|
||||
end
|
||||
display.focus_node = child_node
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move right to child node level"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.root()
|
||||
local callback = function(display)
|
||||
if display.focus_node.parent.is_root then
|
||||
return
|
||||
end
|
||||
|
||||
while not display.focus_node.parent.is_root do
|
||||
display.focus_node.parent.memory = display.focus_node.index
|
||||
display.focus_node = display.focus_node.parent
|
||||
end
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move to top most node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.select()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
-- to push location to jumplist:
|
||||
-- move display to start_cursor, set mark ', then move to new location
|
||||
vim.api.nvim_win_set_cursor(display.for_win, display.start_cursor)
|
||||
vim.api.nvim_command("normal! m'")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
|
||||
if display.config.source_buffer.reorient == "smart" then
|
||||
local total_lines = display.focus_node.scope["end"].line - display.focus_node.scope["start"].line + 1
|
||||
|
||||
if total_lines >= vim.api.nvim_win_get_height(display.for_win) then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
else
|
||||
local mid_line =
|
||||
bit.rshift(display.focus_node.scope["start"].line + display.focus_node.scope["end"].line, 1)
|
||||
vim.api.nvim_win_set_cursor(display.for_win, { mid_line, 0 })
|
||||
vim.api.nvim_command("normal! zz")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
end
|
||||
elseif display.config.source_buffer.reorient == "mid" then
|
||||
vim.api.nvim_command("normal! zz")
|
||||
elseif display.config.source_buffer.reorient == "top" then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Select and Goto current node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.yank_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["end"].line, display.focus_node.name_range["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_command('normal! "+y')
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Yank node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.yank_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_command('normal! "+y')
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Yank node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.visual_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["end"].line, display.focus_node.name_range["end"].character - 1 }
|
||||
)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Visual select node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.visual_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Visual select node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.insert_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
vim.api.nvim_feedkeys("i", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Insert node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.insert_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_feedkeys("i", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Insert node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.append_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["end"].line, display.focus_node.name_range["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_feedkeys("a", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Append node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.append_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
if
|
||||
string.len(
|
||||
vim.api.nvim_buf_get_lines(
|
||||
display.for_buf,
|
||||
display.focus_node.scope["end"].line - 1,
|
||||
display.focus_node.scope["end"].line,
|
||||
false
|
||||
)[1]
|
||||
) == display.focus_node.scope["end"].character
|
||||
then
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character }
|
||||
)
|
||||
else
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
end
|
||||
vim.api.nvim_feedkeys("a", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Append node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.rename()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
vim.lsp.buf.rename()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Rename"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.delete()
|
||||
local callback = function(display)
|
||||
actions.visual_scope().callback(display)
|
||||
vim.api.nvim_command("normal! d")
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Delete"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.fold_create()
|
||||
local callback = function(display)
|
||||
if vim.o.foldmethod ~= "manual" then
|
||||
vim.notify("Fold create action works only when foldmethod is 'manual'", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
display.state.leaving_window_for_action = true
|
||||
vim.api.nvim_set_current_win(display.for_win)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_command("normal! zf")
|
||||
vim.api.nvim_set_current_win(display.mid.winid)
|
||||
display.state.leaving_window_for_action = false
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Create fold"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.fold_delete()
|
||||
local callback = function(display)
|
||||
if vim.o.foldmethod ~= "manual" then
|
||||
vim.notify("Fold delete action works only when foldmethod is 'manual'", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
display.state.leaving_window_for_action = true
|
||||
vim.api.nvim_set_current_win(display.for_win)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
pcall(vim.api.nvim_command, "normal! zd")
|
||||
vim.api.nvim_set_current_win(display.mid.winid)
|
||||
display.state.leaving_window_for_action = false
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Delete fold"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.comment()
|
||||
local callback = function(display)
|
||||
local status_ok, comment = pcall(require, "Comment.api")
|
||||
if not status_ok then
|
||||
vim.notify("Comment.nvim not found", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
display.state.leaving_window_for_action = true
|
||||
vim.api.nvim_set_current_win(display.for_win)
|
||||
vim.api.nvim_buf_set_mark(
|
||||
display.for_buf,
|
||||
"<",
|
||||
display.focus_node.scope["start"].line,
|
||||
display.focus_node.scope["start"].character,
|
||||
{}
|
||||
)
|
||||
vim.api.nvim_buf_set_mark(
|
||||
display.for_buf,
|
||||
">",
|
||||
display.focus_node.scope["end"].line,
|
||||
display.focus_node.scope["end"].character,
|
||||
{}
|
||||
)
|
||||
comment.locked("toggle.linewise")("v")
|
||||
vim.api.nvim_set_current_win(display.mid.winid)
|
||||
display.state.leaving_window_for_action = false
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Comment"
|
||||
}
|
||||
end
|
||||
|
||||
local function swap_nodes(for_buf, nodeA, nodeB)
|
||||
-- nodeA
|
||||
-- ^
|
||||
-- |
|
||||
-- v
|
||||
-- nodeB
|
||||
|
||||
fix_end_character_position(for_buf, nodeA.scope)
|
||||
fix_end_character_position(for_buf, nodeB.scope)
|
||||
|
||||
if nodeA.scope["end"].line >= nodeB.scope["start"].line and nodeA.parent == nodeB.parent then
|
||||
vim.notify("Cannot swap!", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local nodeA_text = vim.api.nvim_buf_get_lines(for_buf, nodeA.scope["start"].line-1, nodeA.scope["end"].line-1+1, false)
|
||||
local mid_text = vim.api.nvim_buf_get_lines(for_buf, nodeA.scope["end"].line-1+1, nodeB.scope["start"].line-1, false)
|
||||
local nodeB_text = vim.api.nvim_buf_get_lines(for_buf, nodeB.scope["start"].line-1, nodeB.scope["end"].line-1+1, false)
|
||||
|
||||
local start_line = nodeA.scope["start"].line-1
|
||||
local nodeA_line_cnt = nodeA.scope["end"].line + 1 - nodeA.scope["start"].line
|
||||
local mid_line_cnt = nodeB.scope["start"].line - nodeA.scope["end"].line - 1
|
||||
local nodeB_line_cnt = nodeB.scope["end"].line + 1 - nodeB.scope["start"].line
|
||||
|
||||
-- Swap pointers
|
||||
nodeA.next = nodeB.next
|
||||
nodeB.next = nodeA
|
||||
|
||||
nodeB.prev = nodeA.prev
|
||||
nodeA.prev = nodeB
|
||||
|
||||
-- Swap index
|
||||
local nodeB_index = nodeB.index
|
||||
nodeB.index = nodeA.index
|
||||
nodeA.index = nodeB_index
|
||||
|
||||
-- Swap in parent's children array
|
||||
local parent = nodeA.parent
|
||||
parent.children[nodeA.index] = nodeA
|
||||
parent.children[nodeB.index] = nodeB
|
||||
|
||||
-- Adjust line numbers
|
||||
nodeA.scope["start"].line = nodeA.scope["start"].line + nodeB_line_cnt + mid_line_cnt
|
||||
nodeA.scope["end"].line = nodeA.scope["end"].line + nodeB_line_cnt + mid_line_cnt
|
||||
nodeA.name_range["start"].line = nodeA.name_range["start"].line + nodeB_line_cnt + mid_line_cnt
|
||||
nodeA.name_range["end"].line = nodeA.name_range["end"].line + nodeB_line_cnt + mid_line_cnt
|
||||
|
||||
nodeB.scope["start"].line = nodeB.scope["start"].line - nodeA_line_cnt - mid_line_cnt
|
||||
nodeB.scope["end"].line = nodeB.scope["end"].line - nodeA_line_cnt - mid_line_cnt
|
||||
nodeB.name_range["start"].line = nodeB.name_range["start"].line - nodeA_line_cnt - mid_line_cnt
|
||||
nodeB.name_range["end"].line = nodeB.name_range["end"].line - nodeA_line_cnt - mid_line_cnt
|
||||
|
||||
-- Set lines
|
||||
vim.api.nvim_buf_set_lines(for_buf, start_line, start_line + nodeB_line_cnt, false, nodeB_text)
|
||||
vim.api.nvim_buf_set_lines(for_buf, start_line + nodeB_line_cnt, start_line + nodeB_line_cnt + mid_line_cnt, false, mid_text)
|
||||
vim.api.nvim_buf_set_lines(for_buf, start_line + nodeB_line_cnt + mid_line_cnt, start_line + nodeB_line_cnt + mid_line_cnt + nodeA_line_cnt, false, nodeA_text)
|
||||
end
|
||||
|
||||
function actions.move_down()
|
||||
local callback = function(display)
|
||||
if display.focus_node.next == nil then
|
||||
return
|
||||
end
|
||||
|
||||
swap_nodes(display.for_buf, display.focus_node, display.focus_node.next)
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move code block down"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.move_up()
|
||||
local callback = function(display)
|
||||
if display.focus_node.prev == nil then
|
||||
return
|
||||
end
|
||||
|
||||
swap_nodes(display.for_buf, display.focus_node.prev, display.focus_node)
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move code block up"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.toggle_preview()
|
||||
local callback = function(display)
|
||||
if vim.api.nvim_win_get_buf(display.right.winid) == display.right.bufnr then
|
||||
display:show_preview()
|
||||
else
|
||||
display:hide_preview()
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Show preview of current node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.vsplit()
|
||||
local callback = function(display)
|
||||
actions.close().callback(display)
|
||||
vim.api.nvim_command("vsplit")
|
||||
display.for_win = vim.api.nvim_get_current_win()
|
||||
actions.select().callback(display)
|
||||
vim.api.nvim_command("normal! zv")
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Open selected node in a vertical split"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.hsplit()
|
||||
local callback = function(display)
|
||||
actions.close().callback(display)
|
||||
vim.api.nvim_command("split")
|
||||
display.for_win = vim.api.nvim_get_current_win()
|
||||
actions.select().callback(display)
|
||||
vim.api.nvim_command("normal! zv")
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Open selected node in a horizontal split"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.telescope(opts)
|
||||
local callback = function(display)
|
||||
local status_ok, _ = pcall(require, "telescope")
|
||||
if not status_ok then
|
||||
vim.notify("telescope.nvim not found", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local navic = require("nvim-navic.lib")
|
||||
local pickers = require("telescope.pickers")
|
||||
local entry_display = require("telescope.pickers.entry_display")
|
||||
local finders = require("telescope.finders")
|
||||
local conf = require("telescope.config").values
|
||||
local t_actions = require("telescope.actions")
|
||||
local action_state = require("telescope.actions.state")
|
||||
|
||||
local displayer = entry_display.create({
|
||||
separator = " ",
|
||||
items = {
|
||||
{ width = 14 },
|
||||
{ remaining = true },
|
||||
},
|
||||
})
|
||||
|
||||
local function make_display(entry)
|
||||
local node = entry.value
|
||||
local kind = navic.adapt_lsp_num_to_str(node.kind)
|
||||
local kind_hl = "Navbuddy"..kind
|
||||
local name_hl = "NavbuddyNormalFloat"
|
||||
local columns = {
|
||||
{ string.lower(kind), kind_hl },
|
||||
{ node.name, name_hl},
|
||||
}
|
||||
return displayer(columns)
|
||||
end
|
||||
|
||||
local function make_entry(node)
|
||||
return {
|
||||
value = node,
|
||||
display = make_display,
|
||||
name = node.name,
|
||||
ordinal = string.lower(navic.adapt_lsp_num_to_str(node.kind)).." "..node.name,
|
||||
lnum = node.name_range["start"].line,
|
||||
col = node.name_range["start"].character,
|
||||
bufnr = display.for_buf,
|
||||
filename = vim.api.nvim_buf_get_name(display.for_buf),
|
||||
}
|
||||
end
|
||||
|
||||
display:close()
|
||||
pickers.new(opts, {
|
||||
prompt_title = "Fuzzy Search",
|
||||
finder = finders.new_table({
|
||||
results = display.focus_node.parent.children,
|
||||
entry_maker = make_entry
|
||||
}),
|
||||
sorter = conf.generic_sorter(opts),
|
||||
previewer = conf.qflist_previewer(opts),
|
||||
attach_mappings = function(prompt_bufnr, _)
|
||||
t_actions.select_default:replace(function()
|
||||
local selection = action_state.get_selected_entry()
|
||||
display.focus_node = selection.value
|
||||
t_actions.close(prompt_bufnr)
|
||||
end)
|
||||
t_actions.close:enhance({
|
||||
post = function()
|
||||
display = require("nvim-navbuddy.display"):new(display)
|
||||
end
|
||||
})
|
||||
return true
|
||||
end,
|
||||
}):find()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Fuzzy search current level with telescope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.help()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
|
||||
local nui_popup = require("nui.popup")
|
||||
|
||||
local help_popup = nui_popup({
|
||||
relative = "editor",
|
||||
position = display.config.window.position,
|
||||
size = display.config.window.size,
|
||||
enter = true,
|
||||
focusable = true,
|
||||
border = display.config.window.border,
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local function quit_help()
|
||||
help_popup:unmount()
|
||||
require("nvim-navbuddy.display"):new(display)
|
||||
end
|
||||
|
||||
help_popup:map("n", "q", quit_help)
|
||||
help_popup:map("n", "<esc>", quit_help)
|
||||
|
||||
help_popup:mount()
|
||||
|
||||
local max_keybinding_len = 0
|
||||
for k, _ in pairs(display.config.mappings) do
|
||||
max_keybinding_len = math.max(#k, max_keybinding_len)
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
for k, v in pairs(display.config.mappings) do
|
||||
local text = " " .. k .. string.rep(" ", max_keybinding_len - #k) .. " | " .. v.description
|
||||
table.insert(lines, text)
|
||||
end
|
||||
table.sort(lines)
|
||||
table.insert(lines, 1, " Navbuddy Mappings" .. string.rep(" ", math.max(1, vim.api.nvim_win_get_width(help_popup.winid) - 18*2)) .. "press 'q' to exit ")
|
||||
table.insert(lines, 2, string.rep("-", vim.api.nvim_win_get_width(help_popup.winid)))
|
||||
|
||||
vim.api.nvim_buf_set_option(help_popup.bufnr, "modifiable", true)
|
||||
vim.api.nvim_buf_set_lines(help_popup.bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_buf_set_option(help_popup.bufnr, "modifiable", false)
|
||||
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
help_popup.bufnr,
|
||||
-1,
|
||||
"NavbuddyFunction",
|
||||
0,
|
||||
0,
|
||||
-1
|
||||
)
|
||||
for i = 2, #lines do
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
help_popup.bufnr,
|
||||
-1,
|
||||
"NavbuddyKey",
|
||||
i - 1,
|
||||
0,
|
||||
max_keybinding_len + 3
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Show mappings"
|
||||
}
|
||||
end
|
||||
|
||||
return actions
|
||||
@ -0,0 +1,405 @@
|
||||
local navic = require("nvim-navic.lib")
|
||||
|
||||
local nui_popup = require("nui.popup")
|
||||
local nui_layout = require("nui.layout")
|
||||
local nui_text = require("nui.text")
|
||||
|
||||
local ui = require("nvim-navbuddy.ui")
|
||||
|
||||
local ns = vim.api.nvim_create_namespace("nvim-navbuddy")
|
||||
|
||||
local function clear_buffer(buf)
|
||||
vim.api.nvim_win_set_buf(buf.winid, buf.bufnr)
|
||||
|
||||
vim.api.nvim_win_set_option(buf.winid, "signcolumn", "no")
|
||||
vim.api.nvim_win_set_option(buf.winid, "foldlevel", 100)
|
||||
vim.api.nvim_win_set_option(buf.winid, "wrap", true)
|
||||
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", true)
|
||||
vim.api.nvim_buf_set_lines(buf.bufnr, 0, -1, false, {})
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", false)
|
||||
for _, extmark in ipairs(vim.api.nvim_buf_get_extmarks(buf.bufnr, ns, 0, -1, {})) do
|
||||
vim.api.nvim_buf_del_extmark(buf.bufnr, ns, extmark[1])
|
||||
end
|
||||
end
|
||||
|
||||
local function fill_buffer(buf, node, config)
|
||||
local cursor_pos = vim.api.nvim_win_get_cursor(buf.winid)
|
||||
clear_buffer(buf)
|
||||
|
||||
local parent = node.parent
|
||||
|
||||
local lines = {}
|
||||
for _, child_node in ipairs(parent.children) do
|
||||
local text = " " .. config.icons[child_node.kind] .. child_node.name
|
||||
table.insert(lines, text)
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", true)
|
||||
vim.api.nvim_buf_set_lines(buf.bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", false)
|
||||
|
||||
if cursor_pos[1] ~= node.index then
|
||||
cursor_pos[1] = node.index
|
||||
end
|
||||
|
||||
for i, child_node in ipairs(parent.children) do
|
||||
local hl_group = "Navbuddy" .. navic.adapt_lsp_num_to_str(child_node.kind)
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
buf.bufnr,
|
||||
ns,
|
||||
hl_group,
|
||||
i - 1,
|
||||
0,
|
||||
-1
|
||||
)
|
||||
if config.node_markers.enabled then
|
||||
vim.api.nvim_buf_set_extmark(buf.bufnr, ns, i - 1, #lines[i], {
|
||||
virt_text = { {
|
||||
child_node.children ~= nil and config.node_markers.icons.branch
|
||||
or i == cursor_pos[1] and config.node_markers.icons.leaf_selected
|
||||
or config.node_markers.icons.leaf,
|
||||
i == cursor_pos[1] and { "NavbuddyCursorLine", hl_group } or hl_group,
|
||||
} },
|
||||
virt_text_pos = "right_align",
|
||||
virt_text_hide = false,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_add_highlight(buf.bufnr, ns, "NavbuddyCursorLine", cursor_pos[1] - 1, 0, -1)
|
||||
vim.api.nvim_buf_set_extmark(buf.bufnr, ns, cursor_pos[1] - 1, #lines[cursor_pos[1]], {
|
||||
end_row = cursor_pos[1],
|
||||
hl_eol = true,
|
||||
hl_group = "NavbuddyCursorLine" .. navic.adapt_lsp_num_to_str(node.kind),
|
||||
})
|
||||
vim.api.nvim_win_set_cursor(buf.winid, cursor_pos)
|
||||
end
|
||||
|
||||
local display = {}
|
||||
|
||||
function display:new(obj)
|
||||
ui.highlight_setup(obj.config)
|
||||
|
||||
-- Object
|
||||
setmetatable(obj, self)
|
||||
self.__index = self
|
||||
|
||||
local config = obj.config
|
||||
|
||||
-- NUI elements
|
||||
local left_popup = nui_popup({
|
||||
focusable = false,
|
||||
border = config.window.sections.left.border or ui.get_border_chars(config.window.border, "left"),
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local mid_popup = nui_popup({
|
||||
enter = true,
|
||||
border = config.window.sections.mid.border or ui.get_border_chars(config.window.border, "mid"),
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
scrolloff = config.window.scrolloff
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local lsp_name = {
|
||||
bottom = nui_text("[" .. obj.lsp_name .. "]", "NavbuddyFloatBorder"),
|
||||
bottom_align = "right",
|
||||
}
|
||||
|
||||
if
|
||||
config.window.sections.right.border == "none"
|
||||
or config.window.border == "none"
|
||||
or config.window.sections.right.border == "shadow"
|
||||
or config.window.border == "shadow"
|
||||
or config.window.sections.right.border == "solid"
|
||||
or config.window.border == "solid"
|
||||
then
|
||||
lsp_name = nil
|
||||
end
|
||||
|
||||
local right_popup = nui_popup({
|
||||
focusable = false,
|
||||
border = {
|
||||
style = config.window.sections.right.border or ui.get_border_chars(config.window.border, "right"),
|
||||
text = lsp_name,
|
||||
},
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
scrolloff = 0,
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local layout = nui_layout(
|
||||
{
|
||||
relative = "editor",
|
||||
position = config.window.position,
|
||||
size = config.window.size,
|
||||
},
|
||||
nui_layout.Box({
|
||||
nui_layout.Box(left_popup, { size = config.window.sections.left.size }),
|
||||
nui_layout.Box(mid_popup, { size = config.window.sections.mid.size }),
|
||||
nui_layout.Box(right_popup, { grow = 1 }),
|
||||
}, { dir = "row" })
|
||||
)
|
||||
|
||||
obj.layout = layout
|
||||
obj.left = left_popup
|
||||
obj.mid = mid_popup
|
||||
obj.right = right_popup
|
||||
obj.state = {
|
||||
leaving_window_for_action = false,
|
||||
leaving_window_for_reorientation = false,
|
||||
closed = false,
|
||||
-- user_gui_cursor = nil,
|
||||
source_buffer_scrolloff = nil
|
||||
}
|
||||
|
||||
-- Set filetype
|
||||
vim.api.nvim_buf_set_option(obj.mid.bufnr, "filetype", "Navbuddy")
|
||||
|
||||
-- Hidden cursor
|
||||
if obj.state.user_gui_cursor == nil then
|
||||
obj.state.user_gui_cursor = vim.api.nvim_get_option("guicursor")
|
||||
end
|
||||
obj.state.user_gui_cursor = vim.api.nvim_get_option("guicursor")
|
||||
if obj.state.user_gui_cursor ~= "" then
|
||||
vim.api.nvim_set_option("guicursor", "a:NavbuddyCursor")
|
||||
end
|
||||
|
||||
-- User Scrolloff
|
||||
if config.source_buffer.scrolloff then
|
||||
obj.state.source_buffer_scrolloff = vim.api.nvim_get_option("scrolloff")
|
||||
vim.api.nvim_set_option("scrolloff", config.source_buffer.scrolloff)
|
||||
end
|
||||
|
||||
-- Autocmds
|
||||
local augroup = vim.api.nvim_create_augroup("Navbuddy", { clear = false })
|
||||
vim.api.nvim_clear_autocmds({ buffer = obj.mid.bufnr })
|
||||
vim.api.nvim_create_autocmd("CursorMoved", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
local cursor_pos = vim.api.nvim_win_get_cursor(obj.mid.winid)
|
||||
if obj.focus_node ~= obj.focus_node.parent.children[cursor_pos[1]] then
|
||||
obj.focus_node = obj.focus_node.parent.children[cursor_pos[1]]
|
||||
obj:redraw()
|
||||
end
|
||||
|
||||
obj.focus_node.parent.memory = obj.focus_node.index
|
||||
|
||||
obj:clear_highlights()
|
||||
obj:focus_range()
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufLeave", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
if
|
||||
obj.state.leaving_window_for_action == false
|
||||
and obj.state.leaving_window_for_reorientation == false
|
||||
and obj.state.closed == false
|
||||
then
|
||||
obj:close()
|
||||
end
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("CmdlineEnter", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
vim.api.nvim_set_option("guicursor", obj.state.user_gui_cursor)
|
||||
end
|
||||
})
|
||||
vim.api.nvim_create_autocmd("CmdlineLeave", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
if obj.state.user_gui_cursor ~= "" then
|
||||
vim.api.nvim_set_option("guicursor", "a:NavbuddyCursor")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Mappings
|
||||
for i, v in pairs(config.mappings) do
|
||||
obj.mid:map("n", i,
|
||||
function()
|
||||
v.callback(obj)
|
||||
end,
|
||||
{ nowait=true })
|
||||
end
|
||||
|
||||
-- Display
|
||||
layout:mount()
|
||||
obj:redraw()
|
||||
obj:focus_range()
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
function display:focus_range()
|
||||
local ranges = nil
|
||||
|
||||
if vim.deep_equal(self.focus_node.scope, self.focus_node.name_range) then
|
||||
ranges = { { "NavbuddyScope", self.focus_node.scope } }
|
||||
else
|
||||
ranges = { { "NavbuddyScope", self.focus_node.scope }, { "NavbuddyName", self.focus_node.name_range } }
|
||||
end
|
||||
|
||||
if self.config.source_buffer.highlight then
|
||||
for _, v in ipairs(ranges) do
|
||||
local highlight, range = unpack(v)
|
||||
|
||||
if range["start"].line == range["end"].line then
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
self.for_buf,
|
||||
ns,
|
||||
highlight,
|
||||
range["start"].line - 1,
|
||||
range["start"].character,
|
||||
range["end"].character
|
||||
)
|
||||
else
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
self.for_buf,
|
||||
ns,
|
||||
highlight,
|
||||
range["start"].line - 1,
|
||||
range["start"].character,
|
||||
-1
|
||||
)
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
self.for_buf,
|
||||
ns,
|
||||
highlight,
|
||||
range["end"].line - 1,
|
||||
0,
|
||||
range["end"].character
|
||||
)
|
||||
for i = range["start"].line, range["end"].line - 2, 1 do
|
||||
vim.api.nvim_buf_add_highlight(self.for_buf, ns, highlight, i, 0, -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.config.source_buffer.follow_node then
|
||||
self:reorient(self.for_win, self.config.source_buffer.reorient)
|
||||
end
|
||||
end
|
||||
|
||||
function display:reorient(ro_win, reorient_method)
|
||||
vim.api.nvim_win_set_cursor(ro_win, { self.focus_node.name_range["start"].line, self.focus_node.name_range["start"].character })
|
||||
|
||||
self.state.leaving_window_for_reorientation = true
|
||||
vim.api.nvim_set_current_win(ro_win)
|
||||
|
||||
if reorient_method == "smart" then
|
||||
local total_lines = self.focus_node.scope["end"].line - self.focus_node.scope["start"].line + 1
|
||||
|
||||
if total_lines >= vim.api.nvim_win_get_height(ro_win) then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
else
|
||||
local mid_line = bit.rshift(self.focus_node.scope["start"].line + self.focus_node.scope["end"].line, 1)
|
||||
vim.api.nvim_win_set_cursor(ro_win, { mid_line, 0 })
|
||||
vim.api.nvim_command("normal! zz")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
ro_win,
|
||||
{ self.focus_node.name_range["start"].line, self.focus_node.name_range["start"].character }
|
||||
)
|
||||
end
|
||||
elseif reorient_method == "mid" then
|
||||
vim.api.nvim_command("normal! zz")
|
||||
elseif reorient_method == "top" then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
end
|
||||
|
||||
vim.api.nvim_set_current_win(self.mid.winid)
|
||||
self.state.leaving_window_for_reorientation = false
|
||||
end
|
||||
|
||||
function display:show_preview()
|
||||
vim.api.nvim_win_set_buf(self.right.winid, self.for_buf)
|
||||
|
||||
vim.api.nvim_win_set_option(self.right.winid, 'winhighlight', 'Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder')
|
||||
vim.api.nvim_win_set_option(self.right.winid, "signcolumn", "no")
|
||||
vim.api.nvim_win_set_option(self.right.winid, "foldlevel", 100)
|
||||
vim.api.nvim_win_set_option(self.right.winid, "wrap", false)
|
||||
|
||||
self:reorient(self.right.winid, "smart")
|
||||
end
|
||||
|
||||
function display:hide_preview()
|
||||
vim.api.nvim_win_set_buf(self.right.winid, self.right.bufnr)
|
||||
local node = self.focus_node
|
||||
if node.children then
|
||||
if node.memory then
|
||||
fill_buffer(self.right, node.children[node.memory], self.config)
|
||||
else
|
||||
fill_buffer(self.right, node.children[1], self.config)
|
||||
end
|
||||
else
|
||||
clear_buffer(self.right)
|
||||
end
|
||||
end
|
||||
|
||||
function display:clear_highlights()
|
||||
vim.api.nvim_buf_clear_highlight(self.for_buf, ns, 0, -1)
|
||||
end
|
||||
|
||||
function display:redraw()
|
||||
local node = self.focus_node
|
||||
fill_buffer(self.mid, node, self.config)
|
||||
|
||||
local preview_method = self.config.window.sections.right.preview
|
||||
|
||||
if preview_method == "always" then
|
||||
self:show_preview()
|
||||
else
|
||||
if node.children then
|
||||
if node.memory then
|
||||
fill_buffer(self.right, node.children[node.memory], self.config)
|
||||
else
|
||||
fill_buffer(self.right, node.children[1], self.config)
|
||||
end
|
||||
else
|
||||
if preview_method == "leaf" then
|
||||
self:show_preview()
|
||||
else
|
||||
clear_buffer(self.right)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if node.parent.is_root then
|
||||
clear_buffer(self.left)
|
||||
else
|
||||
fill_buffer(self.left, node.parent, self.config)
|
||||
end
|
||||
end
|
||||
|
||||
function display:close()
|
||||
self.state.closed = true
|
||||
vim.api.nvim_set_option("guicursor", self.state.user_gui_cursor)
|
||||
if self.state.source_buffer_scrolloff then
|
||||
vim.api.nvim_set_option("scrolloff", self.state.source_buffer_scrolloff)
|
||||
end
|
||||
self.layout:unmount()
|
||||
self:clear_highlights()
|
||||
end
|
||||
|
||||
return display
|
||||
@ -0,0 +1,435 @@
|
||||
local navic = require("nvim-navic.lib")
|
||||
|
||||
local nui_menu = require("nui.menu")
|
||||
|
||||
local display = require("nvim-navbuddy.display")
|
||||
local actions = require("nvim-navbuddy.actions")
|
||||
|
||||
local config = {
|
||||
window = {
|
||||
border = "single",
|
||||
size = "60%",
|
||||
position = "50%",
|
||||
scrolloff = nil,
|
||||
sections = {
|
||||
left = {
|
||||
size = "20%",
|
||||
},
|
||||
mid = {
|
||||
size = "40%",
|
||||
},
|
||||
right = {
|
||||
preview = "leaf",
|
||||
},
|
||||
},
|
||||
},
|
||||
node_markers = {
|
||||
enabled = true,
|
||||
icons = {
|
||||
leaf = " ",
|
||||
leaf_selected = " → ",
|
||||
branch = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
[1] = " ", -- File
|
||||
[2] = " ", -- Module
|
||||
[3] = " ", -- Namespace
|
||||
[4] = " ", -- Package
|
||||
[5] = " ", -- Class
|
||||
[6] = " ", -- Method
|
||||
[7] = " ", -- Property
|
||||
[8] = " ", -- Field
|
||||
[9] = " ", -- Constructor
|
||||
[10] = "", -- Enum
|
||||
[11] = "", -- Interface
|
||||
[12] = " ", -- Function
|
||||
[13] = " ", -- Variable
|
||||
[14] = " ", -- Constant
|
||||
[15] = " ", -- String
|
||||
[16] = " ", -- Number
|
||||
[17] = "◩ ", -- Boolean
|
||||
[18] = " ", -- Array
|
||||
[19] = " ", -- Object
|
||||
[20] = " ", -- Key
|
||||
[21] = " ", -- Null
|
||||
[22] = " ", -- EnumMember
|
||||
[23] = " ", -- Struct
|
||||
[24] = " ", -- Event
|
||||
[25] = " ", -- Operator
|
||||
[26] = " ", -- TypeParameter
|
||||
[255] = " ", -- Macro
|
||||
},
|
||||
use_default_mappings = true,
|
||||
mappings = {
|
||||
["<esc>"] = actions.close(),
|
||||
["q"] = actions.close(),
|
||||
|
||||
["j"] = actions.next_sibling(),
|
||||
["k"] = actions.previous_sibling(),
|
||||
|
||||
["h"] = actions.parent(),
|
||||
["l"] = actions.children(),
|
||||
["0"] = actions.root(),
|
||||
|
||||
["v"] = actions.visual_name(),
|
||||
["V"] = actions.visual_scope(),
|
||||
|
||||
["y"] = actions.yank_name(),
|
||||
["Y"] = actions.yank_scope(),
|
||||
|
||||
["i"] = actions.insert_name(),
|
||||
["I"] = actions.insert_scope(),
|
||||
|
||||
["a"] = actions.append_name(),
|
||||
["A"] = actions.append_scope(),
|
||||
|
||||
["r"] = actions.rename(),
|
||||
|
||||
["d"] = actions.delete(),
|
||||
|
||||
["f"] = actions.fold_create(),
|
||||
["F"] = actions.fold_delete(),
|
||||
|
||||
["c"] = actions.comment(),
|
||||
|
||||
["<enter>"] = actions.select(),
|
||||
["o"] = actions.select(),
|
||||
|
||||
["J"] = actions.move_down(),
|
||||
["K"] = actions.move_up(),
|
||||
|
||||
["s"] = actions.toggle_preview(),
|
||||
|
||||
["<C-v>"] = actions.vsplit(),
|
||||
["<C-s>"] = actions.hsplit(),
|
||||
|
||||
["t"] = actions.telescope({
|
||||
layout_strategy = "horizontal",
|
||||
layout_config = {
|
||||
height = 0.60,
|
||||
width = 0.60,
|
||||
prompt_position = "top",
|
||||
preview_width = 0.50,
|
||||
},
|
||||
}),
|
||||
|
||||
["g?"] = actions.help(),
|
||||
},
|
||||
lsp = {
|
||||
auto_attach = false,
|
||||
preference = nil,
|
||||
},
|
||||
source_buffer = {
|
||||
follow_node = true,
|
||||
highlight = true,
|
||||
reorient = "smart",
|
||||
scrolloff = nil,
|
||||
},
|
||||
custom_hl_group = nil,
|
||||
}
|
||||
|
||||
setmetatable(config.icons, {
|
||||
__index = function()
|
||||
return "? "
|
||||
end,
|
||||
})
|
||||
|
||||
local navbuddy_attached_clients = {}
|
||||
|
||||
-- @Private Methods
|
||||
|
||||
local function choose_lsp_menu(for_buf, make_request)
|
||||
local style = nil
|
||||
|
||||
if config.window.border ~= nil and config.window.border ~= "None" then
|
||||
style = config.window.border
|
||||
else
|
||||
style = "single"
|
||||
end
|
||||
|
||||
local min_width = 23
|
||||
local lines = {}
|
||||
|
||||
for _, v in ipairs(navbuddy_attached_clients[for_buf]) do
|
||||
min_width = math.max(min_width, #v.name)
|
||||
table.insert(lines, nui_menu.item(v.id .. ":" .. v.name))
|
||||
end
|
||||
|
||||
local min_height = #lines
|
||||
|
||||
local menu = nui_menu({
|
||||
relative = "editor",
|
||||
position = "50%",
|
||||
border = {
|
||||
style = style,
|
||||
text = {
|
||||
top = "[Choose LSP Client]",
|
||||
top_align = "center",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
lines = lines,
|
||||
min_width = min_width,
|
||||
min_height = min_height,
|
||||
keymap = {
|
||||
focus_next = { "j", "<Down>", "<Tab>" },
|
||||
focus_prev = { "k", "<Up>", "<S-Tab>" },
|
||||
close = { "<Esc>", "q", "<C-c>" },
|
||||
submit = { "<CR>", "<Space>", "l" },
|
||||
},
|
||||
on_close = function() end,
|
||||
on_submit = function(item)
|
||||
local id = tonumber(string.match(item.text, "%d+"))
|
||||
for _, check_client in ipairs(navbuddy_attached_clients[for_buf]) do
|
||||
if id == check_client.id then
|
||||
make_request(check_client)
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
menu:mount()
|
||||
end
|
||||
|
||||
local function request(for_buf, handler)
|
||||
local function make_request(client)
|
||||
navic.request_symbol(for_buf, function(bufnr, symbols)
|
||||
navic.update_data(bufnr, symbols)
|
||||
navic.update_context(bufnr)
|
||||
local context_data = navic.get_context_data(bufnr)
|
||||
|
||||
local curr_node = context_data[#context_data]
|
||||
|
||||
handler(for_buf, curr_node, client.name)
|
||||
end, client)
|
||||
end
|
||||
|
||||
if navbuddy_attached_clients[for_buf] == nil then
|
||||
vim.notify("No lsp servers attached", vim.log.levels.ERROR)
|
||||
elseif #navbuddy_attached_clients[for_buf] == 1 then
|
||||
make_request(navbuddy_attached_clients[for_buf][1])
|
||||
elseif config.lsp.preference ~= nil then
|
||||
local found = false
|
||||
|
||||
for _, preferred_lsp in ipairs(config.lsp.preference) do
|
||||
for _, attached_lsp in ipairs(navbuddy_attached_clients[for_buf]) do
|
||||
if preferred_lsp == attached_lsp.name then
|
||||
navbuddy_attached_clients[for_buf] = { attached_lsp }
|
||||
found = true
|
||||
make_request(attached_lsp)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if found then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
choose_lsp_menu(for_buf, make_request)
|
||||
end
|
||||
else
|
||||
choose_lsp_menu(for_buf, make_request)
|
||||
end
|
||||
end
|
||||
|
||||
local function handler(bufnr, curr_node, lsp_name)
|
||||
if curr_node.is_root then
|
||||
if curr_node.children then
|
||||
local curr_line = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local closest_dist = math.abs(curr_line - curr_node.children[1].scope["start"].line)
|
||||
local closest_node = curr_node.children[1]
|
||||
|
||||
for _, node in ipairs(curr_node.children) do
|
||||
if math.abs(curr_line - node.scope["start"].line) < closest_dist then
|
||||
closest_dist = math.abs(curr_line - node.scope["start"].line)
|
||||
closest_node = node
|
||||
end
|
||||
end
|
||||
|
||||
curr_node = closest_node
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
display:new({
|
||||
for_buf = bufnr,
|
||||
for_win = vim.api.nvim_get_current_win(),
|
||||
start_cursor = vim.api.nvim_win_get_cursor(vim.api.nvim_get_current_win()),
|
||||
focus_node = curr_node,
|
||||
config = config,
|
||||
lsp_name = lsp_name,
|
||||
})
|
||||
end
|
||||
|
||||
-- @Public Methods
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.open(bufnr)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
request(bufnr, handler)
|
||||
end
|
||||
|
||||
function M.attach(client, bufnr)
|
||||
if not client.server_capabilities.documentSymbolProvider then
|
||||
if not vim.g.navbuddy_silence then
|
||||
vim.notify(
|
||||
'nvim-navbuddy: Server "' .. client.name .. '" does not support documentSymbols.',
|
||||
vim.log.levels.ERROR
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if navbuddy_attached_clients[bufnr] == nil then
|
||||
navbuddy_attached_clients[bufnr] = {}
|
||||
end
|
||||
|
||||
-- Check if already attached
|
||||
for _, c in ipairs(navbuddy_attached_clients[bufnr]) do
|
||||
if c.id == client.id then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Check for stopped lsp servers
|
||||
for i, c in ipairs(navbuddy_attached_clients[bufnr]) do
|
||||
if c.is_stopped then
|
||||
table.remove(navbuddy_attached_clients[bufnr], i)
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(navbuddy_attached_clients[bufnr], client)
|
||||
|
||||
local navbuddy_augroup = vim.api.nvim_create_augroup("navbuddy", { clear = false })
|
||||
vim.api.nvim_clear_autocmds({
|
||||
buffer = bufnr,
|
||||
group = navbuddy_augroup,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufDelete", {
|
||||
callback = function()
|
||||
navic.clear_buffer_data(bufnr)
|
||||
navbuddy_attached_clients[bufnr] = nil
|
||||
end,
|
||||
group = navbuddy_augroup,
|
||||
buffer = bufnr,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("LspDetach", {
|
||||
callback = function()
|
||||
if navbuddy_attached_clients[bufnr] ~= nil then
|
||||
for i, c in ipairs(navbuddy_attached_clients[bufnr]) do
|
||||
if c.id == client.id then
|
||||
table.remove(navbuddy_attached_clients[bufnr], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
if #navbuddy_attached_clients[bufnr] == 0 then
|
||||
navbuddy_attached_clients[bufnr] = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
group = navbuddy_augroup,
|
||||
buffer = bufnr,
|
||||
})
|
||||
|
||||
vim.api.nvim_buf_create_user_command(bufnr, "Navbuddy", function()
|
||||
M.open(bufnr)
|
||||
end, {})
|
||||
end
|
||||
|
||||
function M.setup(user_config)
|
||||
if user_config ~= nil then
|
||||
if user_config.window ~= nil then
|
||||
config.window = vim.tbl_deep_extend("keep", user_config.window, config.window)
|
||||
end
|
||||
|
||||
-- If one is set, default for others should be none
|
||||
if
|
||||
config.window.sections.left.border ~= nil
|
||||
or config.window.sections.mid.border ~= nil
|
||||
or config.window.sections.right.border ~= nil
|
||||
then
|
||||
config.window.sections.left.border = config.window.sections.left.border or "none"
|
||||
config.window.sections.mid.border = config.window.sections.mid.border or "none"
|
||||
config.window.sections.right.border = config.window.sections.right.border or "none"
|
||||
end
|
||||
|
||||
if user_config.node_markers ~= nil then
|
||||
config.node_markers = vim.tbl_deep_extend("keep", user_config.node_markers, config.node_markers)
|
||||
end
|
||||
|
||||
if user_config.icons ~= nil then
|
||||
for k, v in pairs(user_config.icons) do
|
||||
if navic.adapt_lsp_str_to_num(k) then
|
||||
config.icons[navic.adapt_lsp_str_to_num(k)] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if user_config.use_default_mappings ~= nil then
|
||||
config.use_default_mappings = user_config.use_default_mappings
|
||||
end
|
||||
|
||||
if user_config.mappings ~= nil then
|
||||
if config.use_default_mappings then
|
||||
config.mappings = vim.tbl_deep_extend("keep", user_config.mappings, config.mappings)
|
||||
else
|
||||
config.mappings = user_config.mappings
|
||||
end
|
||||
end
|
||||
|
||||
if user_config.lsp ~= nil then
|
||||
config.lsp = vim.tbl_deep_extend("keep", user_config.lsp, config.lsp)
|
||||
end
|
||||
|
||||
if user_config.source_buffer ~= nil then
|
||||
config.source_buffer = vim.tbl_deep_extend("keep", user_config.source_buffer, config.source_buffer)
|
||||
end
|
||||
|
||||
if user_config.custom_hl_group ~= nil then
|
||||
config.custom_hl_group = user_config.custom_hl_group
|
||||
end
|
||||
end
|
||||
|
||||
if config.lsp.auto_attach == true then
|
||||
local navbuddy_augroup = vim.api.nvim_create_augroup("navbuddy", { clear = false })
|
||||
vim.api.nvim_clear_autocmds({
|
||||
group = navbuddy_augroup,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("LspAttach", {
|
||||
callback = function(args)
|
||||
local bufnr = args.buf
|
||||
if args.data == nil and args.data.client_id == nil then
|
||||
return
|
||||
end
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id)
|
||||
if not client.server_capabilities.documentSymbolProvider then
|
||||
return
|
||||
end
|
||||
M.attach(client, bufnr)
|
||||
end,
|
||||
})
|
||||
|
||||
--- Attach to already active clients.
|
||||
local all_clients = vim.lsp.get_clients()
|
||||
|
||||
local supported_clients = vim.tbl_filter(function(client)
|
||||
return client.server_capabilities.documentSymbolProvider
|
||||
end, all_clients)
|
||||
|
||||
for _, client in ipairs(supported_clients) do
|
||||
local buffers_of_client = vim.lsp.get_buffers_by_client_id(client.id)
|
||||
|
||||
for _, buffer_number in ipairs(buffers_of_client) do
|
||||
M.attach(client, buffer_number)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,196 @@
|
||||
local navic = require("nvim-navic.lib")
|
||||
|
||||
local ui = {}
|
||||
|
||||
function ui.get_border_chars(style, section)
|
||||
if style ~= "single" and style ~= "rounded" and style ~= "double" and style ~= "solid" then
|
||||
return style
|
||||
end
|
||||
|
||||
-- stylua: ignore
|
||||
local border_chars = {
|
||||
top_left = {
|
||||
single = "┌",
|
||||
rounded = "╭",
|
||||
double = "╔",
|
||||
solid = "▛",
|
||||
},
|
||||
top = {
|
||||
single = "─",
|
||||
rounded = "─",
|
||||
double = "═",
|
||||
solid = "▀",
|
||||
},
|
||||
top_right = {
|
||||
single = "┐",
|
||||
rounded = "╮",
|
||||
double = "╗",
|
||||
solid = "▜",
|
||||
},
|
||||
right = {
|
||||
single = "│",
|
||||
rounded = "│",
|
||||
double = "║",
|
||||
solid = "▐",
|
||||
},
|
||||
bottom_right = {
|
||||
single = "┘",
|
||||
rounded = "╯",
|
||||
double = "╝",
|
||||
solid = "▟",
|
||||
},
|
||||
bottom = {
|
||||
single = "─",
|
||||
rounded = "─",
|
||||
double = "═",
|
||||
solid = "▄",
|
||||
},
|
||||
bottom_left = {
|
||||
single = "└",
|
||||
rounded = "╰",
|
||||
double = "╚",
|
||||
solid = "▙",
|
||||
},
|
||||
left = {
|
||||
single = "│",
|
||||
rounded = "│",
|
||||
double = "║",
|
||||
solid = "▌",
|
||||
},
|
||||
top_T = {
|
||||
single = "┬",
|
||||
rounded = "┬",
|
||||
double = "╦",
|
||||
solid = "▛",
|
||||
},
|
||||
bottom_T = {
|
||||
single = "┴",
|
||||
rounded = "┴",
|
||||
double = "╩",
|
||||
solid = "▙",
|
||||
},
|
||||
blank = "",
|
||||
}
|
||||
|
||||
local border_chars_map = {
|
||||
left = {
|
||||
style = {
|
||||
border_chars.top_left[style],
|
||||
border_chars.top[style],
|
||||
border_chars.top[style],
|
||||
border_chars.blank,
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom_left[style],
|
||||
border_chars.left[style],
|
||||
},
|
||||
},
|
||||
mid = {
|
||||
style = {
|
||||
border_chars.top_T[style],
|
||||
border_chars.top[style],
|
||||
border_chars.top[style],
|
||||
border_chars.blank,
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom_T[style],
|
||||
border_chars.left[style],
|
||||
},
|
||||
},
|
||||
right = {
|
||||
border_chars.top_T[style],
|
||||
border_chars.top[style],
|
||||
border_chars.top_right[style],
|
||||
border_chars.right[style],
|
||||
border_chars.bottom_right[style],
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom_T[style],
|
||||
border_chars.left[style],
|
||||
},
|
||||
}
|
||||
return border_chars_map[section]
|
||||
end
|
||||
|
||||
function ui.highlight_setup(config)
|
||||
for lsp_num = 1, 26 do
|
||||
local navbuddy_ok, _ =
|
||||
pcall(vim.api.nvim_get_hl_by_name, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), false)
|
||||
local navic_ok, navic_hl =
|
||||
pcall(vim.api.nvim_get_hl_by_name, "NavicIcons" .. navic.adapt_lsp_num_to_str(lsp_num), true)
|
||||
|
||||
if not navbuddy_ok and navic_ok then
|
||||
navic_hl = navic_hl["foreground"]
|
||||
|
||||
vim.api.nvim_set_hl(0, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), {
|
||||
fg = navic_hl,
|
||||
})
|
||||
end
|
||||
|
||||
local ok, navbuddy_hl =
|
||||
pcall(vim.api.nvim_get_hl_by_name, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), true)
|
||||
if ok then
|
||||
navbuddy_hl = navbuddy_hl["foreground"]
|
||||
|
||||
local highlight
|
||||
if config.custom_hl_group ~= nil then
|
||||
highlight = { link = config.custom_hl_group }
|
||||
else
|
||||
highlight = { bg = navbuddy_hl }
|
||||
end
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursorLine" .. navic.adapt_lsp_num_to_str(lsp_num), highlight)
|
||||
else
|
||||
local _, normal_hl = pcall(vim.api.nvim_get_hl_by_name, "Normal", true)
|
||||
normal_hl = normal_hl["foreground"]
|
||||
vim.api.nvim_set_hl(0, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), { fg = normal_hl })
|
||||
|
||||
local highlight
|
||||
if config.custom_hl_group ~= nil then
|
||||
highlight = { link = config.custom_hl_group }
|
||||
else
|
||||
highlight = { bg = normal_hl }
|
||||
end
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursorLine" .. navic.adapt_lsp_num_to_str(lsp_num), highlight)
|
||||
end
|
||||
end
|
||||
|
||||
local ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyCursorLine", false)
|
||||
if not ok then
|
||||
local highlight
|
||||
if config.custom_hl_group ~= nil then
|
||||
highlight = { link = config.custom_hl_group }
|
||||
else
|
||||
highlight = { reverse = true, bold = true }
|
||||
end
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursorLine", highlight)
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyCursor", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursor", {
|
||||
bg = "#000000",
|
||||
blend = 100,
|
||||
})
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyName", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyName", { link = "IncSearch" })
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyScope", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyScope", { link = "Visual" })
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyFloatBorder", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyFloatBorder", { link = "FloatBorder" })
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyNormalFloat", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyNormalFloat", { link = "NormalFloat" })
|
||||
end
|
||||
end
|
||||
|
||||
return ui
|
||||
Reference in New Issue
Block a user