From 00885ca41cb310f4e689738457b1c390c4d7ddf5 Mon Sep 17 00:00:00 2001 From: psychhim Date: Mon, 22 Sep 2025 00:09:24 +0530 Subject: [PATCH] Fixed opening duplicate buffer/file on a new tab from Neo-tree i.e if the file is already open in a tab, trying to opening the same file on neo-tree will redirect to the already opened tab. Fixed some bugs. Added the same new-tab, empty-buffer functionalities to Telescope as well. --- init.lua | 71 +++++++++++++- lua/custom/plugins/filetree.lua | 169 ++++++++++++++++++-------------- 2 files changed, 165 insertions(+), 75 deletions(-) diff --git a/init.lua b/init.lua index 5728202..0100193 100644 --- a/init.lua +++ b/init.lua @@ -112,8 +112,9 @@ require('lazy').setup({ 'rafamadriz/friendly-snippets', }, }, + -- Useful plugin to show you pending keybinds. - { 'folke/which-key.nvim', opts = {} }, + { 'folke/which-key.nvim', opts = {} }, { -- Adds git related signs to the gutter, as well as utilities for managing changes 'lewis6991/gitsigns.nvim', @@ -338,7 +339,7 @@ vim.keymap.set('n', 't', 'tabnew +termi') -- Create an empty buffer in a new tab vim.keymap.set('n', 'e', function() vim.cmd 'tabnew' -- create a new tab - vim.cmd 'enew' -- create a new empty buffer in it + vim.cmd 'enew' -- create a new empty buffer in it end, { noremap = true, silent = true }) -- Save current buffer (asks for filename if new/unsaved) @@ -434,6 +435,71 @@ require('telescope').setup { -- Enable telescope fzf native, if installed pcall(require('telescope').load_extension, 'fzf') +-- smart_open function for Telescope to check if the current tab has an empty "No Name" buffer. If it has, it replaces the empty buffer and open a file in the same tab +local actions = require 'telescope.actions' +local action_state = require 'telescope.actions.state' + +local function smart_open(prompt_bufnr) + local entry = action_state.get_selected_entry() + if not entry then + return + end + + local path = entry.path or entry.filename + if not path then + return + end + + if prompt_bufnr and vim.api.nvim_buf_is_valid(prompt_bufnr) then + pcall(actions.close, prompt_bufnr) + end + + -- 1. If file is already open → jump to it + local tabpages = vim.api.nvim_list_tabpages() + for _, tab in ipairs(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_get_name(buf) == path then + vim.api.nvim_set_current_tabpage(tab) -- jump to tab + vim.api.nvim_set_current_win(win) -- jump to window + return + end + end + end + + -- 2. If current tab has an empty "No Name" buffer → reuse it + local wins = vim.api.nvim_tabpage_list_wins(0) + for _, win in ipairs(wins) do + local buf = vim.api.nvim_win_get_buf(win) + local name = 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 name == '' and buftype == '' and not modified then + vim.api.nvim_set_current_win(win) + vim.cmd('edit ' .. vim.fn.fnameescape(path)) + return + end + end + + -- 3. Otherwise → open in a new tab + vim.cmd('tabnew ' .. vim.fn.fnameescape(path)) +end + +-- Telescope keymap using Smart Open +vim.keymap.set('n', 'sf', function() + require('telescope.builtin').find_files { + attach_mappings = function(_, map) + map('i', '', function(prompt_bufnr) + smart_open(prompt_bufnr) + end) + map('n', '', function(prompt_bufnr) + smart_open(prompt_bufnr) + end) + return true + end, + } +end, { desc = '[S]earch [F]iles (Smart Open)' }) + -- Telescope live_grep in git root -- Function to find the git root directory based on the current buffer's path local function find_git_root() @@ -490,7 +556,6 @@ end vim.keymap.set('n', 's/', telescope_live_grep_open_files, { desc = '[S]earch [/] in Open Files' }) vim.keymap.set('n', 'ss', require('telescope.builtin').builtin, { desc = '[S]earch [S]elect Telescope' }) vim.keymap.set('n', 'gf', require('telescope.builtin').git_files, { desc = 'Search [G]it [F]iles' }) -vim.keymap.set('n', 'sf', require('telescope.builtin').find_files, { desc = '[S]earch [F]iles' }) vim.keymap.set('n', 'sh', require('telescope.builtin').help_tags, { desc = '[S]earch [H]elp' }) vim.keymap.set('n', 'sw', require('telescope.builtin').grep_string, { desc = '[S]earch current [W]ord' }) vim.keymap.set('n', 'sg', require('telescope.builtin').live_grep, { desc = '[S]earch by [G]rep' }) diff --git a/lua/custom/plugins/filetree.lua b/lua/custom/plugins/filetree.lua index 9c72fa1..1c3614f 100644 --- a/lua/custom/plugins/filetree.lua +++ b/lua/custom/plugins/filetree.lua @@ -1,86 +1,111 @@ -- Unless you are still migrating, remove the deprecated commands from v1.x -vim.cmd([[ let g:neo_tree_remove_legacy_commands = 1 ]]) +vim.cmd [[ let g:neo_tree_remove_legacy_commands = 1 ]] return { - "nvim-neo-tree/neo-tree.nvim", - version = "*", + 'nvim-neo-tree/neo-tree.nvim', + version = '*', dependencies = { - "nvim-lua/plenary.nvim", - "nvim-tree/nvim-web-devicons", -- not strictly required, but recommended - "MunifTanjim/nui.nvim", + 'nvim-lua/plenary.nvim', + 'nvim-tree/nvim-web-devicons', + 'MunifTanjim/nui.nvim', }, config = function() - - -- smart_open function: If there's an empty "No Name" buffer, replace it and open files in the same tab -local function smart_open(state) - local node = state.tree:get_node() - if not node then return end - local path = node:get_id() + local function smart_open(state) + local node = state.tree:get_node() + if not node then + return + end + local path = node:get_id() - -- Get the window in the current tab that is NOT Neo-tree - local wins = vim.api.nvim_tabpage_list_wins(0) - local target_buf = nil - for _, win in ipairs(wins) do - local buf = vim.api.nvim_win_get_buf(win) - 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") - -- find a window with empty, unmodified buffer - if bufname == "" and buftype == "" and not modified then - target_buf = buf - vim.api.nvim_set_current_win(win) - break - end - end + -- 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 - if target_buf then - -- replace the empty buffer - vim.cmd("edit " .. path) - else - -- otherwise open in new tab - require("neo-tree.sources.filesystem.commands").open_tabnew(state) - 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 + + -- 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 { - -- Open Neo-tree in a floating window in middle at first launch when Neovim is opened inside a directory with "nvim ." - close_if_last_window = true, -- close Neo-tree if it's the last window - 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", -- this makes Neo-tree open in the middle - width = 40, - mapping_options = { - noremap = true, - nowait = true, - }, - mappings = { - [""] = smart_open, -- Enter → always open file in new tab if there's no empty buffer - ["t"] = "noop", -- disable t - }, - }, - filesystem = { - follow_current_file = true, - use_libuv_file_watcher = true, - hijack_netrw_behavior = "open_default", - filtered_items = { - visible = true, -- This is what you want: If you set this to `true`, all "hide" just mean "dimmed out" + 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, + ['t'] = 'noop', + }, + }, + filesystem = { + follow_current_file = true, + use_libuv_file_watcher = true, + hijack_netrw_behavior = 'open_default', + filtered_items = { + visible = true, hide_dotfiles = false, hide_gitignored = true, - }, - }, - } + }, + }, + } end, }