ibhagwan / fzf-lua

Improved fzf.vim written in lua
GNU Affero General Public License v3.0
2.1k stars 138 forks source link

Feature: Can fzf-lua be configured so that pressing ESC sends it to the background instead of closing it? #1229

Closed Marskey closed 3 weeks ago

Marskey commented 2 months ago

Have you RTFM'd?

Feature Request

This way, I can resume my last search status exactly where I left off. The current resume feature only redoes the search with the same query, which causes the previous search state to be lost.

ibhagwan commented 2 months ago

ATM, this is not possible, it’s an interesting idea might be worth exploring.

abkrm commented 2 months ago

+1 on this feature request. I use this feature a lot and would be nice to have it supported in fzf-lua.

folke commented 2 months ago

If you're on Neovim >= 0.10, then you can use the keymap below to toggle any floating window.

local function toggle_floats()
  local floats = {}
  local any_hidden = false
  for _, win in ipairs(vim.api.nvim_list_wins()) do
    local config = vim.api.nvim_win_get_config(win)
    if config.relative ~= "" then
      floats[win] = config
      if config.hide then
        any_hidden = true
      end
    end
  end
  for win, config in pairs(floats) do
    config.hide = not any_hidden
    vim.api.nvim_win_set_config(win, config)
  end
end

vim.keymap.set({ "n", "t" }, "<c-;>", toggle_floats)

Edit: this doesn't really work as intended though, since focus would still be on the hidden fzf window :)

lttb commented 2 months ago

I've been using a similar to folke's solution with nvim >= 0.10 for some time, and in general it works fine (see the video example) - it switches the focus to the buffer, and restores the cursor position in the next fzf search

my workflow:

references to the actual config:

demo:

https://github.com/ibhagwan/fzf-lua/assets/11135392/32f974b0-9aac-4744-9824-2fb5c1e84efc

fzf-lua action example

  {
    'ibhagwan/fzf-lua',
    keys = function()
      local fzf = require('fzf-lua')
      local actions = require('fzf-lua.actions')

      return {
        utils.cmd_shift('f', {
          function()
            local tf = require('lttb.dev.toggle_floats')

            if tf.is_hidden('fzf') then
              tf.toggle_floats('fzf')

              return
            end

            fzf.grep_project({
              actions = {
                ['enter'] = {
                  function(selected, opts)
                    tf.toggle_floats('fzf', function()
                      actions.file_edit(selected, opts)
                    end)
                  end,
                  actions.resume,
                },
              },
            })
          end,
          desc = 'fzf: search',
        }),
      }
    end,
  },

toggle_floats.lua

local M = {}

local registry = {}

function M.is_hidden(name)
  local reg = registry[name]
  return reg and #reg.hidden_w > 0
end

function M.toggle_floats(name, callback)
  registry[name] = registry[name] or { hidden_w = {}, last_w = nil }
  local reg = registry[name]

  local wins = vim.api.nvim_list_wins()

  if #reg.hidden_w > 0 then
    for _, w in ipairs(reg.hidden_w) do
      vim.api.nvim_win_set_config(w, { hide = false })
    end

    if reg.last_w then
      vim.api.nvim_set_current_win(reg.last_w)

      vim.schedule(function()
        vim.api.nvim_feedkeys('i', 'n', false)
      end)
    end

    reg.hidden_w = {}
    reg.last_w = nil

    return
  end

  reg.last_w = vim.api.nvim_get_current_win()

  for id, w in ipairs(wins) do
    local win_config = vim.api.nvim_win_get_config(w)

    if
      win_config.relative == 'editor'
      -- ignore mini map (TODO: find a better detection way)
      and win_config.zindex ~= 10
    then
      vim.api.nvim_win_set_config(w, { hide = true })
      table.insert(reg.hidden_w, w)
    end
  end

  vim.opt.eventignore:append('WinLeave')
  vim.opt.eventignore:append('BufLeave')
  vim.api.nvim_set_current_win(1000)

  vim.schedule(function()
    if callback then
      callback()
    end

    vim.opt.eventignore:remove('WinLeave')
    vim.opt.eventignore:remove('BufLeave')
  end)
end

return M
ibhagwan commented 2 months ago

I also thought about the new float hide in neovim 0.10 but this provides a solution only for users with 0.10 and only using floats, there are also users using splits or fzf-tmux.

In general, I’m not too happy with the current state of the window class code since it had many iterations and is a bit messy, it started by only making a window for fzf with no preview buffer (at first, only native previewers were supported, like fzf.vim), then the “builtin” neovim buffer preview, splits, and fzf-tmux.

I’d hate to continue contributing to this mess without first splitting the window class to a base object and having a class for each FzfLuaFloat, FzfLuaSplit, etc, each having their own :hide() callback (which may or may not be supported, e.g. fzf- tmux), that will also open up the window creation for other frameworks like nui.nvim, etc.

That said, this change is a “luxury” change since everything is pretty much working so I need to get inspired to find the time for this :)

ibhagwan commented 2 months ago
ibhagwan commented 3 weeks ago

See #1371 for more info, default bind set to <A-Esc>.

ibhagwan commented 3 weeks ago

Forgot to mention how this addresses the issue of replacing the default <esc> with hide:

require("fzf-lua").setup({
  keymap = {
    builtin = {
      true, -- inherit all other default binds
      ["<Esc>"] = "hide",
    }
  }
})

Can also be set for a single call:

:FzfLua files keymap.builtin.<esc>=hide

Or for a specific picker (or picket "set", e.g. grep):

:lua require("fzf-lua").setup({ files = { keymap = { builtin = { ["<Esc>"] = "hide" } } } })
Marskey commented 3 weeks ago

The feature didn't work as I expected. It should be like what @lttb posted: hide the window and then resume, including the cursor position.

abkrm commented 3 weeks ago

@Marskey I haven't tried @lttb's solution, but I tested the latest version of Fzf-Lua and I think it works as expected (by me). Attaching a screen record for how it behaves for me: output1

ibhagwan commented 3 weeks ago

The feature didn't work as I expected. It should be like what @lttb posted: hide the window and then resume, including the cursor position.

Can you try with the default keybind alt-escape?

Perhaps your key mapping isn’t working or mapped to something else, one way to check if your window is actually hidden is to run :FzfLua unhide, with “unhide” it won’t fall back to resume, if unhide yields nothing your window wasn’t hidden.

Also can you press F1 and see if your mapping worked? My F1 (with the default) below: IMG_2372

Marskey commented 3 weeks ago

My bad, my config did not inherit the default keybind. nice work~ you are awosome!

ibhagwan commented 3 weeks ago

Ty @Marskey for the confirmation.

Note that it’s not meant to simply “restore the cursor” (not only at least), the new functionality sends the fzf process to the background so if you have a long running fd in a large project you can send it to background and come back to it when the enumeration finishes.

Marskey commented 3 weeks ago

@ibhagwan after I resumed, then I use fzf.buffers will occurd follwing error

Error executing vim.schedule lua callback: ...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:313: vim/shared.lua:0: t: expected table, got nil
stack traceback:
        [builtin#36]: at 0x010523481c
        ...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:313: in function 'fn'
        ...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:77: in function <...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:76>
ibhagwan commented 3 weeks ago

@ibhagwan after I resumed, then I use fzf.buffers will occurd follwing error

Error executing vim.schedule lua callback: ...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:313: vim/shared.lua:0: t: expected table, got nil
stack traceback:
        [builtin#36]: at 0x010523481c
        ...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:313: in function 'fn'
        ...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:77: in function <...key/.local/share/nvim/lazy/fzf-lua/lua/fzf-lua/shell.lua:76>

Can you help me reproduce this? Does this happen all the time with buffers (I assume not)? Is a certain sequence required to trigger this bug? Does this happen on selection / up/down / ctrl-x?

Marskey commented 3 weeks ago

@ibhagwan my config

local actions = require("fzf-lua").actions
require("fzf-lua").setup {
  "telescope",
  defaults = { formatter = "path.filename_first" },
  winopts = {
    height = 0.90,
    width = 0.77,
    preview = {
      wrap = "wrap",
      layout = "vertical", -- horizontal|vertical|flex
      vertical = "down:50%", -- right|left:size
      hidden = "hidden", -- hidden|nohidden
    },
  },
  fzf_opts = { ["--layout"] = "reverse", ["--marker"] = "+" },
  fzf_colors = {
    ["gutter"] = "-1",
  },
  hls = {
    cursorline = "CursorLine",
    cursorlinenr = "CursorLineNr",
  },
  grep = {
    rg_opts = "--column --line-number --no-heading --color=always -L --smart-case --max-columns=4096 -e",
  },
  keymap = {
    builtin = {
      ["<Esc>"] = "hide",
      ["<F1>"] = "toggle-help",
      ["<c-n>"] = "toggle-fullscreen",
      -- Only valid with the 'builtin' previewer
      ["<F3>"] = "toggle-preview-wrap",
      ["<c-p>"] = "toggle-preview",
      ["<F5>"] = "toggle-preview-ccw",
      ["<F6>"] = "toggle-preview-cw",
      ["<C-d>"] = "preview-page-down",
      ["<C-u>"] = "preview-page-up",
      ["<S-left>"] = "preview-page-reset",
    },
    fzf = {
      ["ctrl-z"] = "abort",
      ["ctrl-f"] = "forward-char",
      ["ctrl-b"] = "backward-char",
      ["ctrl-a"] = "beginning-of-line",
      ["ctrl-e"] = "end-of-line",
      ["alt-a"] = "toggle-all",
      -- Only valid with fzf previewers (bat/cat/git/etc)
      ["f3"] = "toggle-preview-wrap",
      ["f4"] = "toggle-preview",
      ["ctrl-d"] = "preview-page-down",
      ["ctrl-u"] = "preview-page-up",
    },
  },

  actions = {
    files = {
      ["default"] = actions.file_edit_or_qf,
      ["ctrl-s"] = actions.file_split,
      ["ctrl-v"] = actions.file_vsplit,
      ["ctrl-t"] = actions.file_tabedit,
    },
  },
}

I figure out that ["<Esc>"] = "hide", is the reason cause this error. after opening fzf.files, press esc to hide it, then use fzf.buffers. It happended 100%

ibhagwan commented 3 weeks ago

Does the interface open at all? What happens if you :FzfLua buffers previewer=false?

Marskey commented 3 weeks ago
image

after :FzfLua buffers previewer=false

ibhagwan commented 3 weeks ago

Ty @Marskey, I have a good idea now where this might come from.

Marskey commented 3 weeks ago

If I use <M-esc> It will work normally

ibhagwan commented 3 weeks ago

@Marskey, should work as expected after https://github.com/ibhagwan/fzf-lua/commit/19c52910dce1a95f01fc2dc3c7c7458ad425b887.