diff --git a/lua/telescope/builtin/init.lua b/lua/telescope/builtin/init.lua index 2336a42..80c1f3f 100644 --- a/lua/telescope/builtin/init.lua +++ b/lua/telescope/builtin/init.lua @@ -923,4 +923,54 @@ builtin.keymaps = function(opts) }):find() end +builtin.tags = function(opts) + opts = opts or {} + + local ctags_file = opts.ctags_file or 'tags' + + if not vim.loop.fs_open(vim.fn.expand(ctags_file), "r", 438) then + print('Tags file does not exists. Create one with ctags -R') + return + end + + local fd = assert(vim.loop.fs_open(vim.fn.expand(ctags_file), "r", 438)) + local stat = assert(vim.loop.fs_fstat(fd)) + local data = assert(vim.loop.fs_read(fd, stat.size, 0)) + assert(vim.loop.fs_close(fd)) + + local results = vim.split(data, '\n') + + pickers.new(opts,{ + prompt = 'Tags', + finder = finders.new_table { + results = results, + entry_maker = make_entry.gen_from_ctags(opts), + }, + previewer = previewers.ctags.new(opts), + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr) + actions._goto_file_selection:enhance { + post = function() + local selection = actions.get_selected_entry(prompt_bufnr) + + local scode = string.gsub(selection.scode, '[$]$', '') + scode = string.gsub(scode, [[\\]], [[\]]) + scode = string.gsub(scode, [[\/]], [[/]]) + scode = string.gsub(scode, '[*]', [[\*]]) + + vim.cmd('norm! gg') + vim.fn.search(scode) + vim.cmd('norm! zz') + end, + } + return true + end + }):find() +end + +builtin.current_buffer_tags = function(opts) + opts = opts or {} + return builtin.tags(vim.tbl_extend("force", {only_current_file = true, hide_filename = true}, opts)) +end + return builtin diff --git a/lua/telescope/make_entry.lua b/lua/telescope/make_entry.lua index 906eb95..57344ab 100644 --- a/lua/telescope/make_entry.lua +++ b/lua/telescope/make_entry.lua @@ -559,4 +559,73 @@ function make_entry.gen_from_vimoptions(opts) end end +function make_entry.gen_from_ctags(opts) + opts = opts or {} + + local cwd = vim.fn.expand(opts.cwd or vim.fn.getcwd()) + local current_file = path.normalize(vim.fn.expand('%'), cwd) + + local display_items = { + { width = 30 }, + { remaining = true }, + } + + if opts.show_line then + table.insert(display_items, 2, { width = 30 }) + end + + local displayer = entry_display.create { + separator = " │ ", + items = display_items, + } + + local make_display = function(entry) + local filename + if not opts.hide_filename then + if opts.shorten_path then + filename = path.shorten(entry.filename) + else + filename = entry.filename + end + end + + local scode + if opts.show_line then + scode = entry.scode + end + + return displayer { + filename, + entry.tag, + scode, + } + end + + return function(line) + if line == '' or line:sub(1, 1) == '!' then + return nil + end + + local tag, file, scode = string.match(line, '([^\t]+)\t([^\t]+)\t/^\t?(.*)/;"\t+.*') + + if opts.only_current_file and file ~= current_file then + return nil + end + + return { + valid = true, + + ordinal = file .. ': ' .. tag, + display = make_display, + scode = scode, + tag = tag, + + filename = file, + + col = 1, + lnum = 1, + } + end +end + return make_entry diff --git a/lua/telescope/pickers/entry_display.lua b/lua/telescope/pickers/entry_display.lua index c661b89..aef3047 100644 --- a/lua/telescope/pickers/entry_display.lua +++ b/lua/telescope/pickers/entry_display.lua @@ -43,8 +43,8 @@ end local function truncate(str, len) -- TODO: This doesn't handle multi byte chars... - if vim.fn.strdisplaywidth(str) > len - 1 then - str = str:sub(1, len) + if vim.fn.strdisplaywidth(str) > len then + str = str:sub(1, len - 1) str = str .. "…" end return str @@ -68,8 +68,10 @@ entry_display.create = function(configuration) return function(self, picker) local results = {} - for k, v in ipairs(self) do - table.insert(results, generator[k](v, picker)) + for i = 1, table.getn(generator) do + if self[i] ~= nil then + table.insert(results, generator[i](self[i], picker)) + end end return table.concat(results, configuration.separator or "│") diff --git a/lua/telescope/previewers.lua b/lua/telescope/previewers.lua index d85d149..29442fa 100644 --- a/lua/telescope/previewers.lua +++ b/lua/telescope/previewers.lua @@ -400,6 +400,46 @@ previewers.vimgrep = defaulter(function(opts) } end, {}) +previewers.ctags = defaulter(function(opts) + return previewers.new { + setup = function() + return {} + end, + + teardown = function(self) + if self.state and self.state.hl_id then + pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win) + self.state.hl_id = nil + end + end, + + preview_fn = function(self, entry, status) + with_preview_window(status, nil, function() + local scode = string.gsub(entry.scode, '[$]$', '') + scode = string.gsub(scode, [[\\]], [[\]]) + scode = string.gsub(scode, [[\/]], [[/]]) + scode = string.gsub(scode, '[*]', [[\*]]) + + local new_bufnr = vim.fn.bufnr(entry.filename, true) + vim.fn.bufload(new_bufnr) + + vim.api.nvim_win_set_buf(status.preview_win, new_bufnr) + vim.api.nvim_win_set_option(status.preview_win, 'wrap', false) + vim.api.nvim_win_set_option(status.preview_win, 'winhl', 'Normal:Normal') + vim.api.nvim_win_set_option(status.preview_win, 'signcolumn', 'no') + vim.api.nvim_win_set_option(status.preview_win, 'foldlevel', 100) + + pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win) + vim.fn.search(scode) + vim.cmd "norm zz" + + self.state.hl_win = status.preview_win + self.state.hl_id = vim.fn.matchadd('Search', scode) + end) + end + } +end, {}) + previewers.qflist = defaulter(function(opts) opts = opts or {}