fzf-lua icon indicating copy to clipboard operation
fzf-lua copied to clipboard

Feature: add a combined picker between buffers & git_files/files

Open LoricAndre opened this issue 9 months ago • 6 comments

Have you RTFM'd?

  • [x] I have done proper research

Feature Request

I'd love a picker that would show me my open buffers at the top, then show me files (or git_files, I'm not so sure). I tried building it from the public API but most utility functions are local which makes it quite complicated to implement robustly and maintain with future changes. More generally (but probably harder), it would be interesting to be able to combine multiple pickers, and be able to specify the ordering.

LoricAndre avatar Mar 12 '25 13:03 LoricAndre

Note: a way for me to build something like this in my config would be to expose the contents for specific pickers, that I could retrieve and try to combine myself

LoricAndre avatar Mar 12 '25 13:03 LoricAndre

For now, I put this together, but I'm still missing the icons for the buffers and some robustness:

function FzfLuaSmart(opts)
  local config = require('fzf-lua.config')
  local core = require('fzf-lua.core')
  local path = require('fzf-lua.path')
  local libuv = require('fzf-lua.libuv')
  local make_entry = require('fzf-lua.make_entry')
  opts = config.normalize_opts(opts, 'git.files')
  if not opts then
    return
  end
  opts.cwd = path.git_root(opts)
  opts.git_icons = true
  opts.file_icons = true
  if not opts.cwd then
    return
  end
  local git_cmd = core.mt_cmd_wrapper(opts)
  local git_fn = libuv.spawn_nvim_fzf_cmd({
    cmd = git_cmd,
    cwd = opts.cwd,
    cb_pid = function(pid)
      opts.__pid = pid
    end,
  })
  local contents = function(x, cb, y)
    make_entry.preprocess(opts)
    for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do
      if
        vim.api.nvim_buf_is_loaded(buf_id) and vim.fn.buflisted(buf_id) == 1
      then
        local p = vim.api.nvim_buf_get_name(buf_id)
        local exists, stats = pcall(vim.uv.fs_stat, p)
        if exists and stats and stats.type == 'file' then
          cb(make_entry.file(p .. '\n', opts))
        end
      end
    end

    git_fn(x, cb, y)
  end
  opts = core.set_header(opts, opts.headers or { 'cwd' })
  return core.fzf_exec(contents, opts)
end

LoricAndre avatar Mar 12 '25 14:03 LoricAndre

Maybe in this way you can get icons for buffer:

@@ -31,7 +31,7 @@ function FzfLuaSmart(opts)
         local p = vim.api.nvim_buf_get_name(buf_id)
         local exists, stats = pcall(vim.uv.fs_stat, p)
         if exists and stats and stats.type == "file" then
-          cb(make_entry.file(p .. "\n", opts))
+          x(make_entry.file(p, opts))
         end
       end
     end

Maybe there's other ways for this purpose, e.g. give a higher priority for atime when using fd/find/fzf (but they seems don't support this feature natively...)

phanen avatar Mar 12 '25 14:03 phanen

Thanks ! This works for the icons. As a skim maintainer, I can see a few way to do something like sorting using the atime` (using nth/with-nth for instance), but I don't think that's really what I want for now.

Note: I wasn't able to find much about these arguments (hence the x and y). Where can I find some to better understand it ?

LoricAndre avatar Mar 13 '25 17:03 LoricAndre

Note: a way for me to build something like this in my config would be to expose the contents for specific pickers, that I could retrieve and try to combine myself

That’s def the better approach which I started working towards, lsp_finder has been using a contents array for a long time now: https://github.com/ibhagwan/fzf-lua/blob/15d5cd9a74da7f8739030a5c411c046c70f66a60/lua/fzf-lua/core.lua#L149-L152

The issue I’m facing with these type of pickers is combing buffers which is lua type contents with files that is an external shell command (with a neovim headless wrapper), ATM these can’t be combined as it means I’d have to transfer the entire current state of the main instance to the headless instance to get buffers working properly.

Obviously we can use the simple approach and call vim.system for the files enumeration but that wouldn’t be performant and thus defeating the purpose IMHO.

Note: I wasn't able to find much about these arguments (hence the x and y). Where can I find some to better understand it ?

https://github.com/ibhagwan/fzf-lua/blob/15d5cd9a74da7f8739030a5c411c046c70f66a60/lua/fzf-lua/fzf.lua#L171-L174

We could always improve on docs and annotations, these didn’t even exist properly with lua_la when I started this project…

ibhagwan avatar Mar 13 '25 17:03 ibhagwan

I've come here looking for exactly such a function! thanks so much!

dycw avatar Jun 08 '25 00:06 dycw

FYI, once #2152 is merged (still needs work but it’s getting there), we’ll be able to combine pickers as easy as :FzfLua combine pickers=oldfiles,files (I’m not 100% set on the syntax/naming but something like this).

ibhagwan avatar Jul 05 '25 23:07 ibhagwan

The PR still needs more work but you can try it out now in refactor_contents branch, and use:

:FzfLua combine pickers=buffers,git_files
-- Can even do something as useless as:
:FzfLua combine pickers=buffers,lsp_finder,git_status

This is just the first commit on this so expect bugs :-)

Image

ibhagwan avatar Jul 13 '25 04:07 ibhagwan

Closed via #2152, probably needs improvements, will open new issues for bugs/improvements.

ibhagwan avatar Jul 17 '25 14:07 ibhagwan