diff options
| author | Simon Hauser <Simon-Hauser@outlook.de> | 2022-07-01 22:20:12 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-01 22:20:12 +0200 |
| commit | 0621c1c6ba3e561dfb06f58a7b0aedfcd464b590 (patch) | |
| tree | ab54eeabbb23e167c652d81553a0f3ddc365ae0b /lua/telescope/builtin/__files.lua | |
| parent | bf1a25dbfe9a4368b10354cb46e4b3a0ab0a41a4 (diff) | |
break: prefix internal files and add deprecation messages (#2032)
Diffstat (limited to 'lua/telescope/builtin/__files.lua')
| -rw-r--r-- | lua/telescope/builtin/__files.lua | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/lua/telescope/builtin/__files.lua b/lua/telescope/builtin/__files.lua new file mode 100644 index 0000000..dddd18a --- /dev/null +++ b/lua/telescope/builtin/__files.lua @@ -0,0 +1,522 @@ +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", + 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 apply_checks(files) |
