Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Switch picker without leaving fzf-window #974

Closed
Bekaboo opened this issue Dec 30, 2023 · 19 comments
Closed

[Question] Switch picker without leaving fzf-window #974

Bekaboo opened this issue Dec 30, 2023 · 19 comments
Labels
question Further information is requested

Comments

@Bekaboo
Copy link
Contributor

Bekaboo commented Dec 30, 2023

Info

Not related

Description

First of all thanks for making such a great plugin. fzf-lua is fast, responsive, and feature-rich, I cannot use neovim without it.

I sometimes find myself using the wrong picker only after I have typed several words in the search prompt, e.g. I was meant to live grep patterns in the project but I opened fzf files picker. In this case I want to switch to the live grep picker without leaving fzf window and perserve the previous cwd and the contents in the search prompt, but I haven't found a good way to achieve that.

Currently, I can map <C-_> in the on_create callback to fzf.builtin to switch picker without leaving fzf window, like this:

local fzf = require('fzf-lua')

fzf.setup({
  winopts = {
    on_create = function()
      vim.keymap.set('t', '<C-_>', fzf.builtin, { buffer = true })
    end,
  },
})

But this method has two drawbacks:

  1. It does not preserve the contents in the search prompt
  2. It does not keep previous search cwd

Could you please give me some hints or guidance on how to achieve this? Thanks!

@ibhagwan
Copy link
Owner

First of all thanks for making such a great plugin. fzf-lua is fast, responsive, and feature-rich, I cannot use neovim without it.

Ty for your kind words @Bekaboo!

Your request is possible but it would require a bit more involved code as you’ll need to pass the new options to the new provider.

It does not preserve the contents in the search prompt

You can access the last query with require('fzf-lua').get_info().last_query.

It does not keep previous search cwd

While a bit more hacky, the last cwd (and all other call options) can be found in the last resume options require('fzf-lua').config.__resume_opts.cwd

@ibhagwan ibhagwan added the question Further information is requested label Dec 30, 2023
@Bekaboo
Copy link
Contributor Author

Bekaboo commented Dec 30, 2023

Hi thanks for your reply, after searching in the source code I find another function require('fzf-lua').get_last_query() is it the suggested way of getting the last query than require('fzf-lua').get_info().last_query()?

I tried them both but none of them seems to work, here is my config:

local fzf = require('fzf-lua')

fzf.setup({
  winopts = {
    on_create = function()
      vim.keymap.set('t', '<C-_>', function()
        -- fzf.builtin()
        -- vim.api.nvim_feedkeys('�', 'n', true)
        local info_last_query = fzf.get_info().last_query
        local last_query = fzf.get_last_query()
        local resume_opts = fzf.config.__resume_opts
        print('info_last_query: ' .. vim.inspect(info_last_query))
        print('last_query: ' .. vim.inspect(last_query))
        print('resume_opts: ' .. vim.inspect(resume_opts))
      end, { buffer = true })
    end,
  },
})

All three values (info_last_query, last_query, and resume_opts) are nil after I press <C-_> in fzf window. I've tried to call fzf.builtin() first and close the fzf window first but that does not help. What am I doing wrong here?

@ibhagwan
Copy link
Owner

You’re correct get_last_query is better, I think info doesn’t even have the last query, my bad :)

The issue we have here is that you’re opening the builtin interface which also overrides the last query, there is also config.__resume_map which has resume values per provider but that means you’ll need to know which was the last interface used, I’ll think of something and do some testing and let you know how we can achieve what you’re after.

@ibhagwan
Copy link
Owner

Another issue I see here is that you’re using a mapping in winopts.on_create, this abruptly closes the interface and opens another instead which also prevents the last query from being stored, this is better done via an action mapping.

@ibhagwan
Copy link
Owner

The below adds the functionality you're after for all files providers, if you wish to do that for buffers as well you'd need to also configure actions.buffers:

local fzf = require('fzf-lua')
local actions = fzf.actions

fzf.setup({
  actions = {
    files = {
      ["default"] = actions.file_edit_or_qf,
      ["ctrl-s"]  = actions.file_split,
      ["ctrl-v"]  = actions.file_vsplit,
      ["ctrl-t"]  = actions.file_tabedit,
      ["alt-q"]   = actions.file_sel_to_qf,
      ["alt-l"]   = actions.file_sel_to_ll,
      ["ctrl-_"]  = {
        function()
          local opts = {
            query = fzf.config.__resume_data.last_query,
            cwd = fzf.config.__resume_data.opts.cwd,
          }
          fzf.builtin({
            actions = {
              ["default"] = function(selected)
                fzf[selected[1]](opts)
              end,
            }
          })
        end
      },
    },
  },
})

@Bekaboo
Copy link
Contributor Author

Bekaboo commented Dec 31, 2023

Thanks, it works incredibly well!

@Bekaboo Bekaboo closed this as completed Dec 31, 2023
@hexh250786313
Copy link

I encountered a similar problem, but with a slight difference. I attempted to create a finder that displays the MRU list when the query is empty, and shows the results from fd when the query is not empty.

I wasn't sure how to handle this 'switcher' with fzf-lua, so I ended up implementing it using the vanilla junegunn/fzf, using --bind=change:reload(dynamic_fzf_source.sh)

If possible, could anyone offer me some suggestions?

@ibhagwan
Copy link
Owner

ibhagwan commented Jan 2, 2024

@hexh250786313, you are tryin to mix and match a “live” reload mechanism with fuzzy matching, while possible it’s a bit tricky, if we ignore for a second displaying the MRU on backspace you can change back to fuzzy with enable-search:

--bind "change:reload(fd …)+unbind(change)+change-prompt(fd> )+enable-search"

It might be possible to create go back to the MRU on backspace with a condition that tests the query with {q} but that means you can’t unbind change. This is just atop of my head, I might be able to come up with something better if I think about this longer :)

@dan-cooke
Copy link

@ibhagwan is it possible to achieve this kind of thing within fzf-lua?

@ibhagwan
Copy link
Owner

@ibhagwan is it possible to achieve this kind of thing within fzf-lua?

Not really sure what you’re asking, this is an old issue, by “this kind of thing” do you mean the OP/title or something else? Whatever the question may be it probably is possible depending on how much effort you’re willing to invest.

@dan-cooke
Copy link

@ibhagwan apologies I mean the MRU/files switch that @hexh250786313 was asking about

@ibhagwan
Copy link
Owner

ibhagwan commented Mar 10, 2024

@dan-cooke, my answer #974 (comment) still stands, I can also think of another solution using the libuv headless wrapper used by fzf-lua, take a look at rg_glob_fn from #373, but then again it won’t be fuzzy search since it’s for live_grep.

I can think of many different approaches, all requires to make use of fzf’s change:… event, if you’re serious about it you’ll have to do some reading of the fzf manual and issues to understand how to use it and what’s possible, anything that can be done with vanilla fzf can be done with fzf-lua (with richer functionality), once you have basic code that does what you want I can help you refine it.

@dan-cooke
Copy link

@ibhagwan thanks so much for your helpful replies! I am quite new to Lua/Neovim plugins so I wasn't quite sure how to call the underlying fzf from neovim.

I had a look at @hexh250786313 's dotfiles and I think I'm on the right track.

I will post my solution in here when I'm done!

@dan-cooke
Copy link

dan-cooke commented Mar 11, 2024

@ibhagwan so this works great, thanks for your help

vim.keymap.set('n', '<C-p>', function()
	fzf.oldfiles({
		prompt = 'Recently Used > ',
		cwd_only = true,
		keymap = {

			fzf = {
				-- fzf '--bind=' options
				["change"] = "reload(fd)+unbind(change)+change-prompt(Files> )+enable-search",
			},
		}


	})
end)

Just one final question - maybe unrelated.

But when I switch from oldfiles to fd - the old files is not updated with the entry I select, is there something I can do about that?

Edit: I just need to set include_current_session = true, -- include bufs from current session

@ibhagwan
Copy link
Owner

But when I switch from oldfiles to fd - the old files is not updated with the entry I select, is there something I can do about that?

That’s because the shada file isn’t written to disk when you open a file, it is online added to the shada when you exit neovim.

include_current_session = true

This is a good solution, another way would be to an autocmd that updates the shada file on BufReadPost.

@mangelozzi
Copy link

This is great info, thanks @ibhagwan !

For any future people like me when you start a new sessions and you try find a buffer, but you havent opened it yet, you can switch to the file picker with CTRL+k like this (also includes switching back to buffers again with <Ctrl+k>):

        actions = {
            buffers = { -- When on :buffers, pressing <Ctrl-k> will resume with files
                ["ctrl-k"]  = {
                    function()
                        local opts = {
                            query = fzf.config.__resume_data.last_query,
                            cwd = fzf.config.__resume_data.opts.cwd,
                        }
                        fzf.files(opts)
                    end
                },
            },
            files = { -- When on :files, pressing <Ctrl-k> will resume with buffers
                ["ctrl-k"]  = {
                    function()
                        local opts = {
                            query = fzf.config.__resume_data.last_query,
                            cwd = fzf.config.__resume_data.opts.cwd,
                        }
                        fzf.buffers(opts)
                    end
                },
            },
        },

@ibhagwan
Copy link
Owner

ibhagwan commented Jul 8, 2024

Ty @mangelozzi, btw, I’ve made the last query more accessible from actions:

["ctrl-k"]  = function(sel, opts)
  print('q:', opts.last_query)
end

@mangelozzi
Copy link

mangelozzi commented Jul 8, 2024

Ty @mangelozzi, btw, I’ve made the last query more accessible from actions:

Thanks! I made it more compact with your suggestion:

        actions = {
            buffers = { -- When on :buffers, pressing <Ctrl-Space> will resume with files
                ["Ctrl-Space"] = function(_, opts) fzf.files({ query=opts.last_query, cwd=opts.cwd }) end, -- _ = sel
            },
            files = { -- When on :files, pressing <Ctrl-Space> will resume with buffers
                ["Ctrl-Space"] = function(_, opts) fzf.buffers({ query=opts.last_query, cwd=opts.cwd }) end, -- _ = sel
            }
        },

@ibhagwan
Copy link
Owner

ibhagwan commented Jul 8, 2024

Looks great @mangelozzi!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants