echasnovski / mini.nvim

Library of 40+ independent Lua modules improving overall Neovim (version 0.8 and higher) experience with minimal effort
MIT License
4.53k stars 175 forks source link

[mini.statusline] Inactive status function evaluated in wrong context #779

Closed pkazmier closed 3 months ago

pkazmier commented 3 months ago

Contributing guidelines

Module(s)

mini.statusline

Description

[disclaimer: neovim/lua novice] The function provided to mini.statusline inactive configuration option is not evaluated in the context of the window that the status line belongs to. As a result, any wildcard expansions performed in the user-supplied function, such as vim.fn.expand("%:p"), reference the context of the current window and buffer—not the inactive window and buffer.

This occurs because of line 517 in mini.statusline:

https://github.com/echasnovski/mini.nvim/blob/efa0eb3dc97398e0510372f61bcf625127ab7a24/lua/mini/statusline.lua#L516-L517

I was able to resolve the issue by making a small change to line 517:

      or '%{%v:lua.MiniStatusline.inactive()%}'

Based on the documentation for statusline, the %! expression is evaluated in the context of the current window and buffer, which is fine when rendering the active status line. But the inactive status line should be evaluated in the context of the window and buffer to which the status line belongs, which requires the %{%...%} expression.

Neovim version

NVIM v0.9.5, Build type: Release, LuaJIT 2.1.1703358377

Steps to reproduce

Contents of `minimal.lua`

```lua -- Clone 'mini.nvim' manually in a way that it gets managed by 'mini.deps' local path_package = vim.fn.stdpath("data") .. "/site/" local mini_path = path_package .. "pack/deps/start/mini.nvim" if not vim.loop.fs_stat(mini_path) then vim.cmd('echo "Installing `mini.nvim`" | redraw') local clone_cmd = { "git", "clone", "--filter=blob:none", "https://github.com/echasnovski/mini.nvim", mini_path, } vim.fn.system(clone_cmd) vim.cmd("packadd mini.nvim | helptags ALL") vim.cmd('echo "Installed `mini.nvim`" | redraw') end -- Set up 'mini.deps' (customize to your liking) require("mini.deps").setup({ path = { package = path_package } }) local pretty_path = function(args) return "[" .. args.pretty .. "]" .. vim.fn.expand("%:p") end MiniDeps.now(function() local MiniStatusline = require("mini.statusline") MiniStatusline.setup({ content = { inactive = function() return MiniStatusline.combine_groups({ { hl = "MiniStatuslineFilename", strings = { pretty_path({ pretty = "INACTIVE" }) } }, }) end, active = function() return MiniStatusline.combine_groups({ { hl = "MiniStatuslineFilename", strings = { pretty_path({ pretty = "ACTIVE" }) } }, }) end, }, }) end) ```

  1. echo "This is file ONE" > one.txt
  2. echo "This is file TWO" > two.txt
  3. nvim -nu minimal.lua
  4. :e one.txt
  5. <c-w> s
  6. :e two.txt, the inactive status line incorrectly shows "two.txt"—instead of "one.txt".

Expected behavior

The inactive status line should show "one.txt". Not sure how to point my minimal.lua to my patched version of mini.statusline or I would have provided a screenshot here too.

Actual behavior

The inactive status line (bottom) shows "two.txt"—even though the buffer is for "one.txt":

image
pkazmier commented 3 months ago

The example above is trivial, but my version of pretty_path shortens long directory paths and provides separate highlight groups for directory and filename. In order to do so in the inactive status line, I need the expansion for %:p for the inactive window versus the current buffer and window.

echasnovski commented 3 months ago

Thanks for the issue!

Yes, your analysis looks correct and I agree that this is not ideal. I'll see if %{%...%} has unwanted side effects.

This was not issue previously because sections are usually only used for active window. I don't particularly think that this is a bug per se because it can be overcome with delaying expanding by returning string from pretty_path() (or its complicated alternative):

local pretty_path = function(args) return '[' .. args.pretty .. ']' .. '%{%expand("%:p")%}' end
pkazmier commented 3 months ago

Thanks for the workaround. It's certainly ugly ...

    content = {
      inactive = function()
        return MiniStatusline.combine_groups({
          { hl = "MiniStatuslineFilename", strings = { [[%{%luaeval("pretty_path({ pretty = 'INACTIVE' })")%}]] } },
        })
      end,
    },

... but it does work.

For context, I truncate pathnames from "/a/really/long/pathname" to "/a/.../long/pathname" based on trunc_width. So, for consistency with the active status line, I want my inactive status line to display paths the same way. This is why I supply my own function for the inactive status line. I was perplexed, however, as to why it wasn't working. After googling a bit, I discovered a reddit thread that pointed me to the fact that %! uses the wrong context in this context.

echasnovski commented 3 months ago

Thanks again for noticing this!

It should be fixed on latest main.

pkazmier commented 3 months ago

Thanks!