From d95b2c4f5588a947c4b04a53f31073281d490e76 Mon Sep 17 00:00:00 2001 From: Kim Gert Nielsen Date: Tue, 3 Dec 2024 14:41:42 +0100 Subject: [PATCH] Add support for fzf --- README.md | 109 ++++++++++++++++-- lua/agrolens/config.lua | 54 +++++++++ lua/agrolens/core.lua | 71 +++++++++++- lua/agrolens/fzf.lua | 83 +++++++++++++ lua/agrolens/init.lua | 14 ++- .../_extensions => agrolens}/utils.lua | 37 ------ lua/telescope/_extensions/agrolenslib.lua | 83 +------------ tests/utils_spec.lua | 8 +- 8 files changed, 331 insertions(+), 128 deletions(-) create mode 100644 lua/agrolens/config.lua create mode 100644 lua/agrolens/fzf.lua rename lua/{telescope/_extensions => agrolens}/utils.lua (62%) diff --git a/README.md b/README.md index d6765f0..641b8af 100644 --- a/README.md +++ b/README.md @@ -13,19 +13,113 @@ Its an extention to telescope that runs pre-defined (or custom) tree-sitter quer [Neovim 0.10+](https://github.com/neovim/neovim) +[Nvim tree-sitter](https://github.com/nvim-treesitter/nvim-treesitter) + +Language specific tree-sitter support is also needed (Depends on your needs) + +Support for telescope requires: + [Telescope](https://github.com/nvim-telescope/telescope.nvim) [Plenary](https://github.com/nvim-lua/plenary.nvim) -[Nvim tree-sitter](https://github.com/nvim-treesitter/nvim-treesitter) +Support for fzf requires: + +[Fzf-lua](https://github.com/ibhagwan/fzf-lua) + + +# Default options + +Options are the same for fzf and telescope they are just added in different places + +```lua +{ + -- Enable/Disable debug messages (is put in ~/.cache/nvim/agrolens.log) + debug = false, + + -- Some tree-sitter plugins uses hidden buffers + -- and we can enable those to if we want + include_hidden_buffers = false, + + -- Make sure the query only runs on + -- same filetype as the current one + same_type = true, + + -- Match a given string or object + -- Example `:Telescope agrolens query=callings buffers=all same_type=false match=name,object` + -- this will query all callings but only those who match the word on the cursor + match = nil, + + -- Disable displaying indententations in telescope + disable_indentation = false, + + -- Alias can be used to join several queries into a single name + -- Example: `aliases = { yamllist = "docker-compose,github-workflow-steps"}` + aliases = {}, + + -- Several internal functions can also be overwritten + -- + -- Default entry maker (telescope only) + -- entry_maker = agrolens.entry_maker + -- + -- Default way of finding current directory + -- cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.uv.cwd() + -- + -- Default previewer (telescope only) + -- previewer = conf.grep_previewer(opts) + -- + -- Default sorting (telescope only) + -- sorter = conf.generic_sorter(opts) + + -- Default enable devicons + disable_devicons = false, + + -- display length + display_width = 150, + + -- force long path name even when only a single buffer + force_long_filepath = false, +} +``` -And the language you with to use is also required to be installed via Nvim tree-sitter +# Setup -# Installation +
Fzf + +```lua +{ + "desdic/agrolens.nvim", + opts = { + force_long_filepath = true, + debug = false, + same_type = false, + include_hidden_buffers = false, + disable_indentation = true, + aliases = { + yamllist = "docker-compose,github-workflow-steps", + work = "cheflxchost,github-workflow-steps,pytest,ipam", + all = "cheflxchost,pytest,ipam,functions,labels", + }, + }, + keys = { + { + "zu", + function() + require("agrolens.fzf").run({ + query = "functions,labels", + buffers = "all", + same_type = false, + }) + end, + desc = "find functions and labels", + }, + }, +} +``` -Install +
-Use your favorite plugin manager +
Telescope ```lua "desdic/agrolens.nvim" @@ -50,8 +144,10 @@ require("telescope").extensions = { } } ``` +
+ -# Usage +# Usage via Telescope ``` :Telescope agrolens @@ -115,7 +211,6 @@ Jump to next match in query `work` Using aliases its possible to create a new query name where its a list of other queries like ``` -agrolens = { ... aliases = { yamllist = "docker-compose,github-workflow-steps", diff --git a/lua/agrolens/config.lua b/lua/agrolens/config.lua new file mode 100644 index 0000000..92c76ba --- /dev/null +++ b/lua/agrolens/config.lua @@ -0,0 +1,54 @@ +local config = {} + +--- Default telescope options: +---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section) +config.opts = { + -- Enable/Disable debug messages (is put in ~/.cache/nvim/agrolens.log) + debug = false, + + -- Some tree-sitter plugins uses hidden buffers + -- and we can enable those to if we want + include_hidden_buffers = false, + + -- Make sure the query only runs on + -- same filetype as the current one + same_type = true, + + -- Match a given string or object + -- Example `:Telescope agrolens query=callings buffers=all same_type=false match=name,object` + -- this will query all callings but only those who match the word on the cursor + match = nil, + + -- Disable displaying indententations in telescope + disable_indentation = false, + + -- Alias can be used to join several queries into a single name + -- Example: `aliases = { yamllist = "docker-compose,github-workflow-steps"}` + aliases = {}, + + -- Several internal functions can also be overwritten + -- + -- Default entry maker + -- entry_maker = agrolens.entry_maker + -- + -- Default way of finding current directory + -- cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.uv.cwd() + -- + -- Default previewer + -- previewer = conf.grep_previewer(opts) + -- + -- Default sorting + -- sorter = conf.generic_sorter(opts) + + -- Default enable devicons + disable_devicons = false, + + -- display length + display_width = 150, + + -- force long path name even when only a single buffer + force_long_filepath = false, +} +--minidoc_afterlines_end + +return config diff --git a/lua/agrolens/core.lua b/lua/agrolens/core.lua index bbfee87..e5c5f4f 100644 --- a/lua/agrolens/core.lua +++ b/lua/agrolens/core.lua @@ -1,6 +1,6 @@ local M = {} -local utils = require("telescope._extensions.utils") +local utils = require("agrolens.utils") local ppath = require("plenary.path") local empty = vim.tbl_isempty local len = vim.tbl_count @@ -220,4 +220,73 @@ M.sanitize_opts = function(opts, telescope_opts, telescope_config) return opts end +M.make_bufferlist = function(opts) + local buffers = {} + + for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + if + opts.same_type == false + or vim.filetype.match({ buf = bufnr }) == opts.cur_type + then + if opts.include_hidden_buffers == false then + if vim.fn.getbufinfo(bufnr)[1].listed == 1 then + table.insert(buffers, bufnr) + end + else + table.insert(buffers, bufnr) + end + end + end + return buffers +end + +M.get_buffers = function(opts) + local curbuf = vim.api.nvim_get_current_buf() + + opts.cur_type = vim.filetype.match({ buf = curbuf }) + + local bufids = { curbuf } + if opts.buffers and type(opts.buffers) == "string" then + if opts.buffers == "all" then + bufids[curbuf] = nil + bufids = M.make_bufferlist(opts) + end + end + opts.bufids = bufids + + return opts +end + +M.jump_to_buffer_line = function(bufnr, row, col) + vim.api.nvim_set_current_buf(bufnr) + + pcall(function() + vim.api.nvim_win_set_cursor(0, { + row or 1, + col or 0, + }) + end) +end + +M.jump_next = function(curline, jumplist) + table.sort(jumplist) + for _, line in pairs(jumplist) do + if line > curline then + vim.api.nvim_win_set_cursor(0, { line, 0 }) + break + end + end +end + +M.jump_prev = function(curline, jumplist) + table.sort(jumplist, function(a, b) + return a > b + end) + for _, line in pairs(jumplist) do + if line < curline then + vim.api.nvim_win_set_cursor(0, { line, 0 }) + break + end + end +end return M diff --git a/lua/agrolens/fzf.lua b/lua/agrolens/fzf.lua new file mode 100644 index 0000000..69bd170 --- /dev/null +++ b/lua/agrolens/fzf.lua @@ -0,0 +1,83 @@ +local fzf = {} +local core = require("agrolens.core") + +local contents = {} + +local fzf_lua = require("fzf-lua") +local builtin = require("fzf-lua.previewer.builtin") +local fzfpreview = builtin.buffer_or_file:extend() + +function fzfpreview:new(o, opts, fzf_win) + fzfpreview.super.new(self, o, opts, fzf_win) + setmetatable(self, fzfpreview) + return self +end + +function fzfpreview.parse_entry(_, entry_str) + if entry_str == "" then + return {} + end + + local entry = contents[entry_str] + return { + path = entry.filename, + line = entry.lnum or 1, + col = 1, + } +end + +fzf.run = function(args) + local opts = {} + local cfg = require("agrolens.config").opts + + opts = core.sanitize_opts(opts, cfg, args) + + opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.uv.cwd() + opts = core.get_buffers(opts) + + if opts.jump then + local jumplist = core.generate_jump_list(opts) + local curline = vim.api.nvim_win_get_cursor(0)[1] + + if opts.jump == "next" then + core.jump_next(curline, jumplist) + elseif opts.jump == "prev" then + core.jump_prev(curline, jumplist) + end + else + fzf_lua.fzf_exec(function(fzf_cb) + local results = core.get_captures(opts) + for _, b in ipairs(results) do + local fname = b.relfilename + + if opts.force_long_filepath ~= true then + fname = vim.fs.basename(b.filename) + end + + local key = fname .. ":" .. b.lnum .. ":" .. b.line + contents[key] = b + fzf_cb(key) + end + fzf_cb() + end, { + previewer = fzfpreview, + prompt = "Agrolens> ", + actions = { + ["enter"] = { + fn = function(selected) + local entry = contents[selected[1]] + + core.jump_to_buffer_line( + entry.bufnr, + entry.lnum, + entry.col + ) + end, + silent = true, + }, + }, + }) + end +end + +return fzf diff --git a/lua/agrolens/init.lua b/lua/agrolens/init.lua index edfe991..03b67e7 100644 --- a/lua/agrolens/init.lua +++ b/lua/agrolens/init.lua @@ -61,7 +61,7 @@ agrolens.opts = { --minidoc_afterlines_end local ts_utils = require("nvim-treesitter.ts_utils") -local agroutils = require("telescope._extensions.utils") +local utils = require("agrolens.utils") local empty = vim.tbl_isempty local len = vim.tbl_count @@ -229,7 +229,7 @@ end agrolens.match_line = function(block, line, captures, capindex) local pattern = "^%s*" - .. escape_pattern(agroutils.ltrim(block.node_text)) + .. escape_pattern(utils.ltrim(block.node_text)) .. "$" local matches = string.match(line, pattern) @@ -328,4 +328,14 @@ agrolens.generate = function(opts) end end +agrolens.setup = function(options) + agrolens.config = require("agrolens.config").opts + + if options ~= nil then + for k, v in pairs(options) do + agrolens.config[k] = v + end + end +end + return agrolens diff --git a/lua/telescope/_extensions/utils.lua b/lua/agrolens/utils.lua similarity index 62% rename from lua/telescope/_extensions/utils.lua rename to lua/agrolens/utils.lua index 2489926..26a9860 100644 --- a/lua/telescope/_extensions/utils.lua +++ b/lua/agrolens/utils.lua @@ -68,41 +68,4 @@ M.hash_keys_to_list = function(entries) return list end -M.make_bufferlist = function(opts) - local buffers = {} - - for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do - if - opts.same_type == false - or vim.filetype.match({ buf = bufnr }) == opts.cur_type - then - if opts.include_hidden_buffers == false then - if vim.fn.getbufinfo(bufnr)[1].listed == 1 then - table.insert(buffers, bufnr) - end - else - table.insert(buffers, bufnr) - end - end - end - return buffers -end - -M.get_buffers = function(opts) - local curbuf = vim.api.nvim_get_current_buf() - - opts.cur_type = vim.filetype.match({ buf = curbuf }) - - local bufids = { curbuf } - if opts.buffers and type(opts.buffers) == "string" then - if opts.buffers == "all" then - bufids[curbuf] = nil - bufids = M.make_bufferlist(opts) - end - end - opts.bufids = bufids - - return opts -end - return M diff --git a/lua/telescope/_extensions/agrolenslib.lua b/lua/telescope/_extensions/agrolenslib.lua index b7d6f60..d8cd93d 100644 --- a/lua/telescope/_extensions/agrolenslib.lua +++ b/lua/telescope/_extensions/agrolenslib.lua @@ -2,84 +2,13 @@ local pickers = require("telescope.pickers") local finders = require("telescope.finders") local actions = require("telescope.actions") local conf = require("telescope.config").values -local utils = require("telescope._extensions.utils") +local utils = require("agrolens.utils") local core = require("agrolens.core") local entry_display = require("telescope.pickers.entry_display") local agrolens = {} ---- Default telescope options: ----@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section) -agrolens.telescope_opts = { - -- Enable/Disable debug messages (is put in ~/.cache/nvim/agrolens.log) - debug = false, - - -- Some tree-sitter plugins uses hidden buffers - -- and we can enable those to if we want - include_hidden_buffers = false, - - -- Make sure the query only runs on - -- same filetype as the current one - same_type = true, - - -- Match a given string or object - -- Example `:Telescope agrolens query=callings buffers=all same_type=false match=name,object` - -- this will query all callings but only those who match the word on the cursor - match = nil, - - -- Disable displaying indententations in telescope - disable_indentation = false, - - -- Alias can be used to join several queries into a single name - -- Example: `aliases = { yamllist = "docker-compose,github-workflow-steps"}` - aliases = {}, - - -- Several internal functions can also be overwritten - -- - -- Default entry maker - -- entry_maker = agrolens.entry_maker - -- - -- Default way of finding current directory - -- cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.uv.cwd() - -- - -- Default previewer - -- previewer = conf.grep_previewer(opts) - -- - -- Default sorting - -- sorter = conf.generic_sorter(opts) - - -- Default enable devicons - disable_devicons = false, - - -- display length - display_width = 150, - - -- force long path name even when only a single buffer - force_long_filepath = false, -} ---minidoc_afterlines_end - -agrolens.jump_next = function(curline, jumplist) - table.sort(jumplist) - for _, line in pairs(jumplist) do - if line > curline then - vim.api.nvim_win_set_cursor(0, { line, 0 }) - break - end - end -end - -agrolens.jump_prev = function(curline, jumplist) - table.sort(jumplist, function(a, b) - return a > b - end) - for _, line in pairs(jumplist) do - if line < curline then - vim.api.nvim_win_set_cursor(0, { line, 0 }) - break - end - end -end +agrolens.telescope_opts = require("agrolens.config").opts agrolens.entry_maker = function(entry) local basename = vim.fs.basename(entry.filename) @@ -103,8 +32,6 @@ agrolens.entry_maker = function(entry) and agrolens.telescope_opts.force_long_filepath ~= true then fname = vim.fs.basename(entry.filename) - -- else - -- fname = ppath:new(fname):make_relative(agrolens.cur_opts.cwd) end local line = fname @@ -173,16 +100,16 @@ agrolens.run = function(opts) opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.uv.cwd() opts.previewer = opts.previewer or conf.grep_previewer(opts) opts.sorter = opts.sorter or conf.generic_sorter(opts) - opts = utils.get_buffers(opts) + opts = core.get_buffers(opts) if opts.jump then local jumplist = core.generate_jump_list(opts) local curline = vim.api.nvim_win_get_cursor(0)[1] if opts.jump == "next" then - agrolens.jump_next(curline, jumplist) + core.jump_next(curline, jumplist) elseif opts.jump == "prev" then - agrolens.jump_prev(curline, jumplist) + core.jump_prev(curline, jumplist) end else pickers diff --git a/tests/utils_spec.lua b/tests/utils_spec.lua index af593d8..dba7d07 100644 --- a/tests/utils_spec.lua +++ b/tests/utils_spec.lua @@ -1,5 +1,5 @@ describe("utils", function() - local utils = require("telescope._extensions.utils") + local utils = require("agrolens.utils") local eq = assert.equals @@ -15,7 +15,10 @@ describe("utils", function() it("file_extention", function() eq(utils.file_extension(vim.fs.basename("/home/myuser/test.go")), "go") - eq(utils.file_extension(vim.fs.basename("/home/myuser/test.test.js")), "test.js") + eq( + utils.file_extension(vim.fs.basename("/home/myuser/test.test.js")), + "test.js" + ) end) it("matchstr", function() @@ -29,5 +32,4 @@ describe("utils", function() eq(elems[2], "test2") eq(elems[3], " test3") end) - end)