Skip to content

bug(picker): win.list / win.input config cannot override the picker's own window defaults #2942

Description

@RyanSaxe

Did you check docs and existing issues?

  • I have read all the snacks.nvim docs
  • I have updated the plugin to the latest version before submitting this issue
  • I have searched the existing issues of snacks.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.12.4

Operating system/version

macOS 14.4

Describe the bug

Snacks.win.resolve(...) gives precedence to its last argument:

Snacks.win.resolve({ wo = { winhighlight = "A" } }, { wo = { winhighlight = "B" } }).wo.winhighlight
--> "B"

win.lua:257 relies on that ordering — M.resolve(Snacks.config.get("win", defaults), opts) — defaults first, user opts last, so user config wins.

The picker's list and input windows call it the other way around:

  • picker/core/list.lua:71Snacks.win.resolve(picker.opts.win.list, { --[[ defaults ]] })
  • picker/core/input.lua:22Snacks.win.resolve(picker.opts.win.input, { --[[ defaults ]] })

So every key those default tables set is unconfigurable through win.list / win.input — globally, per-source, or per-call. The user value isn't merged and losing on a sub-key; it's dropped entirely. wo.winhighlight is the one I hit, but the same applies to wo.cursorline, bo.filetype, minimal, on_win, and the rest.

The box windows and the preview window are constructed differently and aren't affected.

For context on why this isn't just cosmetic: there's no other injection point for these windows either. Mutating win.opts.wo after construction is undone by layout.lua:472, which rebuilds win.opts from the deep copy layout.lua:105 took when the layout was built. Writing the live vim.wo option is undone by win:update() (win.lua:806) on the next layout update, which runs under eventignore = "all" (layout.lua:283-289) so no autocmd can react to it. So for these two windows the defaults are effectively final.

My use case is theming: I want the explorer source, which uses a sidebar layout flush against the terminal edge, to paint on a different background than the floating pickers. They share SnacksPickerList / SnacksPickerInput, and per-source win config is the natural lever.

Steps To Reproduce

  1. nvim -u repro.lua
  2. The files picker opens and prints the configured vs. actual winhighlight.
configured: NormalFloat:ErrorMsg
actual    : FloatFooter:SnacksPickerListFooter,CursorLine:SnacksPickerListCursorLine,NormalFloat:SnacksPickerList,FloatBorder:SnacksPickerListBorder,FloatTitle:SnacksPickerListTitle

Expected Behavior

win.list.wo.winhighlight overrides the built-in default, the way win config does everywhere else in snacks.

Swapping the arguments at those two call sites — Snacks.win.resolve({ --[[ defaults ]] }, picker.opts.win.list) — lines them up with win.lua:257. Happy to open a PR if you'd like it that way.

Repro

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
  spec = {
    { "folke/snacks.nvim", opts = { picker = {} } },
  },
})

vim.defer_fn(function()
  Snacks.picker.files({
    win = { list = { wo = { winhighlight = "NormalFloat:ErrorMsg" } } },
    on_show = function(p)
      print("configured: NormalFloat:ErrorMsg")
      print("actual    : " .. p.list.win.opts.wo.winhighlight)
    end,
  })
end, 500)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions