current commit
261101.1 · fix(git): fix fish preview quoting for special char paths
---@diagnostic disable: missing-fields
local path = require "fzf-lua.path"
local utils = require "fzf-lua.utils"
local actions = require "fzf-lua.actions"
local previewers = require "fzf-lua.previewer"
local M = {}

function M._default_previewer_fn()
  local winopts = M.globals.winopts
  if type(winopts) == "function" then
    winopts = winopts() or {}
    winopts.preview = type(winopts.preview) == "table" and winopts.preview or {}
    winopts.preview.default = winopts.preview.default
        or utils.map_get(M.defaults, "winopts.preview.default")
  end
  local previewer = M.globals.default_previewer or utils.map_get(winopts, "preview.default")
  -- the setup function cannot have a custom previewer as deepcopy
  -- fails with stack overflow while trying to copy the custom class
  -- the workaround is to define the previewer as a function instead
  -- https://github.com/ibhagwan/fzf-lua/issues/677
  return type(previewer) == "function" and previewer() or previewer
end

---@param opts? table
---@return string?
function M._preview_pager_fn(opts)
  -- fzf exports both variables to preview commands, but fish resets `$COLUMNS`
  -- (#1023); skim only exports `$COLUMNS` (#2846).
  local cols = opts and opts.__SK_VERSION and "$COLUMNS" or "$FZF_PREVIEW_COLUMNS"
  return vim.fn.executable("delta") == 1 and
      ("delta --width=%s --%s"):format(utils._if_win_normalize_vars(cols), vim.o.bg) or
      nil
end

function M._man_cmd_fn(bat_pager)
  local cmd = utils.is_darwin() and "man -P cat"
      or vim.fn.executable("mandb") == 1 and "man"
      or "man -c"
  local bat_cmd = bat_pager and (function()
    for _, bin in ipairs({ "batcat", "bat" }) do
      if vim.fn.executable(bin) == 1 then
        return string.format("%s --color=always -p -l man", bin)
      end
    end
  end)()
  local pager = bat_cmd or "col -bx"
  return string.format("%s %%s 2>/dev/null | %s", cmd, pager)
end

-- Cross platform extended perl regex grep flag
local GREP_PERL_REGEXP = utils.is_darwin() and "--extended-regexp" or "--perl-regexp"

-- fzf runs bind commands through `cmd.exe` on Windows where environment
-- variables use `%VAR%` instead of `$VAR`
local FZF_POS = utils._if_win_normalize_vars("$FZF_POS")

---@class fzf-lua.config.TreesitterWinopts
---@field enabled boolean Enable treesitter highlighting in fzf main window.
---@field fzf_colors? table<string, string> Treesitter fzf color overrides.

---@class fzf-lua.config.Winopts: vim.api.keyset.win_config
---Height of the fzf-lua float, between 0-1 will represent percentage of `vim.o.lines` (1: max height), if >= 1 will use fixed number of lines.
---@field height? number
---Width of the fzf-lua float, between 0-1 will represent percentage of `vim.o.columns` (1: max width), if >= 1 will use fixed number of columns.
---@field width? number
---Screen row where to place the fzf-lua float window, between 0-1 will represent percentage of `vim.o.lines` (0: top, 1: bottom), if >= 1 will attempt to place the float in the exact screen line.
---@field row? number
---Screen column where to place the fzf-lua float window, between 0-1 will represent percentage of `vim.o.columns` (0: leftmost, 1: rightmost), if >= 1 will attempt to place the float in the exact screen column.
---@field col? number
---Border of the fzf-lua float, possible values are `none|single|double|rounded|thicc|thiccc|thicccc` or a custom border character array passed as is to `nvim_open_win`.
---@field border? string|table
---Controls title display in the fzf window, set by the calling picker.
---@field title? string
---Controls title display in the fzf window, possible values are `left|right|center`.
---@field title_pos? "center"|"left"|"right"
---Set to `false` to disable fzf window title flags (hidden, ignore, etc).
---@field title_flags? boolean
---Preview window configuration.
---@field preview? fzf-lua.config.PreviewOpts
---Neovim split command to use for fzf-lua interface, e.g `belowright new`.
---@field split? string|function|false
---Backdrop opacity value, 0 for fully opaque, 100 for fully transparent (i.e. disabled).
---@field backdrop? number|boolean
---Use fullscreen for the fzf-lua floating window.
---@field fullscreen? boolean
---Use treesitter highlighting in fzf's main window. NOTE: Only works for file-like entries where treesitter parser exists and is loaded for the filetype.
---@field treesitter? fzf-lua.config.TreesitterWinopts|boolean
---Use extmarks with conceal to visually shorten paths while keeping full paths for actions/preview. Set to `true` for 1 char, or a number for custom length. NOTE: Unlike the picker `path_shorten` option, this doesn't modify the actual entry text, making it compatible with `combine()`. NOTE: This option has no effect when using `fzf-tmux` as the fzf window runs in a tmux popup outside of Neovim where extmarks are not available.
---@field path_shorten? boolean|integer
---Callback after the creation of the fzf-lua main terminal window.
---@field on_create? fun(e: { winid?: integer, bufnr?: integer })
---Callback after closing the fzf-lua window.
---@field on_close? fun()
---Toggle behavior for fzf-lua window.
---@field toggle_behavior? string
---Enable window transparency.
---@field winblend? boolean
---Enable window highlight groups.
---@field winhl? boolean
---Highlight the current line in main window.
---@field cursorline? boolean
---Internal window highlight mappings.
---@field __winhls? { main: [string, string?][], prev: [string, string?][] }

---@class fzf-lua.config.PreviewOpts
---Default previewer for file pickers, possible values `builtin|bat|cat|head`.
---@field default? string
---Preview border for native fzf previewers (i.e. `bat`, `git_status`), set to `noborder` to hide the preview border, consult `man fzf` for all available options.
---@field border? any
---Line wrap in both native fzf and the builtin previewer, mapped to fzf's `--preview-window:[no]wrap` flag.
---@field wrap? boolean
---Preview startup visibility in both native fzf and the builtin previewer, mapped to fzf's `--preview-window:[no]hidden` flag. NOTE: this is different than setting `previewer=false` which disables the previewer altogether with no toggle ability.
---@field hidden? boolean
---Vertical preview layout, mapped to fzf's `--preview-window:...` flag. Requires `winopts.preview.layout={vertical|flex}`.
---@field vertical? string
---Horizontal preview layout, mapped to fzf's `--preview-window:...` flag. Requires `winopts.preview.layout={horizontal|flex}`.
---@field horizontal? string
---Preview layout, possible values are `horizontal|vertical|flex`, when set to `flex` fzf window width is tested against `winopts.preview.flip_columns`, when <= `vertical` is used, otherwise `horizontal`.
---@field layout? string
---Auto-detect the preview layout based on available width, see note in `winopts.preview.layout`.
---@field flip_columns? integer
---Controls title display in the builtin previewer.
---@field title? boolean
---Controls title display in the builtin previewer, possible values are `left|right|center`.
---@field title_pos? "center"|"left"|"right"
---Scrollbar style in the builtin previewer, set to `false` to disable, possible values are `float|border`.
---@field scrollbar? string|boolean
---Float style scrollbar offset from the right edge of the preview window. Requires `winopts.preview.scrollbar=float`.
---@field scrolloff? integer
---Debounce time (milliseconds) for displaying the preview buffer in the builtin previewer.
---@field delay? integer
---@field winopts? fzf-lua.config.PreviewerWinopts Window options for the builtin previewer.
---(skim only option), allow preview process run in pty
---@field pty? boolean

---missing fields are injected later, not sure how to tell luals about it
---@class fzf-lua.config.Defaults: fzf-lua.config.Base,{}
---@field nbsp string Special invisible unicode character used as text delimiter.
---@field winopts fzf-lua.config.Winopts Window options.
---@field keymap fzf-lua.config.Keymap Keymaps for builtin and fzf commands.
---@field actions table<string, fzf-lua.config.Actions> Actions to execute on selected items.
---@field fzf_bin string? Path to fzf binary.
---@field previewers fzf-lua.config.Previewers Previewer configurations.
---@field formatters table<string, any>
---@field file_icon_padding string Padding after file icons.
---@field dir_icon string Directory icon to display in front of directory entries.
---@field __HLS fzf-lua.config.HLS Highlight group configuration.
---@field [string] any
M.defaults = {
  nbsp          = utils.nbsp,
  winopts       = {
    height     = 0.85,
    width      = 0.80,
    row        = 0.35,
    col        = 0.55,
    border     = "rounded",
    zindex     = 50,
    backdrop   = 60,
    fullscreen = false,
    title_pos  = "center",
    treesitter = {
      enabled    = utils.__HAS_NVIM_010,
      fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }
    },
    preview    = {
      default      = "builtin",
      border       = "rounded",
      wrap         = false,
      hidden       = false,
      vertical     = "down:45%",
      horizontal   = "right:60%",
      layout       = "flex",
      flip_columns = 100,
      title        = true,
      title_pos    = "center",
      scrollbar    = "border",
      scrolloff    = -1,
      -- default preview delay, fzf native previewers has a 100ms delay:
      -- https://github.com/junegunn/fzf/issues/2417#issuecomment-809886535
      delay        = 20,
      ---@class fzf-lua.config.PreviewerWinopts
      ---Builtin previewer buffer local option, see `:help 'number'`.
      ---@field number boolean
      ---Builtin previewer buffer local option, see `:help 'relativenumber'`.
      ---@field relativenumber boolean
      ---Builtin previewer buffer local option, see `:help 'cursorline'`.
      ---@field cursorline boolean
      ---Builtin previewer buffer local option, see `:help 'cursorlineopt'`.
      ---@field cursorlineopt string
      ---Builtin previewer buffer local option, see `:help 'cursorcolumn'`.
      ---@field cursorcolumn boolean
      ---Builtin previewer buffer local option, see `:help 'signcolumn'`.
      ---@field signcolumn string
      ---Builtin previewer buffer local option, see `:help 'list'`.
      ---@field list boolean
      ---Builtin previewer buffer local option, see `:help 'foldenable'`.
      ---@field foldenable boolean
      ---Builtin previewer buffer local option, see `:help 'foldmethod'`.
      ---@field foldmethod string
      ---Builtin previewer buffer local option, see `:help 'scrolloff'`.
      ---@field scrolloff integer
      ---Builtin previewer window transparency, see `:help 'winblend'`.
      ---@field winblend integer
      winopts      = {
        number         = true,
        relativenumber = false,
        cursorline     = true,
        cursorlineopt  = "both",
        cursorcolumn   = false,
        signcolumn     = "no",
        list           = false,
        foldenable     = false,
        foldmethod     = "manual",
        scrolloff      = 0,
      },
    },
    -- on_create  = function(_)
    --   vim.cmd("set winhl=Normal:Normal,FloatBorder:Normal")
    --   utils.keymap_set("t", "<A-Esc>", actions.hide, { nowait = true, buffer = e.bufnr })
    -- end,
  },
  ---@class fzf-lua.config.Keymap
  ---@field builtin? table<string, string> Keybinds for builtin (Neovim) commands.
  ---@field fzf? table<string, string> Keybinds for fzf commands.
  keymap        = {
    builtin = {
      ["<M-Esc>"]    = "hide",
      ["<F1>"]       = "toggle-help",
      ["<F2>"]       = "toggle-fullscreen",
      -- Only valid with the 'builtin' previewer
      ["<F3>"]       = "toggle-preview-wrap",
      ["<F4>"]       = "toggle-preview",
      ["<F5>"]       = "toggle-preview-cw",
      ["<F6>"]       = "toggle-preview-behavior",
      ["<F7>"]       = "toggle-preview-ts-ctx",
      ["<F8>"]       = "preview-ts-ctx-dec",
      ["<F9>"]       = "preview-ts-ctx-inc",
      ["<S-Left>"]   = "preview-reset",
      ["<S-down>"]   = "preview-page-down",
      ["<S-up>"]     = "preview-page-up",
      ["<M-S-down>"] = "preview-down",
      ["<M-S-up>"]   = "preview-up",
    },
    fzf = {
      ["ctrl-z"]         = "abort",
      ["ctrl-u"]         = "unix-line-discard",
      ["ctrl-f"]         = "half-page-down",
      ["ctrl-b"]         = "half-page-up",
      ["ctrl-a"]         = "beginning-of-line",
      ["ctrl-e"]         = "end-of-line",
      ["alt-a"]          = "toggle-all",
      ["alt-g"]          = "first",
      ["alt-G"]          = "last",
      -- Only valid with fzf previewers (bat/cat/git/etc)
      ["f3"]             = "toggle-preview-wrap",
      ["f4"]             = "toggle-preview",
      ["shift-down"]     = "preview-page-down",
      ["shift-up"]       = "preview-page-up",
      ["alt-shift-down"] = "preview-down",
      ["alt-shift-up"]   = "preview-up",
    },
  },
  actions       = {
    files = {
      ["enter"]  = 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-Q"]  = actions.file_sel_to_ll,
      ["alt-i"]  = { fn = actions.toggle_ignore, reuse = true, header = false },
      ["alt-h"]  = { fn = actions.toggle_hidden, reuse = true, header = false },
      ["alt-f"]  = { fn = actions.toggle_follow, reuse = true, header = false },
    },
  },
  fzf_bin       = nil, ---@type string? Path to fzf binary.
  ---Fzf command-line options passed to fzf binary.
  fzf_opts      = {
    ["--ansi"]           = true,
    ["--info"]           = "inline-right",
    ["--height"]         = "100%",
    ["--layout"]         = "reverse",
    ["--border"]         = "none",
    ["--highlight-line"] = true,
    -- typo-resistant algo with skim >= v1.5.3
    -- ["--algo"]        = "frizbee",
  },
  ---Options passed to fzf-tmux wrapper.
  fzf_tmux_opts = { ["-p"] = "80%,80%", ["--margin"] = "0,0" },
  ---@class fzf-lua.config.Previewers
  ---@field builtin fzf-lua.config.BuiltinPreviewer
  ---@field git_diff fzf-lua.config.GitDiffPreviewer
  ---@field [string] fzf-lua.config.Previewer
  previewers    = {
    cat = {
      cmd   = "cat",
      args  = "-n",
      _ctor = previewers.fzf.cmd,
    },
    bat = {
      -- reduce startup time by deferring executable check to previewer constructor (#970)
      cmd   = function() return vim.fn.executable("batcat") == 1 and "batcat" or "bat" end,
      -- args  = "--color=always --style=default",
      args  = "--color=always --style=numbers,changes",
      _ctor = previewers.fzf.bat_async,
    },
    bat_native = {
      cmd   = function() return vim.fn.executable("batcat") == 1 and "batcat" or "bat" end,
      args  = "--color=always --style=numbers,changes",
      -- NOTE: no support for `bat_native` on Windows, it's a hassle for no real
      -- benefit, native previewers will be removed from the code at one point
      _ctor = utils._if_win(previewers.fzf.bat_async, previewers.fzf.bat),
    },
    head = {
      cmd   = "head",
      args  = nil,
      _ctor = previewers.fzf.head,
    },
    ---@class fzf-lua.config.GitDiffPreviewer: fzf-lua.config.Previewer
    git_diff = {
      pager         = M._preview_pager_fn,
      cmd_deleted   = "git diff --color HEAD --",
      cmd_modified  = "git diff --color HEAD",
      cmd_untracked = "git diff --color --no-index /dev/null",
      -- TODO: modify previewer code to accept table cmd
      -- cmd_deleted   = { "git", "diff", "--color", "HEAD", "--" },
      -- cmd_modified  = { "git", "diff", "--color", "HEAD" },
      -- cmd_untracked = { "git", "diff", "--color", "--no-index", "/dev/null" },
      _fn_git_icons = function() return M.globals.git.icons end,
      _ctor         = previewers.fzf.git_diff,
    },
    man = {
      _ctor = previewers.builtin.man_pages,
      cmd = function() return M._man_cmd_fn() end,
    },
    man_native = {
      _ctor = previewers.fzf.man_pages,
      cmd = function() return M._man_cmd_fn(true) end,
    },
    help_tags = { _ctor = previewers.builtin.help_tags },
    help_native = { _ctor = previewers.fzf.help_tags },
    swiper = { _ctor = previewers.swiper.default },
    ---@class fzf-lua.config.BuiltinPreviewer: fzf-lua.config.Previewer
    builtin = {
      syntax            = true,
      syntax_delay      = 0,
      syntax_limit_l    = 0,
      syntax_limit_b    = 1024 * 1024,      -- 1MB
      limit_b           = 1024 * 1024 * 10, -- 10MB
      treesitter        = {
        enabled = true,
        disabled = {},
        -- nvim-treesitter-context config options
        -- https://github.com/nvim-treesitter/nvim-treesitter-context
        context = { max_lines = 1, trim_scope = "inner" }
      },
      ueberzug_scaler   = "cover",
      title_fnamemodify = function(s) return path.tail(s) end,
      render_markdown   = { enabled = true, filetypes = { ["markdown"] = true } },
      snacks_image      = { enabled = true, render_inline = true },
      _ctor             = previewers.builtin.buffer_or_file,
    },
    ---@class fzf-lua.config.CodeActionPreviewer: fzf-lua.config.Previewer
    codeaction = {
      _ctor     = previewers.builtin.codeaction,
      diff_opts = { ctxlen = 3 },
    },
    codeaction_native = {
      _ctor     = previewers.fzf.codeaction,
      diff_opts = { ctxlen = 3 },
      pager     = M._preview_pager_fn,
    },
    ---@class fzf-lua.config.UndotreePreviewer: fzf-lua.config.Previewer
    undotree = {
      _ctor     = previewers.builtin.undotree,
      diff_opts = { ctxlen = 5 },
      show_buf  = false,
    },
    undotree_native = {
      _ctor     = previewers.fzf.undotree,
      diff_opts = { ctxlen = 5 },
      pager     = M._preview_pager_fn,
    },
    -- convenient aliaes
    undo = {
      _ctor     = previewers.builtin.undotree,
      diff_opts = { ctxlen = 5 },
    },
    undo_native = {
      _ctor     = previewers.fzf.undotree,
      diff_opts = { ctxlen = 5 },
      pager     = M._preview_pager_fn,
    },
  },
  formatters    = {
    path = {
      filename_first = {
        -- <Tab> is used as the invisible space between the parent and the file part
        enrich = function(o, v)
          o.fzf_opts = vim.tbl_extend("keep", o.fzf_opts or {}, { ["--tabstop"] = 1 })
          if tonumber(v) == 2 then
            -- https://github.com/ibhagwan/fzf-lua/pull/1255
            o.fzf_opts = vim.tbl_extend("keep", o.fzf_opts or {}, {
              ["--ellipsis"] = " ",
              ["--no-hscroll"] = true,
            })
          end
          return o
        end,
        -- underscore `_to` returns a custom to function when options could
        -- affect the transformation, here we create a different function
        -- base on the dir part highlight group.
        -- We use a string function with hardcoded values as non-scope vars
        -- (globals or file-locals) are stored by ref and will be nil in the
        -- `string.dump` (from `config.bytecode`), we use the 3rd function
        -- argument `m` to pass module imports (path, utils, etc).
        _to = function(o, v)
          local _, hl_dir = utils.ansi_from_hl(o.hls.dir_part, "foo")
          local _, hl_file = utils.ansi_from_hl(o.hls.file_part, "foo")
          local v2 = tonumber(v) ~= 2 and "" or [[, "\xc2\xa0" .. string.rep(" ", 200) .. s]]
          return ([[
            return function(s, _, m)
              local _path, _utils = m.path, m.utils
              local _hl_dir = "%s"
              local _hl_file = "%s"
              local tail = _path.tail(s)
              local parent = _path.parent(s)
              if #_hl_file > 0 then
                tail = _hl_file .. tail .. _utils.ansi_escseq.clear
              end
              if parent then
                parent = _path.remove_trailing(parent)
                if #_hl_dir > 0 then
                  parent = _hl_dir .. parent .. _utils.ansi_escseq.clear
                end
                return tail .. "\t" .. parent %s
              else
                return tail %s
              end
            end
          ]]):format(hl_dir or "", hl_file or "", v2, v2)
        end,
        from = function(s, _)
          s = s:gsub("\xc2\xa0     .*$", "") -- gsub v2 postfix
          local parts = utils.strsplit(s, utils.nbsp)
          local last = parts[#parts]
          ---@cast last -?
          -- Lines from grep, lsp, tags are formatted <file>:<line>:<col>:<text>
          -- the pattern below makes sure tab doesn't come from the line text
          local filename, rest = last:match("^([^:]-)\t(.+)$")
          if filename and rest then
            local parent
            if utils.__IS_WINDOWS and path.is_absolute(rest) then
              parent = rest:sub(1, 2) .. (#rest > 2 and rest:sub(3):match("^[^:]+") or "")
            else
              parent = rest:match("^[^:]+")
            end
            local fullpath = path.join({ parent, filename })
            -- overwrite last part with restored fullpath + rest of line
            parts[#parts] = fullpath .. rest:sub(#parent + 1)
            return table.concat(parts, utils.nbsp)
          else
            return s
          end
        end
      },
      dirname_first = {
        -- Credit fo @folke :-)
        -- https://github.com/ibhagwan/fzf-lua/pull/1255
        _to = function(o)
          local _, hl_dir = utils.ansi_from_hl(o.hls.dir_part, "foo")
          local _, hl_file = utils.ansi_from_hl(o.hls.file_part, "foo")
          return ([[
            return function(s, _, m)
              local _path, _utils = m.path, m.utils
              local _hl_dir = "%s"
              local _hl_file = "%s"
              local tail = _path.tail(s)
              local parent = _path.parent(s)
              if #_hl_file > 0 then
                tail = _hl_file .. tail .. _utils.ansi_escseq.clear
              end
              if parent then
                parent = _path.add_trailing(parent)
                if #_hl_dir > 0 then
                  parent = _hl_dir .. parent .. _utils.ansi_escseq.clear
                end
              end
              return (parent or "") .. tail
            end
          ]]):format(hl_dir or "", hl_file or "")
        end,
      },
    }
  },
}

---Find files using `fd`, `rg`, `find` or `dir.exe`.
---@class fzf-lua.config.Files: fzf-lua.config.Base
---Shell command used to generate the file list, default: auto detect `fd|rg|find|dir.exe`.
---@field cmd? string
---Exclude the current file from the list.
---@field ignore_current_file? boolean
---Lua patterns of files to ignore.
---@field file_ignore_patterns? string[]
---Parse the query for a line number suffix, e.g. `file.lua:10` will open `file.lua` at line 10.
---@field line_query? boolean|fun(query: string): lnum: string?, new_query: string?
---Raw shell command to use without any processing, bypasses all fzf-lua internals.
---@field raw_cmd? string
---Display the current working directory in the prompt (`fzf.vim` style).
---@field cwd_prompt? boolean
---Prompt over this length will be shortened using `pathshorten`.
---@field cwd_prompt_shorten_len? integer
---Length of shortened prompt path parts (`:help pathshorten`).
---@field cwd_prompt_shorten_val? integer
---Include hidden files (toggle with `<A-h>`).
---@field hidden? boolean
---Flag passed to the shell command to toggle ignoring `.gitignore` rules.
---@field toggle_ignore_flag? string
---Flag passed to the shell command to toggle showing hidden files.
---@field toggle_hidden_flag? string
---Flag passed to the shell command to toggle following symbolic links.
---@field toggle_follow_flag? string
M.defaults.files = {
  previewer              = M._default_previewer_fn,
  multiprocess           = 1, ---@type integer|boolean
  _type                  = "file",
  file_icons             = 1, ---@type integer|boolean
  color_icons            = true,
  git_icons              = false,
  cwd_prompt             = true,
  cwd_prompt_shorten_len = 32,
  cwd_prompt_shorten_val = 1,
  fzf_opts               = { ["--multi"] = true, ["--scheme"] = "path" },
  _fzf_nth_devicons      = true,
  git_status_cmd         = {
    "git", "-c", "color.status=false", "--no-optional-locks", "status", "--porcelain=v1" },
  find_opts              = [[-type f \! -path '*/.git/*' \! -path '*/.jj/*']],
  rg_opts                = [[--color=never --files -g "!.git" -g "!.jj"]],
  fd_opts                = [[--color=never --type f --type l --exclude .git --exclude .jj]],
  dir_opts               = [[/s/b/a:-d]],
  hidden                 = true,
  toggle_ignore_flag     = "--no-ignore",
  toggle_hidden_flag     = "--hidden",
  toggle_follow_flag     = "-L",
  _actions               = function() return M.globals.actions.files end,
  _headers               = { "actions", "cwd" },
  winopts                = { preview = { winopts = { cursorline = false } } },
}

---Global multi-picker, combines files, buffers and symbols.
---@diagnostic disable-next-line: param-type-mismatch
---@class fzf-lua.config.Global : fzf-lua.config.Files
---@field pickers (fun():table)|table
---@field __alt_opts? boolean
M.defaults.global = vim.tbl_deep_extend("force", M.defaults.files, {
  silent            = true,
  -- TODO: lsp_workspace_symbols locate, not working yet
  -- as opts.__locate_pos is inside the symbols picker opts
  -- locate            = true,
  cwd_prompt        = true,
  line_query        = true,
  pickers           = function()
    local clients = utils.lsp_get_clients({ bufnr = utils.CTX().bufnr })
    ---@diagnostic disable-next-line: redundant-parameter, call-non-callable
    local doc_sym_supported = vim.iter(clients):any(function(client)
      return client:supports_method("textDocument/documentSymbol")
    end)
    ---@diagnostic disable-next-line: redundant-parameter, call-non-callable
    local wks_sym_supported = vim.iter(clients):any(function(client)
      return client:supports_method("workspace/symbol")
    end)
    return {
      { "files",   desc = "Files" },
      -- { "blines",  desc = "blines", prefix = "/" },
      { "buffers", desc = "Bufs", prefix = "$" },
      doc_sym_supported and {
        "lsp_document_symbols",
        desc = "Symbols (buf)",
        prefix = "@",
        opts = { no_autoclose = true, fzf_opts = { ["--with-nth"] = false } }
      } or {
        "btags",
        desc = "Tags (buf)",
        prefix = "@",
        opts = {
          previewer    = { _ctor = previewers.builtin.tags },
          fn_transform = [[return require("fzf-lua.make_entry").tag]],
        }
      },
      wks_sym_supported and
      {
        "lsp_workspace_symbols",
        desc = "Symbols (project)",
        prefix = "#",
        opts = { no_autoclose = true }
      } or {
        "tags",
        desc = "Tags (project)",
        prefix = "#",
        opts = {
          previewer    = { _ctor = previewers.builtin.tags },
          fn_transform = [[return require("fzf-lua.make_entry").tag]],
          rg_opts      = "--no-heading --color=always --smart-case",
          grep_opts    = "--color=auto " .. GREP_PERL_REGEXP,
        }
      },
    }
  end,
  fzf_opts          = { ["--delimiter"] = "[\t]", ["--with-nth"] = ".." },
  winopts           = { preview = { winopts = { cursorline = true } } },
  _ctx              = { includeBuflist = true }, -- we include a buffer picker
  _fzf_nth_devicons = false,
  _treesitter       = true,
})


---@class fzf-lua.config.GitBase: fzf-lua.config.Base
---Path to `.git` directory for bare repos or worktrees.
---@field git_dir? string
---Shell command used to generate the list.
---@field cmd string

---Git pickers parent table.
---@class fzf-lua.config.Git
---@field files     fzf-lua.config.GitFiles
---@field status    fzf-lua.config.GitStatus
---@field diff      fzf-lua.config.GitDiff
---@field hunks     fzf-lua.config.GitHunks
---@field reflog    fzf-lua.config.GitReflog
---@field commits   fzf-lua.config.GitCommits
---@field bcommits  fzf-lua.config.GitBcommits
---@field blame     fzf-lua.config.GitBlame
---@field branches  fzf-lua.config.GitBranches
---@field worktrees fzf-lua.config.GitWorktrees
---@field tags      fzf-lua.config.GitTags
---@field stash     fzf-lua.config.GitStash
---@field icons     fzf-lua.git.icons
-- Must construct our opts table in stages
-- so we can reference 'M.globals.files'
M.defaults.git = {
  ---Git tracked files.
  ---@class fzf-lua.config.GitFiles: fzf-lua.config.Base
  files = {
    previewer         = M._default_previewer_fn,
    cmd               = "git ls-files --exclude-standard",
    multiprocess      = 1, ---@type integer|boolean
    _type             = "file",
    file_icons        = 1, ---@type integer|boolean
    color_icons       = true,
    git_icons         = true,
    fzf_opts          = { ["--multi"] = true, ["--scheme"] = "path" },
    _fzf_nth_devicons = true,
    _actions          = function() return M.globals.actions.files end,
    _headers          = { "cwd" },
    winopts           = { preview = { winopts = { cursorline = false } } },
  },
  ---Git status (modified files).
  ---@class fzf-lua.config.GitStatus: fzf-lua.config.Base
  status = {
    -- override `color.status=always`, technically not required
    -- since we now also call `utils.strip_ansi_coloring` (#706)
    cmd               = "git -c color.status=false --no-optional-locks status --porcelain=v1 -u",
    previewer         = "git_diff",
    multiprocess      = true, ---@type integer|boolean
    fn_transform      = [[return require("fzf-lua.make_entry").git_status]],
    fn_preprocess     = [[return require("fzf-lua.make_entry").preprocess]],
    file_icons        = 1, ---@type integer|boolean
    color_icons       = true,
    fzf_opts          = { ["--multi"] = true },
    _fzf_nth_devicons = true,
    _actions          = function() return M.globals.actions.files end,
    _headers          = { "actions", "cwd" },
    actions           = {
      ["right"]  = { fn = actions.git_unstage, reload = true },
      ["left"]   = { fn = actions.git_stage, reload = true },
      ["ctrl-x"] = { fn = actions.git_reset, reload = true },
      -- Uncomment to test stage|unstage and backward compat
      -- ["ctrl-s"] = { fn = actions.git_stage_unstage, reload = true },
      -- ["ctrl-s"] = { actions.git_stage_unstage, actions.resume },
    },
  },
  ---Git diff (changed files vs a git ref).
  ---@class fzf-lua.config.GitDiff: fzf-lua.config.GitBase
  ---Git reference(s) to compare against.
  ---@field ref? string|string[]
  ---Git reference used as the base for the comparison.
  ---@field ref1? string
  diff = {
    cmd               = "git --no-pager diff --color=always --name-only {ref1} {ref}",
    ref               = nil,
    ref1              = nil,
    preview           = "git diff --color=always {ref1} {ref} {file}",
    preview_pager     = M._preview_pager_fn,
    multiprocess      = 1, ---@type integer|boolean
    _type             = "file",
    file_icons        = 1, ---@type integer|boolean
    color_icons       = true,
    fzf_opts          = { ["--multi"] = true },
    _fzf_nth_devicons = true,
    _actions          = function() return M.globals.actions.files end,
    _headers          = { "cwd", "actions" },
    actions           = {
      ["ctrl-d"] = {
        fn = function(s, _o)
          if not s[1] then return FzfLua.utils.fzf_exit() end
          local o = vim.deepcopy(_o.__call_opts)
          o["__pos_" .. FzfLua.get_info().cmd] = tonumber(s[2])
          o.file = FzfLua.path.entry_to_file(s[1], _o).path
          FzfLua.git_hunks(o)
        end,
        header = "git hunks",
        reuse = #vim.api.nvim_list_uis() == 0,
        exec_silent = #vim.api.nvim_list_uis() > 0,
        field_index = "{} " .. FZF_POS,
      },
      ["ctrl-q"] = {
        fn = function(s, _o)
          local o = vim.deepcopy(_o.__call_opts)
          o["__pos_" .. FzfLua.get_info().cmd] = tonumber(s[2])
          FzfLua.git_commits(o)
        end,
        reuse = true,
        header = "git commits",
        field_index = "{} " .. FZF_POS,
      },
    },
  },
  ---Git diff hunks (changed lines).
  ---@class fzf-lua.config.GitHunks: fzf-lua.config.GitBase
  ---Git file to diff
  ---@field file? string
  ---Git reference(s) to compare against.
  ---@field ref? string|string[]
  ---Git reference used as the base for the comparison.
  ---@field ref1? string
  hunks = {
    previewer         = M._default_previewer_fn,
    cmd               = "git --no-pager diff --color=always {ref1} {ref} {file}",
    ref               = nil,
    ref1              = nil,
    multiprocess      = true, ---@type integer|boolean
    fn_transform      = [[return require("fzf-lua.make_entry").git_hunk]],
    fn_preprocess     = [[return require("fzf-lua.make_entry").preprocess]],
    file_icons        = 1, ---@type integer|boolean
    color_icons       = true,
    fzf_opts          = {
      ["--multi"] = true,
      ["--delimiter"] = ":",
      ["--nth"] = "3..",
    },
    line_field_index  = "{2}",
    _fzf_nth_devicons = true,
    _actions          = function() return M.globals.actions.files end,
    _headers          = { "cwd", "actions" },
    actions           = {
      ["ctrl-q"] = {
        fn = function(_, _o) FzfLua.git_diff(vim.deepcopy(_o.__call_opts)) end,
        reuse = true,
        header = "git diff"
      },
    },
  },
  ---Git commits (project).
  ---@class fzf-lua.config.GitCommits: fzf-lua.config.GitBase
  commits = {
    cmd           = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]]
        .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset"]],
    preview       = "git show --color {1}",
    preview_pager = M._preview_pager_fn,
    actions       = {
      ["enter"]  = actions.git_checkout,
      ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true },
      ["ctrl-d"] = {
        fn = function(s, _o)
          if not s[1] then return FzfLua.utils.fzf_exit() end
          local o = vim.deepcopy(_o.__call_opts)
          o.ref = s[1]:match("[^ ]+")
          o.ref1 = o.ref .. "~"
          o["__pos_" .. FzfLua.get_info().cmd] = tonumber(s[2])
          FzfLua.git_diff(o)
        end,
        header = "git diff",
        reuse = #vim.api.nvim_list_uis() == 0,
        exec_silent = #vim.api.nvim_list_uis() > 0,
        field_index = "{} " .. FZF_POS,
      },
    },
    fzf_opts      = { ["--no-multi"] = true },
    _headers      = { "actions", "cwd" },
    _multiline    = false,
  },
  ---Git commits (buffer).
  ---@class fzf-lua.config.GitBcommits: fzf-lua.config.GitBase
  ---Follow the buffer's history across renames.
  ---@field follow? boolean
  bcommits = {
    cmd           = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]]
        .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset" -- {file}]],
    -- When true, follow the buffer's history across renames.
    follow        = false,
    preview       = "git show --color {1} -- {file}",
    preview_pager = M._preview_pager_fn,
    actions       = {
      ["enter"]  = actions.git_buf_edit,
      ["ctrl-s"] = actions.git_buf_split,
      ["ctrl-v"] = actions.git_buf_vsplit,
      ["ctrl-t"] = actions.git_buf_tabedit,
      ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true },
    },
    fzf_opts      = { ["--no-multi"] = true },
    _headers      = { "actions", "cwd" },
    _multiline    = false,
  },
  ---Git blame (buffer).
  ---@class fzf-lua.config.GitBlame: fzf-lua.config.GitBase
  blame = {
    cmd           = [[git blame --color-lines {file}]],
    preview       = "git show --color {1} -- {file}",
    preview_pager = M._preview_pager_fn,
    actions       = {
      ["enter"]  = actions.git_goto_line,
      ["ctrl-s"] = actions.git_buf_split,
      ["ctrl-v"] = actions.git_buf_vsplit,
      ["ctrl-t"] = actions.git_buf_tabedit,
      ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true },
    },
    fzf_opts      = { ["--no-multi"] = true },
    _multiline    = false,
    -- `winopts.treesitter==true` line match format
    _treesitter   = function(line) return line:match("(%s+)(%d+)%)(.+)$") end,
  },
  ---Git branches.
  ---@class fzf-lua.config.GitBranches: fzf-lua.config.GitBase
  ---Filter branches, possible values are `local|remote|all`.
  ---@field remotes? string
  ---Shell command used to add a branch.
  ---@field cmd_add? string[]
  ---Shell command used to delete a branch.
  ---@field cmd_del? string[]
  branches = {
    cmd        = [[git branch --all --color -vv ]]
        .. [[--sort=-committerdate --sort=refname:rstrip=-2 --sort=-HEAD]],
    preview    = "git log --graph --pretty=oneline --abbrev-commit --color {1}",
    remotes    = "local",
    actions    = {
      ["enter"]  = actions.git_switch,
      ["ctrl-x"] = { fn = actions.git_branch_del, reload = true },
      ["ctrl-a"] = { fn = actions.git_branch_add, field_index = "{q}", reload = true },
    },
    cmd_add    = { "git", "branch" },
    cmd_del    = { "git", "branch", "--delete" },
    fzf_opts   = { ["--no-multi"] = true, ["--tiebreak"] = "begin" },
    _headers   = { "actions", "cwd" },
    _multiline = false,
  },
  ---Git worktrees.
  ---@class fzf-lua.config.GitWorktrees: fzf-lua.config.GitBase
  ---Scope of the `cd` action, possible values are `local|win|tab|global`.
  ---@field scope? string
  worktrees = {
    scope      = "global", -- cd action scope "local|win|tab"
    cmd        = "git worktree list",
    preview    = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]]
        .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset"]],
    actions    = {
      ["enter"]  = actions.git_worktree_cd,
      ["ctrl-x"] = { fn = actions.git_worktree_del, reload = true },
      ["ctrl-a"] = { fn = actions.git_worktree_add, field_index = "{q}", reload = true },
    },
    fzf_opts   = { ["--no-multi"] = true },
    _headers   = { "actions", "cwd" },
    _multiline = false,
  },
  ---Git tags.
  ---@class fzf-lua.config.GitTags: fzf-lua.config.GitBase
  tags = {
    cmd        = [[git for-each-ref --color --sort="-taggerdate" --format ]]
        .. [["%(color:yellow)%(refname:short)%(color:reset) ]]
        .. [[%(color:green)(%(taggerdate:relative))%(color:reset)]]
        .. [[ %(subject) %(color:blue)%(taggername)%(color:reset)" refs/tags]],
    preview    = [[git log --graph --color --pretty=format:"%C(yellow)%h%Creset ]]
        .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset" {1}]],
    actions    = { ["enter"] = actions.git_checkout },
    fzf_opts   = { ["--no-multi"] = true },
    _headers   = { "cwd" },
    _multiline = false,
  },
  ---Git stashes.
  ---@class fzf-lua.config.GitStash: fzf-lua.config.GitBase
  ---@field search? string
  stash = {
    cmd           = "git --no-pager stash list",
    preview       = "git --no-pager stash show --patch --color {1}",
    preview_pager = M._preview_pager_fn,
    actions       = {
      ["enter"]  = actions.git_stash_apply,
      ["ctrl-x"] = { fn = actions.git_stash_drop, reload = true },
    },
    fzf_opts      = {
      -- TODO: multiselect requires more work as dropping
      -- a stash changes the stash index, causing an error
      -- when the next stash is attempted
      ["--no-multi"]  = true,
      ["--delimiter"] = "[:]",
    },
    _headers      = { "actions", "cwd", "search" },
  },
  ---@class fzf-lua.git.icons
  icons = {
    ["M"] = { icon = "M", color = "yellow" },
    ["D"] = { icon = "D", color = "red" },
    ["A"] = { icon = "A", color = "green" },
    ["R"] = { icon = "R", color = "yellow" },
    ["C"] = { icon = "C", color = "yellow" },
    ["T"] = { icon = "T", color = "magenta" },
    ["?"] = { icon = "?", color = "magenta" },
  },
}

---Git reflog.
---@diagnostic disable-next-line: param-type-mismatch
---@class fzf-lua.config.GitReflog: fzf-lua.config.GitCommits
M.defaults.git.reflog = vim.tbl_deep_extend("force", M.defaults.git.commits, {
  cmd = [[git reflog --color=always --format="%C(yellow)%h %C(blue)%gD%C(auto)%d %gs"]],
})

---Jujutsu pickers parent table.
---@class fzf-lua.config.Jj
---@field files     fzf-lua.config.JjFiles
M.defaults.jj = {
  ---Jujutsu tracked files.
  ---@diagnostic disable-next-line: param-type-mismatch
  ---@class fzf-lua.config.JjFiles: fzf-lua.config.GitFiles
  files = vim.tbl_deep_extend("force", M.defaults.git.files, {
    cmd       = "jj file list --ignore-working-copy",
    git_icons = false,
  }),
}

---Grep using `rg`, `grep` or other grep commands.
---@class fzf-lua.config.Grep: fzf-lua.config.Base
---Shell command used to execute grep, default: auto detect `rg|grep`.
---@field cmd? string
---Use `rg` glob parsing, e.g. `foo -- -g*.md` will only match markdown files containing `foo`.
---@field rg_glob? boolean|integer
---Custom glob parsing function, returns the search query and the glob filter.
---@field rg_glob_fn? fun(query: string, opts: table): string, string
---Raw shell command to use without any processing, bypasses all fzf-lua internals.
---@field raw_cmd? string
---Initial search string.
---@field search? string
---Initial search pattern.
---@field regex? string
---Disable escaping of special characters in the search query, set to `2` to disable escaping and regex mode.
---@field no_esc? integer|boolean
---Enable live grep mode (search-as-you-type).
---@field lgrep? boolean
---List of paths to search (grep), e.g. `:FzfLua grep search_paths=/path/to/search`.
---@field search_paths? string[]
---Input prompt for the initial search query.
---@field input_prompt? string
---Ripgrep options passed to the `rg` command.
---@field rg_opts? string
---GNU grep options passed to the `grep` command.
---@field grep_opts? string
---Glob flag passed to the shell command, default `--iglob` (case insensitive), use `--glob` for case sensitive.
---@field glob_flag? string
---Query separator pattern (lua) for extracting glob patterns from the search query, default `%s%-%-` (` --`).
---@field glob_separator? string
---@field __resume_set? function
---@field __resume_get? function
M.defaults.grep = {
  previewer      = M._default_previewer_fn,
  input_prompt   = "Grep For> ",
  multiprocess   = 1, ---@type integer|boolean
  _type          = "file",
  file_icons     = 1, ---@type integer|boolean
  color_icons    = true,
  git_icons      = false,
  fzf_opts       = { ["--multi"] = true },
  grep_opts      = GREP_PERL_REGEXP
      .. " --binary-files=without-match --line-number --recursive --color=always -e",
  rg_opts        = "--column --line-number --no-heading --color=always --smart-case "
      .. "--max-columns=4096 -e",
  rg_glob        = 1, -- do not display warning if using `grep`
  _actions       = function() return M.globals.actions.files end,
  actions        = { ["ctrl-g"] = { actions.grep_lgrep } },
  -- live_grep_glob options
  glob_flag      = "--iglob", -- for case sensitive globs use '--glob'
  glob_separator = "%s%-%-",  -- query separator pattern (lua): ' --'
  _treesitter    = 1,         -- auto disable in live grep
  _headers       = { "actions", "cwd" },
}

---Grep current buffer only.
---@diagnostic disable-next-line: param-type-mismatch
---@class fzf-lua.config.GrepCurbuf: fzf-lua.config.Grep,{}
---@field filename? string
M.defaults.grep_curbuf = vim.tbl_deep_extend("force", M.defaults.grep, {
  rg_glob          = false, -- meaningless for single file rg
  exec_empty_query = true,  -- makes sense to display lines immediately
  fzf_opts         = {
    ["--delimiter"] = "[:]",
    ["--with-nth"]  = "2..",
    ["--nth"]       = "2..",
  },
})

---Neovim's argument list (`:args`).
---@class fzf-lua.config.Args: fzf-lua.config.Base
---Exclude non-file entries (directories) from the list.
---@field files_only? boolean
M.defaults.args = {
  previewer         = M._default_previewer_fn,
  files_only        = true, -- Exclude non-file entries (directories).
  file_icons        = 1, ---@type integer|boolean
  color_icons       = true,
  git_icons         = false,
  fzf_opts          = { ["--multi"] = true, ["--scheme"] = "path" },
  _fzf_nth_devicons = true,
  _actions          = function() return M.globals.actions.files end,
  actions           = { ["ctrl-x"] = { fn = actions.arg_del, reload = true } },
  _headers          = { "actions", "cwd" },
}

---File history (output of `:oldfiles`).
---@class fzf-lua.config.Oldfiles: fzf-lua.config.Base
---Optional shada file to read, see `:help shada`
---@field shada_file? string
---Only include files that still exist on disk.
---@field stat_file? boolean
---Timeout in ms for the per-file stat checks, files whose stat does not
---complete within the timeout are skipped, protects against hangs caused
---by `fs_stat` on stale network mounts, broken links, etc. Set to `0` to
---disable and use blocking stat calls. Requires `stat_file`.
---@field stat_timeout? integer
---Include files opened during the current session.
---@field include_current_session? boolean
---Exclude the current buffer from the list.
---@field ignore_current_buffer? boolean
M.defaults.oldfiles = {
  previewer               = M._default_previewer_fn,
  file_icons              = 1, ---@type integer|boolean
  color_icons             = true,
  git_icons               = false,
  stat_file               = true,
  stat_timeout            = 100,
  include_current_session = false,
  ignore_current_buffer   = true,
  fzf_opts                = { ["--tiebreak"] = "index", ["--multi"] = true },
  _fzf_nth_devicons       = true,
  _actions                = function() return M.globals.actions.files end,
  _headers                = { "cwd" },
  _resume_reload          = true,
}

---File history including current session.
---@class fzf-lua.config.History: fzf-lua.config.Oldfiles
M.defaults.history = vim.tbl_deep_extend("force", {}, M.defaults.oldfiles, {
  include_current_session = true,
  ignore_current_buffer   = false,
})

---Quickfix list entries.
---@class fzf-lua.config.Quickfix: fzf-lua.config.Base
---Separator between filename and text.
---@field separator string
---Only include entries with valid file/line information.
---@field valid_only boolean
M.defaults.quickfix = {
  previewer        = M._default_previewer_fn,
  separator        = "▏",
  file_icons       = 1, ---@type integer|boolean
  color_icons      = true,
  git_icons        = false,
  valid_only       = false,
  fzf_opts         = {
    ["--multi"]     = true,
    ["--delimiter"] = "[\\]:]",
    ["--with-nth"]  = "2..",
  },
  line_field_index = "{3}",
  actions          = { ["ctrl-x"] = { fn = actions.list_del, reload = true } },
  _actions         = function() return M.globals.actions.files end,
  _treesitter      = true,
  _cached_hls      = { "path_colnr", "path_linenr" },
  _headers         = { "actions", "cwd" },
}

---Quickfix list history.
---@class fzf-lua.config.QuickfixStack: fzf-lua.config.Base
---@field marker string
M.defaults.quickfix_stack = {
  marker    = ">",
  previewer = { _ctor = previewers.builtin.quickfix, },
  fzf_opts  = { ["--no-multi"] = true },
  actions   = { ["enter"] = actions.set_qflist, },
}

---Location list entries.
---@class fzf-lua.config.Loclist : fzf-lua.config.Quickfix: fzf-lua.config.Base
---@field is_loclist true
M.defaults.loclist = {
  previewer        = M._default_previewer_fn,
  separator        = "▏",
  file_icons       = 1, ---@type integer|boolean
  color_icons      = true,
  git_icons        = false,
  valid_only       = false,
  fzf_opts         = {
    ["--multi"]     = true,
    ["--delimiter"] = "[\\]:]",
    ["--with-nth"]  = "2..",
  },
  line_field_index = "{3}",
  actions          = { ["ctrl-x"] = { fn = actions.list_del, reload = true } },
  _actions         = function() return M.globals.actions.files end,
  _treesitter      = true,
  _cached_hls      = { "path_colnr", "path_linenr" },
  _headers         = { "actions", "cwd" },
}

---Location list history.
---@class fzf-lua.config.LoclistStack : fzf-lua.config.QuickfixStack: fzf-lua.config.Base
---@field is_loclist true
M.defaults.loclist_stack = {
  marker    = ">",
  previewer = { _ctor = previewers.builtin.quickfix, },
  fzf_opts  = { ["--no-multi"] = true },
  actions   = { ["enter"] = actions.set_qflist, },
}

---Open buffers.
---@class fzf-lua.config.Buffers: fzf-lua.config.BufferLines
---Only display the filename without the path.
---@field filename_only? boolean
---Override the current working directory for relative paths.
---@field cwd? string
---Sort buffers by last used.
---@field sort_lastused? boolean
---Include unloaded (not yet displayed) buffers.
---@field show_unloaded? boolean
---Include unlisted buffers (`:help unlisted-buffer`).
---@field show_unlisted? boolean
---Exclude the current buffer from the list.
---@field ignore_current_buffer? boolean
---Limit results to buffers from the current working directory only.
---@field cwd_only? boolean
---Do not set cursor position when switching buffers.
---@field no_action_set_cursor? boolean
M.defaults.buffers = {
  _type                 = "file",
  previewer             = M._default_previewer_fn,
  file_icons            = 1, ---@type integer|boolean
  color_icons           = true,
  sort_lastused         = true,
  show_unloaded         = true,
  show_unlisted         = false,
  ignore_current_buffer = false,
  no_action_set_cursor  = true,
  cwd_only              = false,
  cwd                   = nil,
  fzf_opts              = { ["--tiebreak"] = "index", ["--multi"] = true },
  _actions              = function()
    return M.globals.actions.buffers or M.globals.actions.files
  end,
  actions               = { ["ctrl-x"] = { fn = actions.buf_del, reload = true } },
  _cached_hls           = { "buf_nr", "buf_flag_cur", "buf_flag_alt", "path_linenr" },
  _headers              = { "actions", "cwd" },
  _ctx                  = { includeBuflist = true },
  _resume_reload        = true,
}

---Open buffers by tabs.
---@class fzf-lua.config.Tabs: fzf-lua.config.BufferLines
---Only display the filename without the path.
---@field filename_only? boolean
---@field __locate_pos? integer
---Only display buffers from the current tab.
---@field current_tab_only? boolean
---Tab title prefix in the results list.
---@field tab_title? string
---Marker for the current tab.
---@field tab_marker? string
---Jump to the selected buffer's location in the file.
---@field locate? boolean
M.defaults.tabs = {
  _type          = "file",
  previewer      = M._default_previewer_fn,
  tab_title      = "Tab",
  tab_marker     = "<<",
  locate         = true,
  file_icons     = 1, ---@type integer|boolean
  color_icons    = true,
  _actions       = function()
    return M.globals.actions.buffers or M.globals.actions.files
  end,
  actions        = {
    ["enter"]  = actions.buf_switch,
    ["ctrl-x"] = { fn = actions.buf_del, reload = true },
  },
  fzf_opts       = {
    ["--multi"]     = true,
    ["--delimiter"] = "[\t\\)]",
    ["--tabstop"]   = "1",
    ["--with-nth"]  = "5..",
  },
  _cached_hls    = { "buf_nr", "buf_flag_cur", "buf_flag_alt", "tab_title", "tab_marker", "path_linenr" },
  _headers       = { "actions", "cwd" },
  _ctx           = { includeBuflist = true },
  _resume_reload = true,
}

---Open buffers lines.
---@class fzf-lua.config.Lines: fzf-lua.config.BufferLines
---Show buffer name in results. Set to a number to only show if the window width exceeds this value.
---@field show_bufname? boolean|integer
---Show buffer name max length
---@field show_bufname_len? integer
---Include unloaded (not yet displayed) buffers.
---@field show_unloaded? boolean
---Include unlisted buffers (`:help unlisted-buffer`).
---@field show_unlisted? boolean
---Exclude terminal buffers from the list.
---@field no_term_buffers? boolean
---Sort buffers by last used.
---@field sort_lastused? boolean
M.defaults.lines = {
  previewer        = M._default_previewer_fn,
  file_icons       = 1, ---@type integer|boolean
  color_icons      = true,
  show_bufname     = 120,
  show_bufname_len = 15,
  show_unloaded    = true,
  show_unlisted    = false,
  no_term_buffers  = true,
  sort_lastused    = true,
  fzf_opts         = {
    ["--multi"]     = true,
    ["--delimiter"] = "[\t]",
    ["--tabstop"]   = "1",
    ["--tiebreak"]  = "index",
    ["--with-nth"]  = "2..",
    ["--nth"]       = "4..",
  },
  line_field_index = "{4}",
  field_index_expr = "{}", -- For `_fmt.from` to work with `bat_native`
  _treesitter      = true,
  _cached_hls      = { "buf_id", "buf_name", "buf_linenr" },
  _fmt             = {
    -- NOTE: `to` is not needed, we format at the source in `buffer_lines`
    to   = false,
    from = function(s, _)
      -- restore the format to something that `path.entry_to_file` can handle
      local bufnr0, lnum, text = s:match("%[(%d+)%].-(%d+) (.+)$")
      local bufnr = tonumber(bufnr0)
      if not bufnr then return "" end ---@cast bufnr integer
      return string.format("[%s]%s%s:%s:%s",
        bufnr, utils.nbsp,
        path.tail(vim.api.nvim_buf_get_name(bufnr)),
        lnum, text)
    end
  },
  _actions         = function()
    return M.globals.actions.buffers or M.globals.actions.files
  end,
  _ctx             = { includeBuflist = true },
}

---Current buffer lines.
---@diagnostic disable-next-line: param-type-mismatch
---@class fzf-lua.config.Blines: fzf-lua.config.Lines
M.defaults.blines = vim.tbl_deep_extend("force", M.defaults.lines, {
  show_bufname    = false,
  show_unloaded   = true,
  show_unlisted   = true,
  no_term_buffers = false,
  fzf_opts        = {
    ["--with-nth"] = "4..",
    ["--nth"]      = "2..",
  },
  _resume_reload  = true,
})

---Current buffer treesitter symbols.
---@class fzf-lua.config.Treesitter: fzf-lua.config.Base
---Buffer number to search, default: current buffer.
---@field bufnr? integer
---@field node_filter? function
M.defaults.treesitter = {
  previewer        = M._default_previewer_fn,
  file_icons       = false, ---@type integer|boolean
  color_icons      = false,
  fzf_opts         = {
    ["--multi"]     = true,
    ["--tabstop"]   = "4",
    ["--delimiter"] = "[:]",
    ["--with-nth"]  = "2..",
  },
  line_field_index = "{2}",
  _actions         = function()
    return M.globals.actions.buffers or M.globals.actions.files
  end,
  _cached_hls      = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" },
  _fmt             = {
    to   = false,
    from = function(s, _)
      return s:gsub("\t\t", ": ")
    end
  },
}

---Misspelled words in buffer.
---@class fzf-lua.config.Spellcheck: fzf-lua.config.BufferLines
---Lua pattern used to split words for spell checking.
---@field word_separator string
---Buffer number to check, default: current buffer.
---@field bufnr? integer
M.defaults.spellcheck = {
  previewer        = M._default_previewer_fn,
  file_icons       = false,
  color_icons      = false,
  word_separator   = "[%s%p]",
  fzf_opts         = {
    ["--multi"]     = true,
    ["--tabstop"]   = "4",
    ["--delimiter"] = "[:]",
    ["--with-nth"]  = "2..",
  },
  line_field_index = "{2}",
  _actions         = function()
    return M.globals.actions.buffers or M.globals.actions.files
  end,
  actions          = {
    ["ctrl-s"] = { fn = actions.spell_suggest, header = "spell suggest" }
  },
  _cached_hls      = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" },
  _headers         = { "actions" },
  _fmt             = {
    to   = false,
    from = function(s, _)
      return s:gsub("\t\t", ": ")
    end
  },
}

---@param line string
---@param include_file boolean?
---@return string?, string?, { start_col: integer, end_col: integer, text: string? }?
local function ctag_line_parser(line, include_file)
  local start_col, end_col = utils.ctag_match(line)
  if not start_col or not end_col then return end
  -- remove tag's wrapping slashes
  start_col = start_col + 1
  end_col = end_col - 1
  local tag = line:sub(start_col, end_col)
  local text, had_caret, had_dollar = utils.regex_strip_anchors(tag)
  local file = (function()
    if not include_file then return "" end
    -- NOTE: since fzf expands tabs to space(s) we cannot extract the
    -- file deterministically, we therefore do a "best effort" backwards
    -- search for "<foo.bar><space(s)>/<tag>/", while this can fail it is
    -- somewhat acceptable as filenames without extensions are irrelevant
    -- as treesitter won't be able to determine the filetype anyways
    -- NOTE: (-2) as we already advanced start_col past the first /
    return line:sub(1, start_col - 2):match("([^%s]+%.[^%s]+)%s+$")
  end)()
  -- include_file was requested but file wasn't found (tags), bail
  if not file then return end
  return file, nil, {
    -- NOTE: ts indexes are zero based
    start_col = start_col + had_caret - 1,
    end_col = end_col - had_dollar,
    text = text
  }
end

---@class fzf-lua.config.TagsBase: fzf-lua.config.Base
---Path to the tags file, default: auto-detect.
---@field ctags_file? string
---Shell command used to generate the tags list.
---@field cmd? string
---Search project ctags.
---@class fzf-lua.config.Tags: fzf-lua.config.TagsBase
---@class fzf-lua.config.TagsGrep: fzf-lua.config.TagsBase,fzf-lua.config.Grep
M.defaults.tags = {
  previewer     = { _ctor = previewers.builtin.tags },
  input_prompt  = "[tags] Grep For> ",
  rg_opts       = "--no-heading --color=always --smart-case",
  grep_opts     = "--color=auto " .. GREP_PERL_REGEXP,
  multiprocess  = true, ---@type integer|boolean
  fn_transform  = [[return require("fzf-lua.make_entry").tag]],
  fn_preprocess = [[return require("fzf-lua.make_entry").preprocess]],
  file_icons    = 1, ---@type integer|boolean
  git_icons     = false,
  color_icons   = true,
  formatter     = false,
  fzf_opts      = {
    ["--delimiter"] = "[\t]",
    ["--tabstop"]   = "6",
    ["--tiebreak"]  = "begin",
  },
  -- line_field_index = "{4}",
  -- field_index_expr = "{}", -- For `_fmt.from` to work with `bat_native`
  _actions      = function() return M.globals.actions.files end,
  actions       = { ["ctrl-g"] = { actions.grep_lgrep } },
  _treesitter   = function(line, _) return ctag_line_parser(line, true) end,
}

---Search current buffer ctags.
---@class fzf-lua.config.Btags : fzf-lua.config.Tags
---@field filename? string
---@field _btags_cmd? string
---Path to the ctags binary.
---@field ctags_bin? string
---Arguments passed to ctags when generating tags.
---@field ctags_args? string
---Auto-generate ctags for the current buffer if no tags file exists.
---@field ctags_autogen? boolean
---@diagnostic disable-next-line: param-type-mismatch, assign-type-mismatch
M.defaults.btags = vim.tbl_deep_extend("force", M.defaults.tags, {
  ctags_file     = false, -- auto-detect
  ctags_autogen  = true,
  rg_opts        = "--color=never --no-heading",
  grep_opts      = "--color=never " .. GREP_PERL_REGEXP,
  file_icons     = false, ---@type integer|boolean
  fzf_opts       = { ["--with-nth"] = "1,3.." },
  actions        = { ["ctrl-g"] = false },
  _resume_reload = true,
  _treesitter    = function(line) return ctag_line_parser(line) end,
})

---Installed colorschemes.
---@class fzf-lua.config.Colorschemes: fzf-lua.config.Base
---Override the list of colorschemes to display.
---@field colors string[]
---Lua patterns to filter colorschemes.
---@field ignore_patterns string[]
---Preview colorschemes as you navigate.
---@field live_preview boolean
M.defaults.colorschemes = {
  live_preview = true,
  winopts      = { height = 0.55, width = 0.50, backdrop = false },
  fzf_opts     = { ["--no-multi"] = true },
  actions      = { ["enter"] = actions.colorscheme },
  _headers     = { "actions" },
}

---Neovim highlight groups.
---@class fzf-lua.config.Highlights: fzf-lua.config.Base
M.defaults.highlights = {
  fzf_opts   = { ["--no-multi"] = true },
  fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" },
  previewer  = { _ctor = previewers.builtin.highlights, },
  actions    = { ["enter"] = actions.hi }
}

---Awesome Neovim colorschemes.
---@class fzf-lua.config.AwesomeColorschemes: fzf-lua.config.Base
---Icons for download status: [downloading, downloaded, not downloaded].
---@field icons [string, string, string]
---@field _adm fzf-lua.AsyncDownloadManager
---@field dl_status integer
---@field _apply_awesome_theme function
---Preview colorschemes as you navigate.
---@field live_preview boolean
---Maximum concurrent download threads.
---@field max_threads integer
---Path to the colorschemes database JSON file.
---@field dbfile string
---Path where downloaded colorschemes will be stored.
---@field packpath string|function
M.defaults.awesome_colorschemes = {
  winopts      = { row = 0, col = 0.99, width = 0.50, backdrop = false },
  live_preview = true,
  max_threads  = 5,
  fzf_opts     = {
    ["--multi"]     = true,
    ["--delimiter"] = "[:]",
    ["--with-nth"]  = "3..",
    ["--tiebreak"]  = "index",
  },
  dbfile       = "data/colorschemes.json",
  icons        = { utils.ansi_codes.blue("󰇚"), utils.ansi_codes.yellow(""), " " },
  packpath     = function()
    ---@diagnostic disable-next-line: assign-type-mismatch
    return path.join({ vim.fn.stdpath("cache"), "fzf-lua" })
  end,
  actions      = {
    ["enter"]  = actions.colorscheme,
    ["ctrl-g"] = { fn = actions.toggle_bg, exec_silent = true },
    ["ctrl-d"] = { fn = actions.cs_update, reload = true },
    ["ctrl-x"] = { fn = actions.cs_delete, reload = true },
  }
}

---Neovim help tags.
---@class fzf-lua.config.Helptags: fzf-lua.config.Base
---Fallback to searching all help files if no tags match.
---@field fallback? boolean
M.defaults.helptags = {
  actions   = {
    ["enter"]  = actions.help,
    ["ctrl-s"] = actions.help,
    ["ctrl-v"] = actions.help_vert,
    ["ctrl-t"] = actions.help_tab,
  },
  fzf_opts  = {
    ["--no-multi"]  = true,
    ["--delimiter"] = string.format("[%s]", utils.nbsp),
    ["--with-nth"]  = "..-2",
    ["--tiebreak"]  = "begin",
  },
  previewer = {
    _ctor = previewers.builtin.help_tags,
  },
}

---Man pages.
---@class fzf-lua.config.Manpages: fzf-lua.config.Base
---Shell command used to list man pages.
---@field cmd string
M.defaults.manpages = {
  cmd       = "man -k .",
  actions   = {
    ["enter"]  = actions.man,
    ["ctrl-s"] = actions.man,
    ["ctrl-v"] = actions.man_vert,
    ["ctrl-t"] = actions.man_tab,
  },
  fzf_opts  = { ["--tiebreak"] = "begin", ["--no-multi"] = true },
  previewer = "man",
}

---@class fzf-lua.config.LspBase: fzf-lua.config.Base
---@field lsp_handler? fzf-lua.LspHandler
---@field lsp_params? table|(fun(client: vim.lsp.Client, bufnr: integer): table?)
---Automatically jump to the location when there's only a single result.
---@field jump1? boolean
---Action to execute when `jump1` is triggered.
---@field jump1_action? fzf-lua.config.Action
---Set to `true` for async LSP requests, or timeout (ms) for `vim.lsp.buf_request_sync`.
---@field async_or_timeout? integer|boolean
---Reuse the current window for jumping to the location.
---@field reuse_win? boolean

---LSP references, definitions, etc.
---@class fzf-lua.config.Lsp: fzf-lua.config.LspBase
---Set to `true` for async LSP requests, or timeout (ms) for `vim.lsp.buf_request_sync`.
---@field async_or_timeout? integer|boolean
---@field symbols fzf-lua.config.LspSymbols
---@field document_symbols fzf-lua.config.LspDocumentSymbols
---@field workspace_symbols fzf-lua.config.LspWorkspaceSymbols
---@field finder fzf-lua.config.LspFinder
---@field code_actions fzf-lua.config.LspCodeActions
M.defaults.lsp = {
  previewer        = M._default_previewer_fn,
  file_icons       = 1, ---@type integer|boolean
  color_icons      = true,
  git_icons        = false,
  async_or_timeout = 5000,
  jump1            = true,
  jump1_action     = actions.file_edit,
  fzf_opts         = { ["--multi"] = true },
  _actions         = function() return M.globals.actions.files end,
  _cached_hls      = { "path_colnr", "path_linenr" },
  _treesitter      = true,
  -- Signals actions to use uri triggering the use of `lsp.util.show_document`
  _uri             = true,
  _headers         = { "actions", "regex_filter" },
}

---LSP symbols (shared config).
---@class fzf-lua.config.LspSymbols: fzf-lua.config.LspBase
---Initial query to filter symbols.
---@field lsp_query? string
---Custom highlight function for symbol kinds.
---@field symbol_hl? fun(s:string):string
---Custom format function for symbol display.
---@field symbol_fmt? fun(s:string, ...):string
---Display style for symbol kinds, `1` for icon+kind, `2` for icon only, `3` for kind only.
---@field symbol_style? integer|false
---Icons for each symbol kind.
---@field symbol_icons? table<string, string>
---Display child prefix (indentation) for nested symbols.
---@field child_prefix? boolean
---Display parent postfix for nested symbols.
---@field parent_postfix? boolean
---Jump to the selected symbol location in the file.
---@field locate? boolean
M.defaults.lsp.symbols = {
  previewer        = M._default_previewer_fn,
  locate           = false,
  file_icons       = 1, ---@type integer|boolean
  color_icons      = true,
  git_icons        = false,
  symbol_style     = 1,
  symbol_icons     = {
    File          = "󰈙",
    Module        = "",
    Namespace     = "󰦮",
    Package       = "",
    Class         = "󰆧",
    Method        = "󰊕",
    Property      = "",
    Field         = "",
    Constructor   = "",
    Enum          = "",
    Interface     = "",
    Function      = "󰊕",
    Variable      = "󰀫",
    Constant      = "󰏿",
    String        = "",
    Number        = "󰎠",
    Boolean       = "󰨙",
    Array         = "󱡠",
    Object        = "",
    Key           = "󰌋",
    Null          = "󰟢",
    EnumMember    = "",
    Struct        = "󰆼",
    Event         = "",
    Operator      = "󰆕",
    TypeParameter = "󰗴",
  },
  symbol_hl        = function(s) return "@" .. s:lower() end,
  symbol_fmt       = function(s, _) return "[" .. s .. "]" end,
  child_prefix     = true,
  parent_postfix   = false,
  async_or_timeout = true,
  -- new formatting options with symbol name at the start
  fzf_opts         = {
    ["--delimiter"] = string.format("[:%s]", utils.nbsp),
    ["--tiebreak"]  = "begin",
    ["--multi"]     = true,
  },
  line_field_index = "{-2}", -- line field index
  field_index_expr = "{}",   -- entry field index
  _actions         = function() return M.globals.actions.files end,
  _uri             = true,
  _fmt             = {
    -- NOT NEEDED: we format at the source in `lsp.symbol_handler`
    -- to = function(s, _)
    --   local file, text = s:match("^(.+:.+:.+:)%s(.*)")
    --   -- fzf has alignment issues with ansi colorings of different escape length
    --   local align = 56 + utils.ansi_escseq_len(text)
    --   return string.format("%-" .. align .. "s%s%s", text, utils.nbsp, file)
    -- end,
    -- `_from` will be called by `path.entry_to_file` *before* `from` so we
    -- can combine `path.filename_first` with the symbol hardcoded formatter
    _from = function(s, _)
      -- restore the format to something that `path.entry_to_file` can
      -- handle more robustly, while this can still work due to the `utils.nbsp`
      -- it will fail when the symbol contains "[%d]" (which we use as bufnr)
      local text, file = s:match(string.format("^(.-)%s(.*)", utils.nbsp))
      return string.format("%s %s", file, text)
    end
  },
}

---LSP document symbols.
---@diagnostic disable-next-line: assign-type-mismatch
---@class fzf-lua.config.LspDocumentSymbols: fzf-lua.config.LspSymbols
---@field __sym_bufnr? integer
---@field __sym_bufname? string
M.defaults.lsp.document_symbols = vim.tbl_deep_extend("force", {}, M.defaults.lsp.symbols, {
  git_icons   = false,
  file_icons  = false, ---@type integer|boolean
  fzf_opts    = {
    ["--tiebreak"]  = "end",
    ["--multi"]     = true,
    ["--tabstop"]   = "4",
    ["--delimiter"] = "[:]",
    ["--with-nth"]  = utils.__IS_WINDOWS and "3.." or "2..",
  },
  _fmt        = {
    _from = function(s)
      -- Remove [<bufnr>] so  entry_to_file can parse as URI
      return s:gsub(".-" .. utils.nbsp, ""):gsub("\t\t", ": ")
    end
  },
  _cached_hls = { "path_colnr", "buf_name", "buf_nr", "buf_linenr" },
  _headers    = { "regex_filter" },
})

---LSP workspace symbols.
---@diagnostic disable-next-line: assign-type-mismatch
---@class fzf-lua.config.LspWorkspaceSymbols: fzf-lua.config.LspSymbols
---@field _headers? string[]
---@field __resume_set? function
---@field __resume_get? function
M.defaults.lsp.workspace_symbols = vim.tbl_deep_extend("force", {}, M.defaults.lsp.symbols, {
  exec_empty_query = true,
  actions          = { ["ctrl-g"] = { actions.sym_lsym } },
  _cached_hls      = { "live_sym", "path_colnr", "path_linenr" },
  _headers         = { "actions", "cwd", "regex_filter" },
})

---All LSP locations combined.
---@class fzf-lua.config.LspFinder: fzf-lua.config.LspBase
---Use async LSP requests.
---@field async boolean
---Separator between provider prefix and entry text.
---@field separator string
---@field _providers table<string, boolean>
---List of LSP providers to query, e.g. `{ "references", "definitions" }`.
---@field providers table
---Do not automatically close the picker when a single result is found.
---@field no_autoclose boolean
M.defaults.lsp.finder = {
  previewer   = M._default_previewer_fn,
  file_icons  = 1, ---@type integer|boolean
  color_icons = true,
  git_icons   = false,
  async       = true,
  silent      = true,
  separator   = "|" .. utils.nbsp,
  _actions    = function() return M.globals.actions.files end,
  -- currently supported providers, defined as map so we can query easily
  _providers  = {
    references      = true,
    definitions     = true,
    declarations    = true,
    typedefs        = true,
    implementations = true,
    incoming_calls  = true,
    outgoing_calls  = true,
    type_sub        = true,
    type_super      = true,
  },
  -- by default display all supported providers
  providers   = {
    { "declarations",    prefix = utils.ansi_codes.magenta("decl") },
    { "implementations", prefix = utils.ansi_codes.green("impl") },
    { "definitions",     prefix = utils.ansi_codes.green("def ") },
    { "typedefs",        prefix = utils.ansi_codes.red("tdef") },
    { "references",      prefix = utils.ansi_codes.blue("ref ") },
    { "incoming_calls",  prefix = utils.ansi_codes.cyan("in  ") },
    { "outgoing_calls",  prefix = utils.ansi_codes.yellow("out ") },
    { "type_sub",        prefix = utils.ansi_codes.cyan("sub ") },
    { "type_super",      prefix = utils.ansi_codes.yellow("supr") },
  },
  fzf_opts    = { ["--multi"] = true },
  _treesitter = true,
  _cached_hls = { "path_colnr", "path_linenr" },
  _headers    = { "actions", "regex_filter" },
  _uri        = true,
}

---LSP code actions.
---@class fzf-lua.config.LspCodeActions: fzf-lua.config.LspBase
---Callback to execute after applying a code action.
---@field post_action_cb function
---Code action context passed to the LSP server.
---@field context vim.lsp.buf.code_action.context
---Filter function to exclude certain code actions.
---@field filter fun(x: lsp.CodeAction|lsp.Command):boolean
---@field _ui_select? { kind: string }
---@field _items any[]
M.defaults.lsp.code_actions = {
  -- previewer        = "codeaction_native",
  previewer = "codeaction",
  fzf_opts  = { ["--no-multi"] = true },
  actions   = {
    ["enter"] = {
      fn = function(...)
        return require("fzf-lua.providers.ui_select").accept_item(...)
      end,
      desc = "accept-item"
    }
  }
}

---Workspace/document diagnostics.
---@class fzf-lua.config.Diagnostics: fzf-lua.config.Base
---Override default diagnostic signs.
---@field signs? table
---Filter diagnostics by exact severity.
---@field severity_only? vim.diagnostic.SeverityFilter
---Filter diagnostics up to and including this severity level.
---@field severity_limit? vim.diagnostic.Severity|1|2|3|4
---Filter diagnostics from this severity level and below.
---@field severity_bound? vim.diagnostic.Severity|1|2|3|4
---Filter diagnostics by namespace.
---@field namespace? integer
---Include all workspace diagnostics (not just current buffer).
---@field diag_all? boolean
---Filter diagnostics by LSP client ID.
---@field client_id? integer
---Sort diagnostics by severity, set to `false` to disable sorting.
---@field sort? integer|boolean
---Add padding after diagnostic icons for alignment.
---@field icon_padding? boolean
---Display diagnostic icons.
---@field diag_icons? boolean
---Display diagnostic source (e.g. `lua_ls`, `eslint`).
---@field diag_source? boolean
---Display diagnostic code.
---@field diag_code? boolean
---Enable multiline diagnostics display, set to a number for max lines.
---@field multiline? integer|boolean
---Color the file/buffer headings.
---@field color_headings? boolean
M.defaults.diagnostics = {
  previewer      = M._default_previewer_fn,
  file_icons     = false, ---@type integer|boolean
  color_icons    = true,
  color_headings = true,
  git_icons      = false,
  diag_icons     = true,
  diag_source    = true,
  diag_code      = true,
  multiline      = 2, ---@type integer|boolean
  fzf_opts       = {
    ["--multi"] = true,
    ["--wrap"]  = true,
  },
  _actions       = function() return M.globals.actions.files end,
  _cached_hls    = { "path_colnr", "path_linenr" },
  _headers       = { "actions", "cwd" },
  -- signs = {
  --   ["Error"] = { text = "e", texthl = "DiagnosticError" },
  --   ["Warn"]  = { text = "w", texthl = "DiagnosticWarn" },
  --   ["Info"]  = { text = "i", texthl = "DiagnosticInfo" },
  --   ["Hint"]  = { text = "h", texthl = "DiagnosticHint" },
  -- },
}

---Fzf-lua builtin commands.
---@class fzf-lua.config.Builtin: fzf-lua.config.Base
---@field metatable table
---@field metatable_exclude table
M.defaults.builtin = {
  no_resume = true,
  winopts   = { height = 0.65, width = 0.50, preview = { hidden = true } },
  fzf_opts  = { ["--no-multi"] = true },
  preview   = function(args)
    local options_md = require("fzf-lua.cmd").options_md()
    return type(options_md) == "table" and options_md[args[1]:lower()] or ""
  end,
  actions   = { ["enter"] = actions.run_builtin },
}

---Fzf-lua configuration profiles.
---@class fzf-lua.config.Profiles: fzf-lua.config.Base
---@field load fzf-lua.profile
M.defaults.profiles = {
  previewer = M._default_previewer_fn,
  fzf_opts  = {
    ["--delimiter"] = "[:]",
    ["--with-nth"]  = "-1..",
    ["--tiebreak"]  = "begin",
    ["--no-multi"]  = true,
  },
  actions   = { ["enter"] = actions.apply_profile },
}

---Neovim marks.
---@class fzf-lua.config.Marks: fzf-lua.config.Base
---Lua pattern to filter marks.
---@field marks? string
---Sort marks alphabetically. Set to `false` to maintain original order.
---@field sort? boolean
M.defaults.marks = {
  sort        = false,
  fzf_opts    = { ["--no-multi"] = true },
  actions     = {
    ["enter"] = actions.goto_mark,
    ["ctrl-s"] = actions.goto_mark_split,
    ["ctrl-v"] = actions.goto_mark_vsplit,
    ["ctrl-t"] = actions.goto_mark_tabedit,
    ["ctrl-x"] = { fn = actions.mark_del, reload = true }
  },
  previewer   = { _ctor = previewers.builtin.marks },
  _cached_hls = { "buf_nr", "path_linenr", "path_colnr" },
}

---Change list.
---@class fzf-lua.config.Changes: fzf-lua.config.Jumps
M.defaults.changes = {
  cmd       = "changes",
  h1        = "change",
  actions   = { ["enter"] = actions.goto_jump },
  previewer = { _ctor = previewers.builtin.jumps },
}

---Jump list.
---@class fzf-lua.config.Jumps: fzf-lua.config.Base
---@field cmd string
---@field h1 string
M.defaults.jumps = {
  cmd       = "jumps",
  fzf_opts  = { ["--no-multi"] = true },
  actions   = { ["enter"] = actions.goto_jump },
  previewer = { _ctor = previewers.builtin.jumps },
}

---Tag stack.
---@class fzf-lua.config.Tagstack: fzf-lua.config.Base
M.defaults.tagstack = {
  file_icons  = 1, ---@type integer|boolean
  color_icons = true,
  git_icons   = true,
  fzf_opts    = { ["--multi"] = true },
  previewer   = M._default_previewer_fn,
  _actions    = function() return M.globals.actions.files end,
}

---Neovim commands.
---@class fzf-lua.config.Commands: fzf-lua.config.Base
---Table of commands to flatten (display without subcommands).
---@field flatten table<string, boolean>
---Include builtin Neovim commands.
---@field include_builtin boolean
---Sort commands by last used.
---@field sort_lastused boolean
M.defaults.commands = {
  actions         = { ["enter"] = actions.ex_run },
  flatten         = {},
  include_builtin = true,
  _cached_hls     = { "cmd_ex", "cmd_buf", "cmd_global" },
}

---Neovim autocommands.
---@class fzf-lua.config.Autocmds: fzf-lua.config.Base
---Show the description field for autocommands in the list.
---@field show_desc boolean
M.defaults.autocmds = {
  show_desc = true, -- show desc field in fzf list
  previewer = { _ctor = previewers.builtin.autocmds },
  _actions  = function() return M.globals.actions.files end,
  fzf_opts  = {
    ["--delimiter"] = "[│]",
    ["--with-nth"]  = "2..",
    ["--no-multi"]  = true,
  },
}

---Undo tree.
---@class fzf-lua.config.Undotree: fzf-lua.config.Base
---@field __locate_pos? integer
---Jump to the current undo position on picker open.
---@field locate boolean
---Undo tree draw style, `tree` for the existing box-drawing layout or `graph` for the `:Undotree` ASCII graph layout.
---@field tree_style "tree"|"graph"
M.defaults.undotree = {
  previewer      = "undotree",
  locate         = true,
  tree_style     = "tree",
  fzf_opts       = { ["--no-multi"] = true },
  actions        = { ["enter"] = actions.undo },
  _cached_hls    = { "buf_linenr", "buf_name", "path_linenr", "dir_part" },
  _resume_reload = true,
  keymap         = { builtin = { ["<F8>"] = "toggle-preview-undo" } },
}

---Command history.
---@class fzf-lua.config.CommandHistory: fzf-lua.config.Base
---Reverse the order of the history list (oldest first).
---@field reverse_list? boolean
M.defaults.command_history = {
  fzf_opts    = { ["--tiebreak"] = "index", ["--no-multi"] = true },
  render_crlf = true,
  _treesitter = function(line) return "foo.vim", nil, line end,
  fzf_colors  = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" },
  actions     = {
    ["enter"]  = actions.ex_run_cr,
    ["ctrl-e"] = actions.ex_run,
    ["ctrl-x"] = { fn = actions.ex_del, field_index = "{+n}", reload = true }
  },
  _headers    = { "actions" },
}

---Search history.
---@class fzf-lua.config.SearchHistory : fzf-lua.config.CommandHistory
---Reverse the order of the history list (oldest first).
---@field reverse_list? boolean
---Also search in reverse direction.
---@field reverse_search? boolean
M.defaults.search_history = {
  fzf_opts    = { ["--tiebreak"] = "index", ["--no-multi"] = true },
  render_crlf = true,
  _treesitter = function(line) return "", nil, line, "regex" end,
  fzf_colors  = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" },
  actions     = {
    ["enter"]  = actions.search_cr,
    ["ctrl-e"] = actions.search,
    ["ctrl-x"] = { fn = actions.search_del, field_index = "{+n}", reload = true }
  },
  _headers    = { "actions" },
}

---Neovim registers.
---@class fzf-lua.config.Registers: fzf-lua.config.Base
---Lua pattern or function to filter registers.
---@field filter string|function
---Display multiline register contents, set to a number for max lines.
---@field multiline? integer|boolean
---Ignore empty registers.
---@field ignore_empty? boolean
M.defaults.registers = {
  multiline    = true, ---@type integer|boolean
  ignore_empty = true,
  actions      = { ["enter"] = actions.paste_register },
  fzf_opts     = { ["--no-multi"] = true },
}

---Neovim keymaps.
---@class fzf-lua.config.Keymaps: fzf-lua.config.Base
---Lua patterns to filter keymaps.
---@field ignore_patterns string[]
---Show the description field for keymaps in the list.
---@field show_desc boolean
---Show additional keymap details (buffer, noremap, etc).
---@field show_details boolean
---List of modes to include, e.g. `{ "n", "i", "v" }`.
---@field modes string[]
M.defaults.keymaps = {
  previewer       = { _ctor = previewers.builtin.keymaps },
  winopts         = { preview = { layout = "vertical" } },
  fzf_opts        = { ["--tiebreak"] = "index", ["--no-multi"] = true },
  ignore_patterns = { "^<SNR>", "^<Plug>" },
  show_desc       = true,
  show_details    = true,
  actions         = {
    ["enter"]  = actions.keymap_apply,
    ["ctrl-s"] = actions.keymap_split,
    ["ctrl-v"] = actions.keymap_vsplit,
    ["ctrl-t"] = actions.keymap_tabedit,
  },
}

---Neovim options.
---@class fzf-lua.config.NvimOptions: fzf-lua.config.Base
---Separator between option name and value.
---@field separator string
---Colorize option values.
---@field color_values boolean
M.defaults.nvim_options = {
  previewer    = { _ctor = previewers.builtin.nvim_options },
  separator    = "│",
  color_values = true,
  actions      = {
    ["enter"]     = { fn = actions.nvim_opt_edit_local, reload = true },
    ["alt-enter"] = { fn = actions.nvim_opt_edit_global, reload = true },
  },
  fzf_opts     = {
    ["--nth"] = 1,
    ["--delimiter"] = "[│]",
    ["--no-multi"] = true,
  },
}

---Spelling suggestions.
---@class fzf-lua.config.SpellSuggest: fzf-lua.config.Base
---The pattern used to match the word under the cursor. Text around the cursor position that matches will be used as the initial query and replaced by a chosen completion. The default matches anything but spaces and single/double quotes.
---@field word_pattern? string
M.defaults.spell_suggest = {
  winopts = {
    relative = "cursor",
    row      = 1,
    col      = 0,
    height   = 0.40,
    width    = 0.30,
  },
  actions = {
    ["enter"] = actions.complete,
  },
}

---Neovim server list.
---@class fzf-lua.config.Serverlist : fzf-lua.config.Base
---@field _screenshot string
M.defaults.serverlist = {
  _screenshot = vim.fn.tempname(),
  previewer = { _ctor = previewers.fzf.nvim_server },
  _resume_reload = true, -- avoid list contain killed server unhide
  actions = {
    ["enter"] = actions.serverlist_connect,
    ["ctrl-o"] = { fn = actions.serverlist_spawn, reload = true, header = "spawn" },
    ["ctrl-x"] = { fn = actions.serverlist_kill, reload = true, header = "kill" },
    ["ctrl-r"] = { fn = function() end, reload = true, header = "reload" },
  },
}


---Filetypes.
---@class fzf-lua.config.Filetypes : fzf-lua.config.Base
M.defaults.filetypes = {
  file_icons = false, ---@type integer|boolean
  actions    = { ["enter"] = actions.set_filetype },
}

---`:packadd <package>`.
---@class fzf-lua.config.Packadd : fzf-lua.config.Base
M.defaults.packadd = {
  actions = {
    ["enter"] = actions.packadd,
  },
}

---Neovim menus.
---@class fzf-lua.config.Menus : fzf-lua.config.Base
M.defaults.menus = {
  actions = {
    ["enter"] = actions.exec_menu,
  },
}

---Tmux integration pickers.
---@class fzf-lua.config.Tmux
---@field buffers fzf-lua.config.TmuxBuffers
---@field cmd string
M.defaults.tmux = {
  ---Tmux paste buffers.
  ---@class fzf-lua.config.TmuxBuffers: fzf-lua.config.Base
  buffers = {
    cmd      = "tmux list-buffers",
    register = [["]],
    actions  = { ["enter"] = actions.tmux_buf_set_reg },
    fzf_opts = { ["--no-multi"] = true, ["--delimiter"] = "[:]" }
  },
}

---DAP (Debug Adapter Protocol) pickers.
---@class fzf-lua.config.DapBase: fzf-lua.config.Base
---@field commands fzf-lua.config.DapCommands
---@field configurations fzf-lua.config.DapConfigurations
---@field variables fzf-lua.config.DapVariables
---@field frames fzf-lua.config.DapFrames
---@field breakpoints fzf-lua.config.DapBreakpoints

---DAP pickers parent table.
---@class fzf-lua.config.Dap
M.defaults.dap = {
  ---DAP builtin commands.
  ---@class fzf-lua.config.DapCommands: fzf-lua.config.DapBase
  commands       = { fzf_opts = { ["--no-multi"] = true }, },
  ---DAP configurations.
  ---@class fzf-lua.config.DapConfigurations: fzf-lua.config.DapBase
  configurations = { fzf_opts = { ["--no-multi"] = true }, },
  ---DAP active session variables.
  ---@class fzf-lua.config.DapVariables: fzf-lua.config.DapBase
  variables      = { fzf_opts = { ["--no-multi"] = true }, },
  ---DAP active session frames.
  ---@class fzf-lua.config.DapFrames: fzf-lua.config.DapBase
  frames         = { fzf_opts = { ["--no-multi"] = true }, },
  ---DAP breakpoints.
  ---@class fzf-lua.config.DapBreakpoints: fzf-lua.config.DapBase
  breakpoints    = {
    file_icons  = 1, ---@type integer|boolean
    color_icons = true,
    git_icons   = false,
    previewer   = M._default_previewer_fn,
    _actions    = function() return M.globals.actions.files end,
    actions     = { ["ctrl-x"] = { fn = actions.dap_bp_del, reload = true } },
    fzf_opts    = {
      ["--delimiter"] = "[\\]:]",
      ["--with-nth"]  = "2..",
    },
    _cached_hls = { "path_colnr", "path_linenr" },
    _headers    = { "actions", "cwd" },
  },
}

---Complete path under cursor (incl dirs).
---@class fzf-lua.config.CompletePath: fzf-lua.config.Base
---@field cmd? string
---Pattern to match the word under cursor for initial query and replacement.
---@field word_pattern? string
M.defaults.complete_path = {
  file_icons        = false, ---@type integer|boolean
  git_icons         = false,
  color_icons       = true,
  multiprocess      = 1, ---@type integer|boolean
  _type             = "file",
  fzf_opts          = { ["--no-multi"] = true },
  _fzf_nth_devicons = true,
  actions           = { ["enter"] = actions.complete },
}

---Complete file under cursor (excl dirs).
---@class fzf-lua.config.CompleteFile: fzf-lua.config.Base
---@field cmd? string
---Pattern to match the word under cursor for initial query and replacement.
---@field word_pattern? string
M.defaults.complete_file = {
  multiprocess      = 1, ---@type integer|boolean
  _type             = "file",
  file_icons        = 1, ---@type integer|boolean
  color_icons       = true,
  git_icons         = false,
  _actions          = function() return M.globals.actions.files end,
  actions           = { ["enter"] = actions.complete },
  previewer         = M._default_previewer_fn,
  winopts           = { preview = { hidden = true } },
  fzf_opts          = { ["--no-multi"] = true },
  _fzf_nth_devicons = true,
}

---Zoxide recent directories.
---@class fzf-lua.config.Zoxide: fzf-lua.config.Base
---Scope of the `cd` action, possible values are `local|win|tab|global`.
---@field scope? string
---Change to the git root directory instead of the zoxide path.
---@field git_root? boolean
M.defaults.zoxide = {
  multiprocess  = true, ---@type integer|boolean
  fn_transform  = [[return require("fzf-lua.make_entry").zoxide]],
  fn_preprocess = [[return require("fzf-lua.make_entry").preprocess]],
  cmd           = "zoxide query --list --score",
  scope         = "global",
  git_root      = false,
  formatter     = "path.dirname_first",
  fzf_opts      = {
    ["--no-multi"]  = true,
    ["--delimiter"] = "[\t]",
    ["--tabstop"]   = "4",
    ["--tiebreak"]  = "end,index",
    ["--nth"]       = "2..",
    ["--no-sort"]   = true, -- sort by score
  },
  actions       = { enter = actions.zoxide_cd }
}

---Complete line (all open buffers).
---@class fzf-lua.config.CompleteLine: fzf-lua.config.Blines
---@field current_buffer_only? boolean
---@field complete? (fun(s: string[], _o: fzf-lua.config.Resolved, l: string, c: integer):string?, integer?)|boolean
M.defaults.complete_line = vim.tbl_deep_extend("force", M.defaults.blines, {
  complete = true,
})


---@class fzf-lua.config.UISelect: fzf-lua.config.Base
M.defaults.ui_select = {
  fzf_opts = { ["--no-multi"] = true },
  ui_select = { preview_type = "native" },
  actions = {
    ["enter"] = {
      fn = function(...)
        return require("fzf-lua.providers.ui_select").accept_item(...)
      end,
      desc = "accept-item"
    }
  }
}


M.defaults.file_icon_padding = ""

-- No need to sset this, already defaults to `nvim_open_win`
-- M.help_open_win              = vim.api.nvim_open_win

M.defaults.dir_icon = ""

---@class fzf-lua.config.HLS
---Main fzf (terminal) window normal (text/bg) highlight group.
---@field normal string
---Main fzf (terminal) window border highlight group.
---@field border string
---Main fzf (terminal) window title highlight group.
---@field title string
---Main fzf (terminal) window title flags highlight group (hidden, etc).
---@field title_flags string
---Backdrop color, black by default, used to darken the background color when opening the UI.
---@field backdrop string
---Help window (F1) normal (text/bg) highlight group.
---@field help_normal string
---Help window (F1) border highlight group.
---@field help_border string
---Builtin previewer window normal (text/bg) highlight group.
---@field preview_normal string
---Builtin previewer window border highlight group.
---@field preview_border string
---Builtin previewer window title highlight group.
---@field preview_title string
---Builtin previewer window `Cursor` highlight group.
---@field cursor string
---Builtin previewer window `CursorLine` highlight group.
---@field cursorline string
---Builtin previewer window `CursorLineNr` highlight group.
---@field cursorlinenr string
---Builtin previewer window search matches highlight group.
---@field search string
---Builtin previewer window `border` scrollbar empty highlight group.
---@field scrollborder_e string
---Builtin previewer window `border` scrollbar full highlight group.
---@field scrollborder_f string
---Builtin previewer window `float` scrollbar empty highlight group.
---@field scrollfloat_e string
---Builtin previewer window `float` scrollbar full highlight group.
---@field scrollfloat_f string|false
---Interactive headers keybind highlight group, e.g. `<ctrl-g> to Disable .gitignore`.
---@field header_bind string
---Interactive headers description highlight group, e.g. `<ctrl-g> to Disable .gitignore`.
---@field header_text string
---Highlight group for the column part of paths, e.g. `file:<line>:<col>:`, used in pickers such as `buffers`, `quickfix`, `lsp`, `diagnostics`, etc.
---@field path_colnr string
---Highlight group for the line part of paths, e.g. `file:<line>:<col>:`, used in pickers such as `buffers`, `quickfix`, `lsp`, `diagnostics`, etc.
---@field path_linenr string
---Highlight group for buffer name (filepath) in `lines`.
---@field buf_name string
---Highlight group for buffer id (number) in `lines`.
---@field buf_id string
---Highlight group for buffer number in `buffers`, `tabs`.
---@field buf_nr string
---Highlight group for buffer line number in `lines`, `blines` and `treesitter`.
---@field buf_linenr string
---Highlight group for the current buffer flag in `buffers`, `tabs`.
---@field buf_flag_cur string
---Highlight group for the alternate buffer flag in `buffers`, `tabs`.
---@field buf_flag_alt string
---Highlight group for the tab title in `tabs`.
---@field tab_title string
---Highlight group for the current tab marker in `tabs`.
---@field tab_marker string
---Highlight group for the directory icon in paths that end with a separator, usually used in path completion, e.g. `complete_path`.
---@field dir_icon string
---Highlight group for the directory part when using `path.dirname_first` or `path.filename_first` formatters.
---@field dir_part string
---Highlight group for the directory part when using `path.dirname_first` or `path.filename_first` formatters.
---@field file_part string
---Highlight group for the prompt text in "live" pickers.
---@field live_prompt string
---Highlight group for the matched characters in `lsp_live_workspace_symbols`.
---@field live_sym string
---Highlight group for ex commands in `:FzfLua commands`, by default links to `Statement`.
---@field cmd_ex string
---Highlight group for buffer commands in `:FzfLua commands`, by default links to `Added`.
---@field cmd_buf string
---Highlight group for global commands in `:FzfLua commands`, by default links to `Directory`.
---@field cmd_global string
---@field fzf fzf-lua.config.fzfHLS
M.defaults.__HLS = {
  normal         = "FzfLuaNormal",
  border         = "FzfLuaBorder",
  title          = "FzfLuaTitle",
  title_flags    = "FzfLuaTitleFlags",
  backdrop       = "FzfLuaBackdrop",
  help_normal    = "FzfLuaHelpNormal",
  help_border    = "FzfLuaHelpBorder",
  preview_normal = "FzfLuaPreviewNormal",
  preview_border = "FzfLuaPreviewBorder",
  preview_title  = "FzfLuaPreviewTitle",
  cursor         = "FzfLuaCursor",
  cursorline     = "FzfLuaCursorLine",
  cursorlinenr   = "FzfLuaCursorLineNr",
  search         = "FzfLuaSearch",
  scrollborder_e = "FzfLuaScrollBorderEmpty",
  scrollborder_f = "FzfLuaScrollBorderFull",
  scrollfloat_e  = "FzfLuaScrollFloatEmpty",
  scrollfloat_f  = "FzfLuaScrollFloatFull",
  header_bind    = "FzfLuaHeaderBind",
  header_text    = "FzfLuaHeaderText",
  path_colnr     = "FzfLuaPathColNr",
  path_linenr    = "FzfLuaPathLineNr",
  buf_name       = "FzfLuaBufName",
  buf_id         = "FzfLuaBufId",
  buf_nr         = "FzfLuaBufNr",
  buf_linenr     = "FzfLuaBufLineNr",
  buf_flag_cur   = "FzfLuaBufFlagCur",
  buf_flag_alt   = "FzfLuaBufFlagAlt",
  tab_title      = "FzfLuaTabTitle",
  tab_marker     = "FzfLuaTabMarker",
  dir_icon       = "FzfLuaDirIcon",
  dir_part       = "FzfLuaDirPart",
  file_part      = "FzfLuaFilePart",
  live_prompt    = "FzfLuaLivePrompt",
  live_sym       = "FzfLuaLiveSym",
  cmd_ex         = "FzfLuaCmdEx",
  cmd_buf        = "FzfLuaCmdBuf",
  cmd_global     = "FzfLuaCmdGlobal",
  ---@class fzf-lua.config.fzfHLS
  ---Highlight group for fzf's `fg` and `bg`, by default links to `FzfLuaNormal`.
  ---@field normal string
  ---Highlight group for fzf's `fg+` and `bg+`, by default links to `FzfLuaCursorLine`.
  ---@field cursorline string
  ---Highlight group for fzf's `hl+`, by default links to `Special`.
  ---@field match string
  ---Highlight group for fzf's `border`, by default links to `FzfLuaBorder`.
  ---@field border string
  ---Highlight group for fzf's `scrollbar`, by default links to `FzfLuaFzfBorder`.
  ---@field scrollbar string
  ---Highlight group for fzf's `separator`, by default links to `FzfLuaFzfBorder`.
  ---@field separator string
  ---Highlight group for fzf's `gutter`, by default links to `FzfLuaFzfBorder`. NOTE: `bg` property of the highlight group will be used.
  ---@field gutter string
  ---Highlight group for fzf's `header`, by default links to `FzfLuaTitle`.
  ---@field header string
  ---Highlight group for fzf's `info`, by default links to `NonText`.
  ---@field info string
  ---Highlight group for fzf's `pointer`, by default links to `Special`.
  ---@field pointer string
  ---Highlight group for fzf's `marker`, by default links to `FzfLuaFzfPointer`.
  ---@field marker string
  ---Highlight group for fzf's `spinner`, by default links to `FzfLuaFzfPointer`.
  ---@field spinner string
  ---Highlight group for fzf's `prompt`, by default links to `Special`.
  ---@field prompt string
  ---Highlight group for fzf's `query`, by default links to `FzfLuaNormal` and sets text to `regular` (non-bold).
  ---@field query string
  fzf            = {
    normal     = "FzfLuaFzfNormal",
    cursorline = "FzfLuaFzfCursorLine",
    match      = "FzfLuaFzfMatch",
    border     = "FzfLuaFzfBorder",
    scrollbar  = "FzfLuaFzfScrollbar",
    separator  = "FzfLuaFzfSeparator",
    gutter     = "FzfLuaFzfGutter",
    header     = "FzfLuaFzfHeader",
    info       = "FzfLuaFzfInfo",
    pointer    = "FzfLuaFzfPointer",
    marker     = "FzfLuaFzfMarker",
    spinner    = "FzfLuaFzfSpinner",
    prompt     = "FzfLuaFzfPrompt",
    query      = "FzfLuaFzfQuery",
  }
}

return M