feat: Implement window picker. (#340)
This commit is contained in:
parent
4706b74938
commit
10c686f7df
@ -37,6 +37,7 @@ let g:nvim_tree_hijack_netrw = 0 "1 by default, prevents netrw from automaticall
|
|||||||
let g:nvim_tree_add_trailing = 1 "0 by default, append a trailing slash to folder names
|
let g:nvim_tree_add_trailing = 1 "0 by default, append a trailing slash to folder names
|
||||||
let g:nvim_tree_group_empty = 1 " 0 by default, compact folders that only contain a single folder into one node in the file tree
|
let g:nvim_tree_group_empty = 1 " 0 by default, compact folders that only contain a single folder into one node in the file tree
|
||||||
let g:nvim_tree_lsp_diagnostics = 1 "0 by default, will show lsp diagnostics in the signcolumn. See :help nvim_tree_lsp_diagnostics
|
let g:nvim_tree_lsp_diagnostics = 1 "0 by default, will show lsp diagnostics in the signcolumn. See :help nvim_tree_lsp_diagnostics
|
||||||
|
let g:nvim_tree_disable_window_picker = 1 "0 by default, will disable the window picker.
|
||||||
let g:nvim_tree_special_files = [ 'README.md', 'Makefile', 'MAKEFILE' ] " List of filenames that gets highlighted with NvimTreeSpecialFile
|
let g:nvim_tree_special_files = [ 'README.md', 'Makefile', 'MAKEFILE' ] " List of filenames that gets highlighted with NvimTreeSpecialFile
|
||||||
let g:nvim_tree_show_icons = {
|
let g:nvim_tree_show_icons = {
|
||||||
\ 'git': 1,
|
\ 'git': 1,
|
||||||
|
|||||||
@ -127,6 +127,12 @@ You can set icons for:
|
|||||||
\ 'empty_open': "",
|
\ 'empty_open': "",
|
||||||
\ 'symlink': "",
|
\ 'symlink': "",
|
||||||
\ 'symlink_open': "",
|
\ 'symlink_open': "",
|
||||||
|
\ },
|
||||||
|
\ 'lsp': {
|
||||||
|
\ 'hint': "",
|
||||||
|
\ 'info': "",
|
||||||
|
\ 'warning': "",
|
||||||
|
\ 'error': "",
|
||||||
\ }
|
\ }
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
@ -243,7 +249,17 @@ default table is
|
|||||||
["README.md"] = true,
|
["README.md"] = true,
|
||||||
["readme.md"] = true,
|
["readme.md"] = true,
|
||||||
}
|
}
|
||||||
<
|
|
||||||
|
|
||||||
|
|g:nvim_tree_disable_window_picker| *g:nvim_tree_disable_window_picker*
|
||||||
|
|
||||||
|
Can be 0 or 1. When 1, will disable the window picker. Files will open in the
|
||||||
|
window from which you last opened NvimTree.
|
||||||
|
|
||||||
|
|g:nvim_tree_window_picker_chars| *g:nvim_tree_window_picker_chars*
|
||||||
|
|
||||||
|
A string of chars used as identifiers by the window picker.
|
||||||
|
`"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"` by default.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
INFORMATIONS *nvim-tree-info*
|
INFORMATIONS *nvim-tree-info*
|
||||||
|
|||||||
@ -45,7 +45,9 @@ local function get_hl_groups()
|
|||||||
GitStaged = { fg = colors.green },
|
GitStaged = { fg = colors.green },
|
||||||
GitMerge = { fg = colors.orange },
|
GitMerge = { fg = colors.orange },
|
||||||
GitRenamed = { fg = colors.purple },
|
GitRenamed = { fg = colors.purple },
|
||||||
GitNew = { fg = colors.yellow }
|
GitNew = { fg = colors.yellow },
|
||||||
|
|
||||||
|
WindowPicker = { gui = "bold", fg = "#ededed", bg = "#4493c8" }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -84,7 +86,8 @@ function M.setup()
|
|||||||
for k, d in pairs(higlight_groups) do
|
for k, d in pairs(higlight_groups) do
|
||||||
local gui = d.gui and ' gui='..d.gui or ''
|
local gui = d.gui and ' gui='..d.gui or ''
|
||||||
local fg = d.fg and ' guifg='..d.fg or ''
|
local fg = d.fg and ' guifg='..d.fg or ''
|
||||||
api.nvim_command('hi def NvimTree'..k..gui..fg)
|
local bg = d.bg and ' guibg='..d.bg or ''
|
||||||
|
api.nvim_command('hi def NvimTree'..k..gui..fg..bg)
|
||||||
end
|
end
|
||||||
|
|
||||||
local links = get_links()
|
local links = get_links()
|
||||||
|
|||||||
@ -11,23 +11,15 @@ local clipboard = {
|
|||||||
copy = {}
|
copy = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
local function clear_prompt()
|
|
||||||
vim.api.nvim_command('normal :esc<CR>')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function refresh_tree()
|
local function refresh_tree()
|
||||||
vim.api.nvim_command(":NvimTreeRefresh")
|
vim.api.nvim_command(":NvimTreeRefresh")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_user_input()
|
|
||||||
return vim.fn.nr2char(vim.fn.getchar())
|
|
||||||
end
|
|
||||||
|
|
||||||
local function create_file(file)
|
local function create_file(file)
|
||||||
if luv.fs_access(file, "r") ~= false then
|
if luv.fs_access(file, "r") ~= false then
|
||||||
print(file..' already exists. Overwrite? y/n')
|
print(file..' already exists. Overwrite? y/n')
|
||||||
local ans = get_user_input()
|
local ans = utils.get_user_input_char()
|
||||||
clear_prompt()
|
utils.clear_prompt()
|
||||||
if ans ~= "y" then
|
if ans ~= "y" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -71,7 +63,7 @@ function M.create(node)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local ans = vim.fn.input('Create file '..add_into)
|
local ans = vim.fn.input('Create file '..add_into)
|
||||||
clear_prompt()
|
utils.clear_prompt()
|
||||||
if not ans or #ans == 0 then return end
|
if not ans or #ans == 0 then return end
|
||||||
|
|
||||||
if not ans:match(utils.path_separator) then
|
if not ans:match(utils.path_separator) then
|
||||||
@ -171,8 +163,8 @@ local function do_single_paste(source, dest, action_type, action_fn)
|
|||||||
|
|
||||||
if dest_stats then
|
if dest_stats then
|
||||||
print(dest..' already exists. Overwrite? y/n/r(ename)')
|
print(dest..' already exists. Overwrite? y/n/r(ename)')
|
||||||
local ans = get_user_input()
|
local ans = utils.get_user_input_char()
|
||||||
clear_prompt()
|
utils.clear_prompt()
|
||||||
should_process = ans:match('^y')
|
should_process = ans:match('^y')
|
||||||
should_rename = ans:match('^r')
|
should_rename = ans:match('^r')
|
||||||
end
|
end
|
||||||
@ -232,8 +224,8 @@ function M.remove(node)
|
|||||||
if node.name == '..' then return end
|
if node.name == '..' then return end
|
||||||
|
|
||||||
print("Remove " ..node.name.. " ? y/n")
|
print("Remove " ..node.name.. " ? y/n")
|
||||||
local ans = get_user_input()
|
local ans = utils.get_user_input_char()
|
||||||
clear_prompt()
|
utils.clear_prompt()
|
||||||
if ans:match('^y') then
|
if ans:match('^y') then
|
||||||
if node.entries ~= nil then
|
if node.entries ~= nil then
|
||||||
local success = remove_dir(node.absolute_path)
|
local success = remove_dir(node.absolute_path)
|
||||||
@ -261,7 +253,7 @@ function M.rename(with_sub)
|
|||||||
local namelen = node.name:len()
|
local namelen = node.name:len()
|
||||||
local abs_path = with_sub and node.absolute_path:sub(0, namelen * (-1) -1) or node.absolute_path
|
local abs_path = with_sub and node.absolute_path:sub(0, namelen * (-1) -1) or node.absolute_path
|
||||||
local new_name = vim.fn.input("Rename " ..node.name.. " to ", abs_path)
|
local new_name = vim.fn.input("Rename " ..node.name.. " to ", abs_path)
|
||||||
clear_prompt()
|
utils.clear_prompt()
|
||||||
if not new_name or #new_name == 0 then return end
|
if not new_name or #new_name == 0 then return end
|
||||||
|
|
||||||
local success = luv.fs_rename(node.absolute_path, new_name)
|
local success = luv.fs_rename(node.absolute_path, new_name)
|
||||||
|
|||||||
@ -213,10 +213,91 @@ function M.set_index_and_redraw(fname)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Get user to pick a window. Selectable windows are all windows in the current
|
||||||
|
---tabpage that aren't NvimTree.
|
||||||
|
---@return integer|nil -- If a valid window was picked, return its id. If an
|
||||||
|
--- invalid window was picked / user canceled, return nil. If there are
|
||||||
|
--- no selectable windows, return -1.
|
||||||
|
function M.pick_window()
|
||||||
|
local tabpage = api.nvim_get_current_tabpage()
|
||||||
|
local win_ids = api.nvim_tabpage_list_wins(tabpage)
|
||||||
|
local tree_winid = view.View.tabpages[tabpage]
|
||||||
|
|
||||||
|
local selectable = vim.tbl_filter(function (id)
|
||||||
|
return id ~= tree_winid
|
||||||
|
end, win_ids)
|
||||||
|
|
||||||
|
-- If there are no selectable windows: return. If there's only 1, return it without picking.
|
||||||
|
if #selectable == 0 then return -1 end
|
||||||
|
if #selectable == 1 then return selectable[1] end
|
||||||
|
|
||||||
|
local chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
|
if vim.g.nvim_tree_window_picker_chars then
|
||||||
|
chars = tostring(vim.g.nvim_tree_window_picker_chars):upper()
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
local win_opts = {}
|
||||||
|
local win_map = {}
|
||||||
|
local laststatus = vim.o.laststatus
|
||||||
|
vim.o.laststatus = 2
|
||||||
|
|
||||||
|
-- Setup UI
|
||||||
|
for _, id in ipairs(selectable) do
|
||||||
|
local char = chars:sub(i, i)
|
||||||
|
local _, statusline = pcall(api.nvim_win_get_option, id, "statusline")
|
||||||
|
local _, winhl = pcall(api.nvim_win_get_option, id, "winhl")
|
||||||
|
|
||||||
|
win_opts[id] = {
|
||||||
|
statusline = statusline or "",
|
||||||
|
winhl = winhl or ""
|
||||||
|
}
|
||||||
|
win_map[char] = id
|
||||||
|
|
||||||
|
api.nvim_win_set_option(id, "statusline", "%=" .. char .. "%=")
|
||||||
|
api.nvim_win_set_option(
|
||||||
|
id, "winhl", "StatusLine:NvimTreeWindowPicker,StatusLineNC:NvimTreeWindowPicker"
|
||||||
|
)
|
||||||
|
|
||||||
|
i = i + 1
|
||||||
|
if i > #chars then break end
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.cmd("redraw")
|
||||||
|
print("Pick window: ")
|
||||||
|
local _, resp = pcall(utils.get_user_input_char)
|
||||||
|
resp = (resp or ""):upper()
|
||||||
|
utils.clear_prompt()
|
||||||
|
|
||||||
|
-- Restore window options
|
||||||
|
for _, id in ipairs(selectable) do
|
||||||
|
for opt, value in pairs(win_opts[id]) do
|
||||||
|
api.nvim_win_set_option(id, opt, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.o.laststatus = laststatus
|
||||||
|
|
||||||
|
return win_map[resp]
|
||||||
|
end
|
||||||
|
|
||||||
function M.open_file(mode, filename)
|
function M.open_file(mode, filename)
|
||||||
local tabpage = api.nvim_get_current_tabpage()
|
local tabpage = api.nvim_get_current_tabpage()
|
||||||
local win_ids = api.nvim_tabpage_list_wins(tabpage)
|
local win_ids = api.nvim_tabpage_list_wins(tabpage)
|
||||||
local target_winid = M.Tree.target_winid
|
|
||||||
|
local target_winid
|
||||||
|
if vim.g.nvim_tree_disable_window_picker == 1 then
|
||||||
|
target_winid = M.Tree.target_winid
|
||||||
|
else
|
||||||
|
target_winid = M.pick_window()
|
||||||
|
end
|
||||||
|
|
||||||
|
if target_winid == -1 then
|
||||||
|
target_winid = M.Tree.target_winid
|
||||||
|
elseif target_winid == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local do_split = mode == "split" or mode == "vsplit"
|
local do_split = mode == "split" or mode == "vsplit"
|
||||||
local vertical = mode ~= "split"
|
local vertical = mode ~= "split"
|
||||||
|
|
||||||
@ -235,7 +316,7 @@ function M.open_file(mode, filename)
|
|||||||
if not target_winid or not vim.tbl_contains(win_ids, target_winid) then
|
if not target_winid or not vim.tbl_contains(win_ids, target_winid) then
|
||||||
-- Target is invalid, or window does not exist in current tabpage: create
|
-- Target is invalid, or window does not exist in current tabpage: create
|
||||||
-- new window
|
-- new window
|
||||||
api.nvim_command(window_opts.split_command .. " vsp")
|
vim.cmd(window_opts.split_command .. " vsp")
|
||||||
target_winid = api.nvim_get_current_win()
|
target_winid = api.nvim_get_current_win()
|
||||||
M.Tree.target_winid = target_winid
|
M.Tree.target_winid = target_winid
|
||||||
|
|
||||||
@ -259,7 +340,7 @@ function M.open_file(mode, filename)
|
|||||||
|
|
||||||
cmd = cmd .. vim.fn.fnameescape(filename)
|
cmd = cmd .. vim.fn.fnameescape(filename)
|
||||||
api.nvim_set_current_win(target_winid)
|
api.nvim_set_current_win(target_winid)
|
||||||
api.nvim_command(cmd)
|
vim.cmd(cmd)
|
||||||
view.resize()
|
view.resize()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -280,7 +361,7 @@ function M.change_dir(foldername)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
api.nvim_command('cd '..foldername)
|
vim.cmd('cd '..foldername)
|
||||||
M.Tree.entries = {}
|
M.Tree.entries = {}
|
||||||
M.init(false, true)
|
M.init(false, true)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -65,6 +65,18 @@ end
|
|||||||
|
|
||||||
M.path_separator = path_separator
|
M.path_separator = path_separator
|
||||||
|
|
||||||
|
function M.clear_prompt()
|
||||||
|
vim.api.nvim_command('normal :esc<CR>')
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get_user_input_char()
|
||||||
|
local c = vim.fn.getchar()
|
||||||
|
while type(c) ~= "number" do
|
||||||
|
c = vim.fn.getchar()
|
||||||
|
end
|
||||||
|
return vim.fn.nr2char(c)
|
||||||
|
end
|
||||||
|
|
||||||
-- get the node from the tree that matches the predicate
|
-- get the node from the tree that matches the predicate
|
||||||
-- @param nodes list of node
|
-- @param nodes list of node
|
||||||
-- @param fn function(node): boolean
|
-- @param fn function(node): boolean
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user