From 7ed2303648bf83bb081d9bd863660ebf2344ce47 Mon Sep 17 00:00:00 2001 From: srdusr Date: Wed, 24 Sep 2025 04:19:28 +0200 Subject: Squashed 'common/config/nvim/' changes from 2a8020a..966d12a 966d12a Update/Overhaul git-subtree-dir: common/config/nvim git-subtree-split: 966d12ac730c83da90d60ab24eae539b2ea69441 --- lua/plugins/telescope.lua | 944 +++++++++++++++++++++++++--------------------- 1 file changed, 524 insertions(+), 420 deletions(-) mode change 100644 => 100755 lua/plugins/telescope.lua (limited to 'lua/plugins/telescope.lua') diff --git a/lua/plugins/telescope.lua b/lua/plugins/telescope.lua old mode 100644 new mode 100755 index 506be8b..5aca8ac --- a/lua/plugins/telescope.lua +++ b/lua/plugins/telescope.lua @@ -1,372 +1,384 @@ local M = {} --- Shorten function names -local actions = require('telescope.actions') -local fb_actions = require('telescope').extensions.file_browser.actions ---local builtin = require("telescope.builtin") ---local utils = require("telescope.utils") ---local layout_actions = require("telescope.actions.layout") ---local themes = require('telescope.themes') -local actions_set = require('telescope.actions.set') -local actions_state = require('telescope.actions.state') -local finders = require('telescope.finders') -local pickers = require('telescope.pickers') -local config = require('telescope.config').values - -require('telescope').setup({ - defaults = { - vimgrep_arguments = { - 'rg', - '--color=never', - '--no-heading', - '--with-filename', - '--line-number', - '--column', - '--smart-case', - '--hidden', - '--fixed-strings', - '--trim', +-- Safely require a module +-- @param name string The module name to require +-- @return table|nil The loaded module or nil if failed +local function safe_require(name) + local ok, mod = pcall(require, name) + return ok and mod or nil +end + +--- Setup and configure Telescope +-- This function initializes Telescope with default configurations and extensions +-- @return boolean True if setup was successful, false otherwise +function M.setup() + -- Check if Telescope is installed + local telescope = safe_require("telescope") + if not telescope then + return false + end + -- Require Telescope and fail early if missing + local telescope = safe_require("telescope") + if not telescope then + return false + end + + local actions = safe_require("telescope.actions") + local actions_set = safe_require("telescope.actions.set") + local actions_state = safe_require("telescope.actions.state") + local finders = safe_require("telescope.finders") + local pickers = safe_require("telescope.pickers") + local config_mod = safe_require("telescope.config") + local utils = safe_require("telescope.utils") + local previewers = require("telescope.previewers") + + local config = config_mod and config_mod.values or {} + + -- 🛡 Safe previewer to avoid nil path error + local safe_previewer = function() + return require("telescope.previewers").new_buffer_previewer({ + define_preview = function(self, entry) + if not entry or type(entry) ~= "table" then return end + + local path = entry.path or entry.filename or entry.value + if type(path) ~= "string" or path == "" then return end + + -- Avoid expanding things like " Recent Books" which aren't valid files + if path:match("^%s") then return end + + -- Resolve tilde if present + path = path:gsub("^~", vim.env.HOME) + + if vim.fn.filereadable(path) ~= 1 and vim.fn.isdirectory(path) ~= 1 then + return + end + + -- Protect against nil path being passed further + if not self.state or not self.state.bufnr or not self.state.bufname then return end + + local preview_utils = require("telescope.previewers.utils") + preview_utils.buffer_previewer_maker(path, self.state.bufnr, { + bufname = self.state.bufname, + callback = function(bufnr, success) + if not success then + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { "Failed to preview file." }) + end + end, + }) + end, + }) + end + + local function get_extension_actions(ext) + local ok, telescope_ext = pcall(require, "telescope._extensions." .. ext) + if not ok then return {} end + return telescope_ext.actions or {} + end + + telescope.setup({ + defaults = { + vimgrep_arguments = { + "rg", + "--color=never", + "--no-heading", + "--with-filename", + "--line-number", + "--column", + "--smart-case", + "--hidden", + "--fixed-strings", + "--trim", + }, + previewer = safe_previewer(), + prompt_prefix = " ", + selection_caret = " ", + entry_prefix = " ", + path_display = { "tail" }, + file_ignore_patterns = { + "packer_compiled.lua", + "~/.config/zsh/plugins", + "zcompdump", + "%.DS_Store", + "%.git/", + "%.spl", + "%[No Name%]", + "/$", + "node_modules", + "%.png", + "%.zip", + "%.pxd", + "^.local/", + "^.cache/", + "^downloads/", + "^music/", + }, + mappings = { + i = { + [""] = actions.cycle_history_next, + [""] = actions.cycle_history_prev, + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + [""] = actions.close, + [""] = actions.which_key, + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + [""] = actions.select_default, + [""] = actions.select_horizontal, + [""] = actions.select_vertical, + [""] = actions.select_tab, + [""] = actions.delete_buffer, + [""] = actions.preview_scrolling_up, + [""] = actions.preview_scrolling_down, + [""] = actions.results_scrolling_up, + [""] = actions.results_scrolling_down, + [""] = actions.toggle_selection + actions.move_selection_worse, + [""] = actions.toggle_selection + actions.move_selection_better, + [""] = actions.send_to_qflist + actions.open_qflist, + [""] = actions.send_selected_to_qflist + actions.open_qflist, + [""] = actions.complete_tag, + [""] = actions.which_key, + }, + n = { + [""] = actions.close, + [""] = actions.close, + [""] = actions.select_default, + [""] = actions.select_horizontal, + [""] = actions.select_vertical, + [""] = actions.select_tab, + [""] = actions.delete_buffer, + [""] = actions.toggle_selection + actions.move_selection_worse, + [""] = actions.toggle_selection + actions.move_selection_better, + [""] = actions.send_to_qflist + actions.open_qflist, + [""] = actions.send_selected_to_qflist + actions.open_qflist, + ["j"] = actions.move_selection_next, + ["k"] = actions.move_selection_previous, + ["H"] = actions.move_to_top, + ["M"] = actions.move_to_middle, + ["L"] = actions.move_to_bottom, + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + ["gg"] = actions.move_to_top, + ["G"] = actions.move_to_bottom, + [""] = actions.preview_scrolling_up, + [""] = actions.preview_scrolling_down, + [""] = actions.results_scrolling_up, + [""] = actions.results_scrolling_down, + ["cd"] = function(prompt_bufnr) + local selection = actions_state.get_selected_entry() + local dir = vim.fn.fnamemodify(selection.path, ":p:h") + actions.close(prompt_bufnr) + vim.cmd("silent lcd " .. dir) + end, + ["?"] = actions.which_key, + }, + }, }, - prompt_prefix = ' ', - selection_caret = ' ', - entry_prefix = ' ', - path_display = { 'tail' }, - --path_display = { "truncate" }, - --path_display = { "smart" }, - file_ignore_patterns = { - 'packer_compiled.lua', - '~/.config/zsh/plugins', - 'zcompdump', - '%.DS_Store', - '%.git/', - '%.spl', - --"%.log", - '%[No Name%]', -- new files / sometimes folders (netrw) - '/$', -- ignore folders (netrw) - 'node_modules', - '%.png', - '%.zip', - '%.pxd', - --"^.vim/", - '^.local/', - '^.cache/', - '^downloads/', - '^music/', - --"^node_modules/", - --"^undodir/", + preview = { + filesize_limit = 3, + timeout = 250, }, - mappings = { - i = { - [''] = actions.cycle_history_next, - [''] = actions.cycle_history_prev, - - [''] = actions.move_selection_next, - [''] = actions.move_selection_previous, - - --[""] = actions.close, - [''] = actions.close, -- close w/ one esc - --[""] = "close", -- close w/ one esc - [''] = actions.which_key, -- keys from pressing - - [''] = actions.move_selection_next, - [''] = actions.move_selection_previous, - - [''] = actions.select_default, - [''] = actions.select_horizontal, - [''] = actions.select_vertical, - [''] = actions.select_tab, - [''] = actions.delete_buffer, - - [''] = actions.preview_scrolling_up, - [''] = actions.preview_scrolling_down, - - [''] = actions.results_scrolling_up, - [''] = actions.results_scrolling_down, - - [''] = actions.toggle_selection + actions.move_selection_worse, - [''] = actions.toggle_selection + actions.move_selection_better, - [''] = actions.send_to_qflist + actions.open_qflist, - [''] = actions.send_selected_to_qflist + actions.open_qflist, - [''] = actions.complete_tag, - [''] = actions.which_key, -- keys from pressing - --[""] = function(prompt_bufnr) - -- local selection = require("telescope.actions.state").get_selected_entry() - -- local dir = vim.fn.fnamemodify(selection.path, ":p:h") - -- require("telescope.actions").close(prompt_bufnr) - -- -- Depending on what you want put `cd`, `lcd`, `tcd` - -- vim.cmd(string.format("silent lcd %s", dir)) - --end, + selection_strategy = "reset", + sorting_strategy = "ascending", + scroll_strategy = "limit", + color_devicons = true, + layout_strategy = "horizontal", + layout_config = { + horizontal = { + height = 0.95, + preview_cutoff = 70, + width = 0.92, + preview_width = { 0.55, max = 50 }, }, - n = { - --["cd"] = function(prompt_bufnr) - -- local selection = require("telescope.actions.state").get_selected_entry() - -- local dir = vim.fn.fnamemodify(selection.path, ":p:h") - -- require("telescope.actions").close(prompt_bufnr) - -- -- Depending on what you want put `cd`, `lcd`, `tcd` - -- vim.cmd(string.format("silent lcd %s", dir)) - --end, - [''] = actions.close, - [''] = actions.close, - [''] = actions.select_default, - [''] = actions.select_horizontal, - [''] = actions.select_vertical, - [''] = actions.select_tab, - [''] = actions.delete_buffer, - - [''] = actions.toggle_selection + actions.move_selection_worse, - [''] = actions.toggle_selection + actions.move_selection_better, - [''] = actions.send_to_qflist + actions.open_qflist, - [''] = actions.send_selected_to_qflist + actions.open_qflist, - - ['j'] = actions.move_selection_next, - ['k'] = actions.move_selection_previous, - ['H'] = actions.move_to_top, - ['M'] = actions.move_to_middle, - ['L'] = actions.move_to_bottom, - - [''] = actions.move_selection_next, - [''] = actions.move_selection_previous, - ['gg'] = actions.move_to_top, - ['G'] = actions.move_to_bottom, - - [''] = actions.preview_scrolling_up, - [''] = actions.preview_scrolling_down, - - [''] = actions.results_scrolling_up, - [''] = actions.results_scrolling_down, - ['cd'] = function(prompt_bufnr) - local selection = require('telescope.actions.state').get_selected_entry() - local dir = vim.fn.fnamemodify(selection.path, ':p:h') - require('telescope.actions').close(prompt_bufnr) - -- Depending on what you want put `cd`, `lcd`, `tcd` - vim.cmd(string.format('silent lcd %s', dir)) - end, - ['?'] = actions.which_key, - --[""] = function(prompt_bufnr) - -- local selection = require("telescope.actions.state").get_selected_entry() - -- local dir = vim.fn.fnamemodify(selection.path, ":p:h") - -- require("telescope.actions").close(prompt_bufnr) - -- -- Depending on what you want put `cd`, `lcd`, `tcd` - -- vim.cmd(string.format("silent lcd %s", dir)) - --end, + bottom_pane = { + height = 12, + preview_cutoff = 70, + prompt_position = "bottom", }, }, - }, - preview = { - filesize_limit = 3, - timeout = 250, - }, - selection_strategy = 'reset', - sorting_strategy = 'ascending', - scroll_strategy = 'limit', - color_devicons = true, - layout_strategy = 'horizontal', - layout_config = { - horizontal = { - height = 0.95, - preview_cutoff = 70, - width = 0.92, - preview_width = { 0.55, max = 50 }, - }, - bottom_pane = { - height = 12, - preview_cutoff = 70, - prompt_position = 'bottom', + find_files = { + cwd = vim.fn.getcwd(), + prompt_prefix = " ", + follow = true, }, - }, - find_files = { - --cwd = '%:p:h', - cwd = vim.fn.getcwd(), - prompt_prefix = ' ', - --hidden = true, - --no_ignore = false, - follow = true, - }, - --pickers = { - -- live_grep = { - -- disable_coordinates = true, - -- layout_config = { - -- horizontal = { - -- preview_width = 0.55, - -- }, - -- }, - -- }, - --}, - --pickers = { - -- live_grep = { - -- mappings = { - -- i = { - -- [""] = ts_select_dir_for_grep, - -- }, - -- n = { - -- [""] = ts_select_dir_for_grep, - -- }, - -- }, - -- }, - --}, - --pickers = { - --lsp_references = { - -- prompt_prefix='⬅️', - -- show_line=false, - -- trim_text=true, - -- include_declaration=false, - -- initial_mode = "normal", - --}, - --lsp_definitions = { - -- prompt_prefix='➡️', - -- show_line=false, - -- trim_text=true, - -- initial_mode = "normal", - --}, - --lsp_document_symbols = { - -- prompt_prefix='* ', - -- show_line = false, - --}, - --treesitter = { - -- prompt_prefix=' ', - -- show_line = false, - --}, - --keymaps = { prompt_prefix='? ' }, - --oldfiles = { prompt_prefix=' ' }, - --highlights = { prompt_prefix=' ' }, - --git_files = { - -- prompt_prefix=' ', - -- show_untracked = true, - -- path_display = { "tail" }, - --}, - --buffers = { - -- prompt_prefix=' ', - -- ignore_current_buffer = true, - -- initial_mode = "normal", - -- sort_mru = true, - --}, - --live_grep = { - -- cwd='%:p:h', - -- disable_coordinates=true, - -- prompt_title='Search in Folder', - -- prompt_prefix=' ', - --}, - --spell_suggest = { - -- initial_mode = "normal", - -- prompt_prefix = "暈", - -- theme = "cursor", - -- layout_config = { cursor = { width = 0.3 } } - --}, - --colorscheme = { - -- enable_preview = true, - -- prompt_prefix = '', - -- results_title = '', - -- layout_strategy = "bottom_pane", - --}, - --}, - - extensions = { - file_browser = { - theme = 'dropdown', - -- disables netrw and use telescope-file-browser in its place - hijack_netrw = false, - mappings = { - -- your custom insert mode mappings - ['i'] = { - [''] = function() - vim.cmd('normal vbd') - end, - [''] = fb_actions.goto_parent_dir, - }, - ['n'] = { - -- your custom normal mode mappings - ['N'] = fb_actions.create, - [''] = fb_actions.goto_parent_dir, - --["/"] = function() - -- vim.cmd("startinsert") - --end, + extensions = { + file_browser = { + theme = "dropdown", + hijack_netrw = false, + mappings = { + i = { + [""] = function() vim.cmd("normal vbd") end, + [""] = function() + local fb_actions = get_extension_actions("file_browser") + if fb_actions.goto_parent_dir then + fb_actions.goto_parent_dir() + end + end, + }, + n = { + ["N"] = function() + local fb_actions = get_extension_actions("file_browser") + if fb_actions.create then + fb_actions.create() + end + end, + [""] = function() + local fb_actions = get_extension_actions("file_browser") + if fb_actions.goto_parent_dir then + fb_actions.goto_parent_dir() + end + end, + }, }, }, }, - }, -}) - --------------------------------------------------------------------------------- - --- Load extensions: --- have to be loaded after telescope setup/config -require('telescope').load_extension('fzf') -require('telescope').load_extension('ui-select') -require('telescope').load_extension('file_browser') -require('telescope').load_extension('changed_files') -require('telescope').load_extension('media_files') -require('telescope').load_extension('notify') -require('telescope').load_extension('dap') -require('telescope').load_extension('session-lens') -require('telescope').load_extension('flutter') -require('telescope').load_extension('recent_files') ---require('telescope').load_extension('projects') - ---M.curbuf = function(opts) --- opts = opts --- or themes.get_dropdown({ --- previewer = false, --- shorten_path = false, --- border = true, --- }) --- require("telescope.builtin").current_buffer_fuzzy_find(opts) ---end + }) -function M.find_configs() - -- Track dotfiles (bare git repository) - -- Inside shell config file: - -- alias config='git --git-dir=$HOME/.cfg --work-tree=$HOME' - -- cfg_files=$(config ls-tree --name-only -r HEAD) - -- export CFG_FILES="$cfg_files" - local tracked_files = {} - - for file in string.gmatch(os.getenv('CFG_FILES'), '[^\n]+') do - table.insert(tracked_files, os.getenv('HOME') .. '/' .. file) + -- Load extensions + for _, ext in ipairs({ + "fzf", "ui-select", "file_browser", "changed_files", + "media_files", "notify", "dap", "session-lens", "recent_files" + }) do + pcall(telescope.load_extension, ext) end - local history = os.getenv('HOME') .. '/.config/zsh/.zhistory' - table.insert(tracked_files, history) + -- Define the custom command findhere/startup + vim.cmd('command! Findhere lua require("plugins.telescope").findhere()') - require('telescope.builtin').find_files({ - hidden = true, - no_ignore = false, - prompt_title = ' Find Configs', - results_title = 'Config Files', - path_display = { 'smart' }, - search_dirs = tracked_files, - layout_strategy = 'horizontal', - layout_config = { preview_width = 0.65, width = 0.75 }, - }) + return true +end + +-- Find config files +local function _sys_path(repo_path) + local home = os.getenv("HOME") or vim.fn.expand("~") + + -- Case 1: Files in the OS-specific home folder (e.g., linux/home/.bashrc) + if repo_path:find("/home/", 1, true) then + local file = repo_path:match(".*/home/(.*)") + return home .. "/" .. file + -- Case 2: Files in the common folder (e.g., common/README.md) + elseif repo_path:find("common/", 1, true) then + local file = repo_path:match("common/(.*)") + return home .. "/" .. file + -- Case 3: Root-level files (e.g., profile/profile_script or README.md) + elseif repo_path:find("profile/", 1, true) or repo_path:find("README.md", 1, true) then + return home .. "/" .. repo_path + -- Case 4: System-level files (e.g., linux/etc/issue) + elseif repo_path:find("/etc/", 1, true) then + local file = repo_path:match(".*/etc/(.*)") + return "/etc/" .. file + -- Return nil for paths that don't match any known pattern + else + return nil + end +end + +function M.find_configs() + local telescope_builtin = require("telescope.builtin") + local tracked_files = {} + local home = os.getenv("HOME") or "~" + local original_dir = vim.fn.getcwd() + vim.fn.chdir(home) + + vim.api.nvim_create_autocmd("VimLeave", { + callback = function() + vim.fn.chdir(original_dir) + end, + }) + + -- Check if the bare repository exists + if vim.fn.isdirectory(home .. "/.cfg") == 1 then + -- Repository exists, use git to find tracked files + local handle = io.popen("git --git-dir=" .. home .. "/.cfg --work-tree=" .. home .. " ls-tree --name-only -r HEAD") + local cfg_files = "" + if handle then + cfg_files = handle:read("*a") or "" + handle:close() + end + + -- Process the list of files + for file in string.gmatch(cfg_files, "[^\n]+") do + file = vim.trim(file) + if file ~= "" then + local fullpath = _sys_path(file) + if fullpath and (vim.fn.filereadable(fullpath) == 1 or vim.fn.isdirectory(fullpath) == 1) then + table.insert(tracked_files, fullpath) + end + end + end + end + + -- If no files were found (either no repo or no tracked files), use fallback paths + if #tracked_files == 0 then + local fallback_dirs = { + home .. "/.config/nvim", + home .. "/.config/zsh", + home .. "/.config/tmux", + home .. "/.bashrc", + home .. "/.zshrc", + home .. "/.tmux.conf", + } + for _, path in ipairs(fallback_dirs) do + if vim.fn.filereadable(path) == 1 or vim.fn.isdirectory(path) == 1 then + table.insert(tracked_files, path) + end + end + end + + if #tracked_files == 0 then + vim.notify("[find_configs] No configuration files found to search.", vim.log.levels.WARN) + return + end + + -- Launch Telescope + telescope_builtin.find_files({ + hidden = true, + no_ignore = false, + prompt_title = " Find Configs", + results_title = "Config Files", + path_display = { "smart" }, + search_dirs = tracked_files, + layout_strategy = "horizontal", + layout_config = { preview_width = 0.65, width = 0.75 }, + previewer = true, + }) end function M.find_scripts() - require('telescope.builtin').find_files({ + require("telescope.builtin").find_files({ hidden = true, no_ignore = true, - prompt_title = ' Find Scripts', - path_display = { 'smart' }, + prompt_title = " Find Scripts", + path_display = { "smart" }, search_dirs = { - '~/.scripts', + "~/.scripts", }, - layout_strategy = 'horizontal', + layout_strategy = "horizontal", layout_config = { preview_width = 0.65, width = 0.75 }, }) end function M.find_projects() - local search_dir = '~/projects' + local search_dir = "~/projects" + local actions = safe_require("telescope.actions") + local actions_set = safe_require("telescope.actions.set") + local actions_state = safe_require("telescope.actions.state") + local finders = safe_require("telescope.finders") + local pickers = safe_require("telescope.pickers") + local config_mod = safe_require("telescope.config") + local config = config_mod and config_mod.values or {} + pickers .new({}, { - prompt_title = 'Find Projects', + prompt_title = "Find Projects", finder = finders.new_oneshot_job({ - 'find', + "find", vim.fn.expand(search_dir), - '-type', - 'd', - '-maxdepth', - '1', + "-type", + "d", + "-maxdepth", + "1", }), - previewer = require('telescope.previewers').vim_buffer_cat.new({}), + previewer = require("telescope.previewers").vim_buffer_cat.new({}), sorter = config.generic_sorter({}), attach_mappings = function(prompt_bufnr, map) actions_set.select:replace(function() @@ -375,9 +387,9 @@ function M.find_projects() local dir = entry.value actions.close(prompt_bufnr, false) vim.fn.chdir(dir) - vim.cmd('e .') + vim.cmd("e .") vim.cmd("echon ''") - print('cwd: ' .. vim.fn.getcwd()) + print("cwd: " .. vim.fn.getcwd()) end end) return true @@ -390,50 +402,64 @@ function M.grep_notes() local opts = {} opts.hidden = false opts.search_dirs = { - '~/documents/notes/', + "~/documents/main/", } - opts.prompt_prefix = '  ' - opts.prompt_title = ' Grep Notes' - opts.path_display = { 'smart' } - require('telescope.builtin').live_grep(opts) + opts.prompt_prefix = " " + opts.prompt_title = " Grep Notes" + opts.path_display = { "smart" } + require("telescope.builtin").live_grep(opts) end function M.find_notes() - require('telescope.builtin').find_files({ + require("telescope.builtin").find_files({ hidden = true, no_ignore = false, - prompt_title = ' Find Notes', - path_display = { 'smart' }, + prompt_title = " Find Notes", + path_display = { "smart" }, search_dirs = { - '~/documents/notes/private/', - '~/documents/notes', + "~/documents/main", }, - layout_strategy = 'horizontal', + layout_strategy = "horizontal", layout_config = { preview_width = 0.65, width = 0.75 }, }) end function M.find_private() - require('telescope.builtin').find_files({ + require("telescope.builtin").find_files({ hidden = true, no_ignore = false, - prompt_title = ' Find Notes', - path_display = { 'smart' }, + prompt_title = " Find Notes", + path_display = { "smart" }, search_dirs = { - '~/notes/private', - '~/notes', + "~/notes/private", + "~/notes", }, - layout_strategy = 'horizontal', + layout_strategy = "horizontal", layout_config = { preview_width = 0.65, width = 0.75 }, }) end function M.find_books() - local search_dir = '~/documents/books' - vim.fn.jobstart('$HOME/.scripts/track-books.sh') - local recent_books_directory = vim.fn.stdpath('config') .. '/tmp/' - local recent_books_file = recent_books_directory .. 'recent_books.txt' - local search_cmd = 'find ' .. vim.fn.expand(search_dir) .. ' -type d -o -type f -maxdepth 1' + local search_dir = "~/documents/books" + local actions = safe_require("telescope.actions") + local actions_set = safe_require("telescope.actions.set") + local actions_state = safe_require("telescope.actions.state") + local finders = safe_require("telescope.finders") + local pickers = safe_require("telescope.pickers") + local config_mod = safe_require("telescope.config") + local config = config_mod and config_mod.values or {} + + vim.fn.jobstart("$HOME/.scripts/track-books.sh") + local recent_books_directory = vim.fn.stdpath("config") .. "/tmp/" + local recent_books_file = recent_books_directory .. "recent_books.txt" + + -- Check if recent_books.txt exists, create it if not + if vim.fn.filereadable(recent_books_file) == 0 then + vim.fn.mkdir(recent_books_directory, "p") -- Ensure the directory exists + vim.fn.writefile({}, recent_books_file) -- Create an empty file + end + + local search_cmd = "find " .. vim.fn.expand(search_dir) .. " -type d -o -type f -maxdepth 1" local recent_books = vim.fn.readfile(recent_books_file) local search_results = vim.fn.systemlist(search_cmd) @@ -441,14 +467,14 @@ function M.find_books() local results = {} -- Section for Recent Books - table.insert(results, ' Recent Books') + table.insert(results, " Recent Books") for _, recent_book_path in ipairs(recent_books) do local formatted_path = vim.fn.fnameescape(recent_book_path) table.insert(results, formatted_path) end -- Section for All Books - table.insert(results, ' All Books') + table.insert(results, " All Books") local directories = {} local files = {} @@ -472,14 +498,14 @@ function M.find_books() end local picker = pickers.new({}, { - prompt_title = 'Find Books', + prompt_title = "Find Books", finder = finders.new_table({ results = results, }), file_ignore_patterns = { - '%.git', + "%.git", }, - previewer = require('telescope.previewers').vim_buffer_cat.new({}), + previewer = require("telescope.previewers").vim_buffer_cat.new({}), sorter = config.generic_sorter({}), attach_mappings = function(prompt_bufnr, map) actions_set.select:replace(function() @@ -490,17 +516,18 @@ function M.find_books() actions.close(prompt_bufnr, false) -- Check if it's under "Recent Books" - if path == ' Recent Books' or path == ' All Books' then - vim.notify("Cannot select 'All Books'/'Recent Books', please select a book or directory.", vim.log.levels.WARN, { title = 'Find Books' }) + if path == " Recent Books" or path == " All Books" then + vim.notify("Cannot select 'All Books'/'Recent Books', please select a book or directory.", + vim.log.levels.WARN, { title = "Find Books" }) else -- Determine whether it's a directory or a file local is_directory = vim.fn.isdirectory(path) if is_directory then -- It's a directory, navigate to it in the current buffer - vim.cmd('e ' .. path) + vim.cmd("e " .. path) else -- It's a file, open it - vim.cmd('e ' .. path) + vim.cmd("e " .. path) end end end @@ -513,48 +540,43 @@ function M.find_books() end function M.grep_current_dir() - local buffer_dir = require('telescope.utils').buffer_dir() + local buffer_dir = require("telescope.utils").buffer_dir() local opts = { - prompt_title = 'Live Grep in ' .. buffer_dir, + prompt_title = "Live Grep in " .. buffer_dir, cwd = buffer_dir, } - require('telescope.builtin').live_grep(opts) + require("telescope.builtin").live_grep(opts) end --------------------------------------------------------------------------------- - -local dropdown = require('telescope.themes').get_dropdown({ - hidden = true, - no_ignore = true, - previewer = false, - prompt_title = '', - preview_title = '', - results_title = '', - layout_config = { - --anchor = "S", - prompt_position = 'top', - }, -}) - --- File browser always relative to buffer ---local opts_file_browser = vim.tbl_extend('force', dropdown, { --- path_display = { '%:p:h' }, ---}) +-- Helper functions that depend on telescope availability +local function get_dropdown_theme() + return require("telescope.themes").get_dropdown({ + hidden = true, + no_ignore = true, + previewer = false, + prompt_title = "", + preview_title = "", + results_title = "", + layout_config = { + prompt_position = "top", + }, + }) +end -- Set current folder as prompt title -local with_title = function(opts, extra) +local function with_title(opts, extra) extra = extra or {} local path = opts.cwd or opts.path or extra.cwd or extra.path or nil - local title = '' - local buf_path = vim.fn.expand('%:p:h') + local title = "" + local buf_path = vim.fn.expand("%:p:h") local cwd = vim.fn.getcwd() if path ~= nil and buf_path ~= cwd then - title = require('plenary.path'):new(buf_path):make_relative(cwd) + title = require("plenary.path"):new(buf_path):make_relative(cwd) else - title = vim.fn.fnamemodify(cwd, ':t') + title = vim.fn.fnamemodify(cwd, ":t") end - return vim.tbl_extend('force', opts, { + return vim.tbl_extend("force", opts, { prompt_title = title, }, extra or {}) end @@ -562,31 +584,21 @@ end -- Find here function M.findhere() -- Open file browser if argument is a folder - local arg = vim.api.nvim_eval('argv(0)') - if arg and (vim.fn.isdirectory(arg) ~= 0 or arg == '') then + local arg = vim.api.nvim_eval("argv(0)") + if arg and (vim.fn.isdirectory(arg) ~= 0 or arg == "") then vim.defer_fn(function() - require('telescope.builtin').find_files(with_title(dropdown)) - -- require'telescope.builtin'.find_files(require('telescope.themes').get_dropdown({ - -- hidden = true, - -- results_title = '', - -- layout_config = { prompt_position = 'top' }, - -- })) + require("telescope.builtin").find_files(with_title(get_dropdown_theme())) end, 10) end end --- Define the custom command findhere/startup -vim.cmd('command! Findhere lua require("plugins.telescope").findhere()') ---vim.cmd('command! Startup lua require("plugins.telescope").findhere()') ---vim.api.nvim_command('autocmd VimEnter * lua require("plugins/telescope").findhere()') - -- Find dirs function M.find_dirs() - local root_dir = vim.fn.input('Enter the root directory: ') + local root_dir = vim.fn.input("Enter the root directory: ") -- Check if root_dir is empty - if root_dir == '' then - print('No directory entered. Aborting.') + if root_dir == "" then + print("No directory entered. Aborting.") return end @@ -598,14 +610,22 @@ function M.find_dirs() local subentries = vim.fn.readdir(root_path) if subentries then for _, subentry in ipairs(subentries) do - local absolute_path = root_path .. '/' .. subentry + local absolute_path = root_path .. "/" .. subentry table.insert(entries, subentry) end end + local actions = safe_require("telescope.actions") + local actions_set = safe_require("telescope.actions.set") + local actions_state = safe_require("telescope.actions.state") + local finders = safe_require("telescope.finders") + local pickers = safe_require("telescope.pickers") + local config_mod = safe_require("telescope.config") + local config = config_mod and config_mod.values or {} + pickers .new({}, { - prompt_title = 'Change Directory or Open File', + prompt_title = "Change Directory or Open File", finder = finders.new_table({ results = entries, }), @@ -617,13 +637,13 @@ function M.find_dirs() if entry ~= nil then local selected_entry = entry.value actions.close(prompt_bufnr, false) - local selected_path = root_path .. '/' .. selected_entry + local selected_path = root_path .. "/" .. selected_entry if vim.fn.isdirectory(selected_path) == 1 then vim.fn.chdir(selected_path) - vim.cmd('e .') - print('cwd: ' .. vim.fn.getcwd()) + vim.cmd("e .") + print("cwd: " .. vim.fn.getcwd()) else - vim.cmd('e ' .. selected_path) + vim.cmd("e " .. selected_path) end end end) @@ -633,4 +653,88 @@ function M.find_dirs() :find() end +-- Safe telescope function wrapper for keymaps +local function safe_telescope_call(module_path, func_name, fallback_msg) + return function() + local ok, module = pcall(require, module_path) + if ok and module[func_name] then + module[func_name]() + else + vim.notify(fallback_msg or ("Telescope plugin not available for " .. func_name), vim.log.levels.WARN) + end + end +end + +local function safe_telescope_builtin(func_name, fallback_msg) + return function(opts) + local ok, telescope_builtin = pcall(require, "telescope.builtin") + if not ok then + vim.notify(fallback_msg or ("Telescope builtin module (telescope.builtin) not found!"), vim.log.levels.ERROR) + vim.notify("Error details: " .. tostring(telescope_builtin), vim.log.levels.DEBUG) -- telescope_builtin will contain the error message here + return + end + + if not telescope_builtin[func_name] then + vim.notify(fallback_msg or ("Telescope builtin function '" .. func_name .. "' not found!"), vim.log.levels.ERROR) + vim.notify("Available builtin functions: " .. vim.inspect(vim.tbl_keys(telescope_builtin)), vim.log.levels.DEBUG) + return + end + + -- If both are ok, proceed + telescope_builtin[func_name](opts or {}) + end +end + +-- Safe builtin telescope functions +local function safe_telescope_builtin(func_name, fallback_msg) + return function(opts) + local ok, telescope_builtin = pcall(require, "telescope.builtin") + if ok and telescope_builtin[func_name] then + telescope_builtin[func_name](opts or {}) + else + vim.notify(fallback_msg or ("Telescope builtin not available: " .. func_name), vim.log.levels.WARN) + end + end +end + +-- Safe extension calls with better checking +local function safe_telescope_extension(ext_name, func_name, fallback_msg) + return function(opts) + local telescope_mod = package.loaded.telescope or require("telescope") + if not telescope_mod then + return + end + + -- Check if extension is loaded + if not telescope_mod.extensions or not telescope_mod.extensions[ext_name] then + vim.notify(fallback_msg or ("Telescope extension '" .. ext_name .. "' not available (plugin may not be installed)"), vim.log.levels.WARN) + return + end + + local ext_func = telescope_mod.extensions[ext_name][func_name] + if not ext_func then + vim.notify(fallback_msg or ("Function '" .. func_name .. "' not found in extension '" .. ext_name .. "'"), vim.log.levels.WARN) + return + end + + ext_func(opts or {}) + end +end + +-- Fallback-safe `find_files` +M.safe_find_files = function() + local builtin = safe_require("telescope.builtin") + if builtin and builtin.find_files then + builtin.find_files() + else + local file = vim.fn.input("Open file: ", "", "file") + if file ~= "" then vim.cmd("edit " .. file) end + end +end + +-- Export safe wrapper functions for external use +M.safe_telescope_call = safe_telescope_call +M.safe_telescope_builtin = safe_telescope_builtin +M.safe_telescope_extension = safe_telescope_extension + return M -- cgit v1.2.3