From 8ffc8d8ab60c73d6d7cea6c92928baaa55564e3d Mon Sep 17 00:00:00 2001 From: psychhim Date: Sun, 5 Oct 2025 22:12:30 +0530 Subject: [PATCH] added: smart_split_open function for split windows; so Neovim asks if the user wants to re-open the already open buffer in the current tab as split window or just jump to the existing one --- lua/custom/plugins/filetree.lua | 305 ++++++++++++++++++-------------- 1 file changed, 172 insertions(+), 133 deletions(-) diff --git a/lua/custom/plugins/filetree.lua b/lua/custom/plugins/filetree.lua index dae405f..b1c6d68 100644 --- a/lua/custom/plugins/filetree.lua +++ b/lua/custom/plugins/filetree.lua @@ -2,143 +2,182 @@ vim.cmd [[ let g:neo_tree_remove_legacy_commands = 1 ]] return { - 'nvim-neo-tree/neo-tree.nvim', - version = '*', - dependencies = { - 'nvim-lua/plenary.nvim', - 'nvim-tree/nvim-web-devicons', - 'MunifTanjim/nui.nvim', - }, - config = function() - local function smart_open(state) - local node = state.tree:get_node() - if not node then - return - end - local path = node:get_id() + 'nvim-neo-tree/neo-tree.nvim', + version = '*', + dependencies = { + 'nvim-lua/plenary.nvim', + 'nvim-tree/nvim-web-devicons', + 'MunifTanjim/nui.nvim', + }, + config = function() + local function smart_open(state) + local node = state.tree:get_node() + if not node then + return + end + local path = node:get_id() - -- If the node is a directory, just toggle expand/collapse - if node.type == 'directory' then - state.commands.toggle_node(state, node) - return - end + -- If the node is a directory, just toggle expand/collapse + if node.type == 'directory' then + state.commands.toggle_node(state, node) + return + end - -- --- File handling starts here --- - -- Reuse already open buffer in any tab safely - for _, tab in ipairs(vim.api.nvim_list_tabpages()) do - if vim.api.nvim_tabpage_is_valid(tab) then - for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do - if vim.api.nvim_win_is_valid(win) then - local buf = vim.api.nvim_win_get_buf(win) - if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_name(buf) == path then - vim.api.nvim_set_current_tabpage(tab) - vim.api.nvim_set_current_win(win) - -- close Neo-tree if open - for _, w in ipairs(vim.api.nvim_list_wins()) do - if vim.api.nvim_win_is_valid(w) then - local b = vim.api.nvim_win_get_buf(w) - if vim.api.nvim_buf_is_valid(b) and vim.api.nvim_buf_get_option(b, 'filetype') == 'neo-tree' then - vim.api.nvim_win_close(w, true) - end - end - end - return - end - end - end - end - end + -- --- File handling starts here --- + -- Reuse already open buffer in any tab safely + for _, tab in ipairs(vim.api.nvim_list_tabpages()) do + if vim.api.nvim_tabpage_is_valid(tab) then + for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do + if vim.api.nvim_win_is_valid(win) then + local buf = vim.api.nvim_win_get_buf(win) + if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_name(buf) == path then + vim.api.nvim_set_current_tabpage(tab) + vim.api.nvim_set_current_win(win) + -- close Neo-tree if open + for _, w in ipairs(vim.api.nvim_list_wins()) do + if vim.api.nvim_win_is_valid(w) then + local b = vim.api.nvim_win_get_buf(w) + if vim.api.nvim_buf_is_valid(b) and vim.api.nvim_buf_get_option(b, 'filetype') == 'neo-tree' then + vim.api.nvim_win_close(w, true) + end + end + end + return + end + end + end + end + end - -- Reuse empty buffer in current tab - local wins = vim.api.nvim_tabpage_list_wins(0) - local empty_buf = nil - for _, win in ipairs(wins) do - if vim.api.nvim_win_is_valid(win) then - local buf = vim.api.nvim_win_get_buf(win) - if vim.api.nvim_buf_is_valid(buf) then - local bufname = vim.api.nvim_buf_get_name(buf) - local buftype = vim.api.nvim_buf_get_option(buf, 'buftype') - local modified = vim.api.nvim_buf_get_option(buf, 'modified') - if bufname == '' and buftype == '' and not modified then - empty_buf = buf - vim.api.nvim_set_current_win(win) - break - end - end - end - end + -- Reuse empty buffer in current tab + local wins = vim.api.nvim_tabpage_list_wins(0) + local empty_buf = nil + for _, win in ipairs(wins) do + if vim.api.nvim_win_is_valid(win) then + local buf = vim.api.nvim_win_get_buf(win) + if vim.api.nvim_buf_is_valid(buf) then + local bufname = vim.api.nvim_buf_get_name(buf) + local buftype = vim.api.nvim_buf_get_option(buf, 'buftype') + local modified = vim.api.nvim_buf_get_option(buf, 'modified') + if bufname == '' and buftype == '' and not modified then + empty_buf = buf + vim.api.nvim_set_current_win(win) + break + end + end + end + end - if empty_buf then - vim.cmd('edit ' .. vim.fn.fnameescape(path)) - else - vim.cmd('tabnew ' .. vim.fn.fnameescape(path)) - end + if empty_buf then + vim.cmd('edit ' .. vim.fn.fnameescape(path)) + else + vim.cmd('tabnew ' .. vim.fn.fnameescape(path)) + end - -- Always close Neo-tree window if open - for _, win in ipairs(vim.api.nvim_list_wins()) do - if vim.api.nvim_win_is_valid(win) then - local buf = vim.api.nvim_win_get_buf(win) - if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_option(buf, 'filetype') == 'neo-tree' then - vim.api.nvim_win_close(win, true) - end - end - end - end + -- Always close Neo-tree window if open + for _, win in ipairs(vim.api.nvim_list_wins()) do + if vim.api.nvim_win_is_valid(win) then + local buf = vim.api.nvim_win_get_buf(win) + if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_option(buf, 'filetype') == 'neo-tree' then + vim.api.nvim_win_close(win, true) + end + end + end + end - require('neo-tree').setup { - close_if_last_window = true, - popup_border_style = 'rounded', - enable_git_status = true, - enable_diagnostics = true, - default_component_configs = { - indent = { padding = 1, indent_size = 2 }, - icon = { folder_closed = '', folder_open = '', folder_empty = 'ﰊ' }, - }, - window = { - position = 'float', - width = 40, - mapping_options = { noremap = true, nowait = true }, - mappings = { - [''] = smart_open, - ['v'] = function(state) - local node = state.tree:get_node() - if node.type == 'directory' then - state.commands.toggle_node(state, node) - return - end - local path = node:get_id() - state.commands.open_split(state) -- opens horizontal split (top) - vim.schedule(function() - vim.cmd 'wincmd J' -- move the new split to bottom - end) - end, - ['h'] = function(state) - local node = state.tree:get_node() - if node.type == 'directory' then - state.commands.toggle_node(state, node) - return - end - local path = node:get_id() - state.commands.open_vsplit(state) -- opens vertical split (left) - vim.schedule(function() - vim.cmd 'wincmd L' -- move the new split to right - end) - end, - ['t'] = 'noop', - }, - }, - filesystem = { - follow_current_file = { - enabled = true, -- updated to table format - }, - use_libuv_file_watcher = true, - hijack_netrw_behavior = 'open_default', - filtered_items = { - visible = true, - hide_dotfiles = false, - hide_gitignored = true, - }, - }, - } - end, + -- Smart_open_split for split windows + local function smart_open_split(state, direction) + local node = state.tree:get_node() + if not node then + return + end + local path = node:get_id() + + if node.type == 'directory' then + state.commands.toggle_node(state, node) + return + end + + -- Check if file is open in another tab + local open_tab, open_win + for _, tab in ipairs(vim.api.nvim_list_tabpages()) do + for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do + local buf = vim.api.nvim_win_get_buf(win) + if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_name(buf) == path then + open_tab = tab + open_win = win + break + end + end + if open_tab then + break + end + end + + if open_tab then + local choice = vim.fn.confirm('File is already open in another tab. Open split here anyway?', '&Yes\n&No', + 2) + if choice ~= 1 then + -- User chose No → jump to the tab where file is open + vim.api.nvim_set_current_tabpage(open_tab) + vim.api.nvim_set_current_win(open_win) + return + end + -- Else user chose Yes → continue to open split in current tab + end + + -- Open split in current tab + if direction == 'v' then + state.commands.open_vsplit(state) + vim.schedule(function() + vim.cmd 'wincmd L' + end) + else + state.commands.open_split(state) + vim.schedule(function() + vim.cmd 'wincmd J' + end) + end + + vim.cmd('edit ' .. vim.fn.fnameescape(path)) + end + + require('neo-tree').setup { + close_if_last_window = true, + popup_border_style = 'rounded', + enable_git_status = true, + enable_diagnostics = true, + default_component_configs = { + indent = { padding = 1, indent_size = 2 }, + icon = { folder_closed = '', folder_open = '', folder_empty = 'ﰊ' }, + }, + window = { + position = 'float', + width = 40, + mapping_options = { noremap = true, nowait = true }, + mappings = { + [''] = smart_open, + ['v'] = function(state) + smart_open_split(state, 'h') + end, + ['h'] = function(state) + smart_open_split(state, 'v') + end, + ['t'] = 'noop', + }, + }, + filesystem = { + follow_current_file = { + enabled = true, -- updated to table format + }, + use_libuv_file_watcher = true, + hijack_netrw_behavior = 'open_default', + filtered_items = { + visible = true, + hide_dotfiles = false, + hide_gitignored = true, + }, + }, + } + end, }