diff options
Diffstat (limited to 'lua/telescope/builtin/files.lua')
| -rw-r--r-- | lua/telescope/builtin/files.lua | 533 |
1 files changed, 14 insertions, 519 deletions
diff --git a/lua/telescope/builtin/files.lua b/lua/telescope/builtin/files.lua index dddd18a..645fc10 100644 --- a/lua/telescope/builtin/files.lua +++ b/lua/telescope/builtin/files.lua @@ -1,522 +1,17 @@ -local action_state = require "telescope.actions.state" -local action_set = require "telescope.actions.set" -local finders = require "telescope.finders" -local make_entry = require "telescope.make_entry" -local pickers = require "telescope.pickers" -local previewers = require "telescope.previewers" -local sorters = require "telescope.sorters" -local utils = require "telescope.utils" -local conf = require("telescope.config").values -local log = require "telescope.log" - -local Path = require "plenary.path" - -local flatten = vim.tbl_flatten -local filter = vim.tbl_filter - -local files = {} - -local escape_chars = function(string) - return string.gsub(string, "[%(|%)|\\|%[|%]|%-|%{%}|%?|%+|%*|%^|%$|%.]", { - ["\\"] = "\\\\", - ["-"] = "\\-", - ["("] = "\\(", - [")"] = "\\)", - ["["] = "\\[", - ["]"] = "\\]", - ["{"] = "\\{", - ["}"] = "\\}", - ["?"] = "\\?", - ["+"] = "\\+", - ["*"] = "\\*", - ["^"] = "\\^", - ["$"] = "\\$", - ["."] = "\\.", - }) -end - --- Special keys: --- opts.search_dirs -- list of directory to search in --- opts.grep_open_files -- boolean to restrict search to open files -files.live_grep = function(opts) - local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments - local search_dirs = opts.search_dirs - local grep_open_files = opts.grep_open_files - opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd() - - local filelist = {} - - if grep_open_files then - local bufnrs = filter(function(b) - if 1 ~= vim.fn.buflisted(b) then - return false - end - return true - end, vim.api.nvim_list_bufs()) - if not next(bufnrs) then - return - end - - for _, bufnr in ipairs(bufnrs) do - local file = vim.api.nvim_buf_get_name(bufnr) - table.insert(filelist, Path:new(file):make_relative(opts.cwd)) - end - elseif search_dirs then - for i, path in ipairs(search_dirs) do - search_dirs[i] = vim.fn.expand(path) - end - end - - local additional_args = {} - if opts.additional_args ~= nil and type(opts.additional_args) == "function" then - additional_args = opts.additional_args(opts) - end - - if opts.type_filter then - additional_args[#additional_args + 1] = "--type=" .. opts.type_filter - end - - if type(opts.glob_pattern) == "string" then - additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern - elseif type(opts.glob_pattern) == "table" then - for i = 1, #opts.glob_pattern do - additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern[i] - end - end - - local live_grepper = finders.new_job(function(prompt) - -- TODO: Probably could add some options for smart case and whatever else rg offers. - - if not prompt or prompt == "" then - return nil - end - - local search_list = {} - - if search_dirs then - table.insert(search_list, search_dirs) - end - - if grep_open_files then - search_list = filelist - end - - return flatten { vimgrep_arguments, additional_args, "--", prompt, search_list } - end, opts.entry_maker or make_entry.gen_from_vimgrep(opts), opts.max_results, opts.cwd) - - pickers.new(opts, { - prompt_title = "Live Grep", - finder = live_grepper, - previewer = conf.grep_previewer(opts), - -- TODO: It would be cool to use `--json` output for this - -- and then we could get the highlight positions directly. - sorter = sorters.highlighter_only(opts), - attach_mappings = function(_, map) - map("i", "<c-space>", function(prompt_bufnr) - local line = action_state.get_current_line() - require("telescope.actions.generate").refine(prompt_bufnr, { - prompt_title = "Find Word (" .. line .. ")", - sorter = conf.generic_sorter(opts), - }) - end) - return true - end, - }):find() -end - --- Special keys: --- opts.search -- the string to search. --- opts.search_dirs -- list of directory to search in --- opts.use_regex -- special characters won't be escaped -files.grep_string = function(opts) - -- TODO: This should probably check your visual selection as well, if you've got one - - local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments - local search_dirs = opts.search_dirs - local word = opts.search or vim.fn.expand "<cword>" - local search = opts.use_regex and word or escape_chars(word) - local word_match = opts.word_match - opts.entry_maker = opts.entry_maker or make_entry.gen_from_vimgrep(opts) - - local title_word = word:gsub("\n", "\\n") - - local additional_args = {} - if opts.additional_args ~= nil and type(opts.additional_args) == "function" then - additional_args = opts.additional_args(opts) - end - - local args = flatten { - vimgrep_arguments, - additional_args, - word_match, - "--", - search, - } - - if search_dirs then - for _, path in ipairs(search_dirs) do - table.insert(args, vim.fn.expand(path)) - end - end - - pickers.new(opts, { - prompt_title = "Find Word (" .. title_word .. ")", - finder = finders.new_oneshot_job(args, opts), - previewer = conf.grep_previewer(opts), - sorter = conf.generic_sorter(opts), - }):find() -end - -files.find_files = function(opts) - local find_command = (function() - if opts.find_command then - if type(opts.find_command) == "function" then - return opts.find_command(opts) - end - return opts.find_command - elseif 1 == vim.fn.executable "fd" then - return { "fd", "--type", "f" } - elseif 1 == vim.fn.executable "fdfind" then - return { "fdfind", "--type", "f" } - elseif 1 == vim.fn.executable "rg" then - return { "rg", "--files" } - elseif 1 == vim.fn.executable "find" and vim.fn.has "win32" == 0 then - return { "find", ".", "-type", "f" } - elseif 1 == vim.fn.executable "where" then - return { "where", "/r", ".", "*" } - end - end)() - - if not find_command then - utils.notify("builtin.find_files", { - msg = "You need to install either find, fd, or rg", - level = "ERROR", - }) - return - end - - local command = find_command[1] - local hidden = opts.hidden - local no_ignore = opts.no_ignore - local no_ignore_parent = opts.no_ignore_parent - local follow = opts.follow - local search_dirs = opts.search_dirs - local search_file = opts.search_file - - if search_dirs then - for k, v in pairs(search_dirs) do - search_dirs[k] = vim.fn.expand(v) - end - end - - if command == "fd" or command == "fdfind" or command == "rg" then - if hidden then - table.insert(find_command, "--hidden") - end - if no_ignore then - table.insert(find_command, "--no-ignore") - end - if no_ignore_parent then - table.insert(find_command, "--no-ignore-parent") - end - if follow then - table.insert(find_command, "-L") - end - if search_file then - if command == "rg" then - table.insert(find_command, "-g") - table.insert(find_command, "*" .. search_file .. "*") - else - table.insert(find_command, search_file) - end - end - if search_dirs then - if command ~= "rg" and not search_file then - table.insert(find_command, ".") - end - for _, v in pairs(search_dirs) do - table.insert(find_command, v) - end - end - elseif command == "find" then - if not hidden then - table.insert(find_command, { "-not", "-path", "*/.*" }) - find_command = flatten(find_command) - end - if no_ignore ~= nil then - log.warn "The `no_ignore` key is not available for the `find` command in `find_files`." - end - if no_ignore_parent ~= nil then - log.warn "The `no_ignore_parent` key is not available for the `find` command in `find_files`." - end - if follow then - table.insert(find_command, 2, "-L") - end - if search_file then - table.insert(find_command, "-name") - table.insert(find_command, "*" .. search_file .. "*") - end - if search_dirs then - table.remove(find_command, 2) - for _, v in pairs(search_dirs) do - table.insert(find_command, 2, v) - end - end - elseif command == "where" then - if hidden ~= nil then - log.warn "The `hidden` key is not available for the Windows `where` command in `find_files`." - end - if no_ignore ~= nil then - log.warn "The `no_ignore` key is not available for the Windows `where` command in `find_files`." - end - if no_ignore_parent ~= nil then - log.warn "The `no_ignore_parent` key is not available for the Windows `where` command in `find_files`." - end - if follow ~= nil then - log.warn "The `follow` key is not available for the Windows `where` command in `find_files`." - end - if search_dirs ~= nil then - log.warn "The `search_dirs` key is not available for the Windows `where` command in `find_files`." - end - if search_file ~= nil then - log.warn "The `search_file` key is not available for the Windows `where` command in `find_files`." - end - end - - if opts.cwd then - opts.cwd = vim.fn.expand(opts.cwd) - end - - opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts) - - pickers.new(opts, { - prompt_title = "Find Files", - finder = finders.new_oneshot_job(find_command, opts), - previewer = conf.file_previewer(opts), - sorter = conf.file_sorter(opts), - }):find() -end - -local function prepare_match(entry, kind) - local entries = {} - - if entry.node then - table.insert(entries, entry) - else - for name, item in pairs(entry) do - vim.list_extend(entries, prepare_match(item, name)) - end - end - - return entries -end - --- TODO: finish docs for opts.show_line -files.treesitter = function(opts) - opts.show_line = vim.F.if_nil(opts.show_line, true) - - local has_nvim_treesitter, _ = pcall(require, "nvim-treesitter") - if not has_nvim_treesitter then - utils.notify("builtin.treesitter", { - msg = "User need to install nvim-treesitter needs to be installed", - level = "ERROR", - }) - return - end - - local parsers = require "nvim-treesitter.parsers" - if not parsers.has_parser(parsers.get_buf_lang(opts.bufnr)) then - utils.notify("builtin.treesitter", { - msg = "No parser for the current buffer", - level = "ERROR", - }) - return - end - - local ts_locals = require "nvim-treesitter.locals" - local results = {} - for _, definition in ipairs(ts_locals.get_definitions(opts.bufnr)) do - local entries = prepare_match(ts_locals.get_local_nodes(definition)) - for _, entry in ipairs(entries) do - entry.kind = vim.F.if_nil(entry.kind, "") - table.insert(results, entry) - end - end - - if vim.tbl_isempty(results) then - return - end - - pickers.new(opts, { - prompt_title = "Treesitter Symbols", - finder = finders.new_table { - results = results, - entry_maker = opts.entry_maker or make_entry.gen_from_treesitter(opts), - }, - previewer = conf.grep_previewer(opts), - sorter = conf.prefilter_sorter { - tag = "kind", - sorter = conf.generic_sorter(opts), - }, - }):find() -end - -files.current_buffer_fuzzy_find = function(opts) - -- All actions are on the current buffer - local filename = vim.fn.expand(vim.api.nvim_buf_get_name(opts.bufnr)) - local filetype = vim.api.nvim_buf_get_option(opts.bufnr, "filetype") - - local lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, false) - local lines_with_numbers = {} - - for lnum, line in ipairs(lines) do - table.insert(lines_with_numbers, { - lnum = lnum, - bufnr = opts.bufnr, - filename = filename, - text = line, - }) - end - - local ts_ok, ts_parsers = pcall(require, "nvim-treesitter.parsers") - if ts_ok then - filetype = ts_parsers.ft_to_lang(filetype) - end - local _, ts_configs = pcall(require, "nvim-treesitter.configs") - - local parser_ok, parser = pcall(vim.treesitter.get_parser, opts.bufnr, filetype) - local query_ok, query = pcall(vim.treesitter.get_query, filetype, "highlights") - if parser_ok and query_ok and ts_ok and ts_configs.is_enabled("highlight", filetype, opts.bufnr) then - local root = parser:parse()[1]:root() - - local highlighter = vim.treesitter.highlighter.new(parser) - local highlighter_query = highlighter:get_query(filetype) - - local line_highlights = setmetatable({}, { - __index = function(t, k) - local obj = {} - rawset(t, k, obj) - return obj - end, - }) - for id, node in query:iter_captures(root, opts.bufnr, 0, -1) do - local hl = highlighter_query:_get_hl_from_capture(id) - if hl and type(hl) ~= "number" then - local row1, col1, row2, col2 = node:range() - - if row1 == row2 then - local row = row1 + 1 - - for index = col1, col2 do - line_highlights[row][index] = hl - end - else - local row = row1 + 1 - for index = col1, #lines[row] do - line_highlights[row][index] = hl - end - - while row < row2 + 1 do - row = row + 1 - - for index = 0, #(lines[row] or {}) do - line_highlights[row][index] = hl - end - end - end - end - end - - opts.line_highlights = line_highlights - end - - pickers.new(opts, { - prompt_title = "Current Buffer Fuzzy", - finder = finders.new_table { - results = lines_with_numbers, - entry_maker = opts.entry_maker or make_entry.gen_from_buffer_lines(opts), - }, - sorter = conf.generic_sorter(opts), - previewer = conf.grep_previewer(opts), - attach_mappings = function() - action_set.select:enhance { - post = function() - local selection = action_state.get_selected_entry() - vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 }) - end, - } - - return true - end, - }):find() -end - -files.tags = function(opts) - local tagfiles = opts.ctags_file and { opts.ctags_file } or vim.fn.tagfiles() - for i, ctags_file in ipairs(tagfiles) do - tagfiles[i] = vim.fn.expand(ctags_file, true) - end - if vim.tbl_isempty(tagfiles) then - utils.notify("builtin.tags", { - msg = "No tags file found. Create one with ctags -R", +local m = setmetatable({}, { + __index = function(_, k) + local utils = require "telescope.utils" + utils.notify("builtin", { + msg = string.format( + 'You are using an internal interface. Do not use `require("telescope.builtin.files").%s`,' + .. ' please use `require("telescope.builtin").%s`! We will remove this endpoint soon!', + k, + k + ), level = "ERROR", }) - return - end - opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_ctags(opts)) - - pickers.new(opts, { - prompt_title = "Tags", - finder = finders.new_oneshot_job(flatten { "cat", tagfiles }, opts), - previewer = previewers.ctags.new(opts), - sorter = conf.generic_sorter(opts), - attach_mappings = function() - action_set.select:enhance { - post = function() - local selection = action_state.get_selected_entry() - if not selection then - return - end - - if selection.scode then - -- un-escape / then escape required - -- special chars for vim.fn.search() - -- ] ~ * - local scode = selection.scode:gsub([[\/]], "/"):gsub("[%]~*]", function(x) - return "\\" .. x - end) - - vim.cmd "norm! gg" - vim.fn.search(scode) - vim.cmd "norm! zz" - else - vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 }) - end - end, - } - return true - end, - }):find() -end - -files.current_buffer_tags = function(opts) - return files.tags(vim.tbl_extend("force", { - prompt_title = "Current Buffer Tags", - only_current_file = true, - path_display = "hidden", - }, opts)) -end - -local function apply_checks(mod) - for k, v in pairs(mod) do - mod[k] = function(opts) - opts = opts or {} - - v(opts) - end - end - - return mod -end + return require("telescope.builtin")[k] + end, +}) -return apply_checks(files) +return m |
