Repository: nvim-lualine/lualine.nvim (lua)

Issue:
Is there any ways to keep my lualine still?
if i switch to another window like 'NvimTree', i wish to keep my lualine in my main buffer, is there any  options can reach this? If we can keep lualine switching in main buffer except some window ( NvimTree ), that could be better :D

Pull request description:
closes #710

Patch:
diff --git a/README.md b/README.md
index a76247144..19a59f6aa 100644
--- a/README.md
+++ b/README.md
@@ -125,6 +125,7 @@ require('lualine').setup {
       statusline = {},
       winbar = {},
     },
+    ignore_focus = {},
     always_divide_middle = true,
     globalstatus = false,
     refresh = {
@@ -337,7 +338,7 @@ Values set here are treated as default for other options
 that work in component level.
 
 For example even though `icons_enabled` is a general component option.
-you can set `icons_enabled` to `false` and icons will be disabled on all
+You can set `icons_enabled` to `false` and icons will be disabled on all
 component. You can still overwrite defaults set in option table by specifying
 the option value in component.
 
@@ -351,6 +352,13 @@ options = {
       winbar = {},           -- only ignores the ft for winbar.
   },
 
+  ignore_focus = {},         -- If current filetype is in this list it'll
+                             -- always be drawn as inactive statusline
+                             -- and the last window will be drawn as active statusline.
+                             -- for example if you don't want statusline of
+                             -- your file tree / sidebar window to have active
+                             -- statusline you can add their filetypes here.
+
   always_divide_middle = true, -- When set to true, left sections i.e. 'a','b' and 'c'
                                -- can't take over the entire statusline even
                                -- if neither of 'x', 'y' or 'z' are present.
diff --git a/doc/lualine.txt b/doc/lualine.txt
index d4db42133..ae33925c0 100644
--- a/doc/lualine.txt
+++ b/doc/lualine.txt
@@ -109,6 +109,7 @@ For more information, check out `:help lua-heredoc`.
           statusline = {},
           winbar = {},
         },
+        ignore_focus = {},
         always_divide_middle = true,
         globalstatus = false,
         refresh = {
@@ -346,7 +347,7 @@ Global options                         These are `options` that are used in
 Values set here are treated as default for other options that work in component
 level.
 
-For example even though `icons_enabled` is a general component option. you can
+For example even though `icons_enabled` is a general component option. You can
 set `icons_enabled` to `false` and icons will be disabled on all component. You
 can still overwrite defaults set in option table by specifying the option value
 in component.
@@ -361,6 +362,13 @@ in component.
           winbar = {},           -- only ignores the ft for winbar.
       },
     
+      ignore_focus = {},         -- If current filetype is in this list it'll
+                                 -- always be drawn as inactive statusline
+                                 -- and the last window will be drawn as active statusline.
+                                 -- for example if you don't want statusline of
+                                 -- your file tree / sidebar window to have active
+                                 -- statusline you can add their filetypes here.
+    
       always_divide_middle = true, -- When set to true, left sections i.e. 'a','b' and 'c'
                                    -- can't take over the entire statusline even
                                    -- if neither of 'x', 'y' or 'z' are present.
diff --git a/lua/lualine.lua b/lua/lualine.lua
index ba376a7e4..847f8d650 100644
--- a/lua/lualine.lua
+++ b/lua/lualine.lua
@@ -19,6 +19,9 @@ local timers = {
   wb_timer = vim.loop.new_timer(),
 }
 
+local last_focus = {}
+local refresh_real_curwin
+
 -- The events on which lualine redraws itself
 local default_refresh_events = 'WinEnter,BufEnter,SessionLoadPost,FileChangedShellPost,VimResized,Filetype'
 if vim.fn.has('nvim-0.7') == 1 then -- utilize ModeChanged event introduced in 0.7
@@ -187,7 +190,7 @@ end)
 --- check if any extension matches the filetype and return proper sections
 ---@param current_ft string : filetype name of current file
 ---@param is_focused boolean : whether being evaluated for focused window or not
----@return table : (section_table) section config where components are replaced with
+---@return table|nil : (section_table) section config where components are replaced with
 ---      component objects
 -- TODO: change this so it uses a hash table instead of iteration over list
 --       to improve redraws. Add buftype / bufname for extensions
@@ -195,7 +198,11 @@ end)
 local function get_extension_sections(current_ft, is_focused, sec_name)
   for _, extension in ipairs(config.extensions) do
     if vim.tbl_contains(extension.filetypes, current_ft) then
-      return extension[(is_focused and '' or 'inactive_') .. sec_name]
+      if is_focused then
+        return extension[sec_name]
+      else
+        return extension['inactive_' .. sec_name] or extension[sec_name]
+      end
     end
   end
   return nil
@@ -267,7 +274,9 @@ end
 local function status_dispatch(sec_name)
   return function(focused)
     local retval
-    local current_ft = vim.bo.filetype
+    local current_ft = refresh_real_curwin
+        and vim.api.nvim_buf_get_option(vim.api.nvim_win_get_buf(refresh_real_curwin), 'filetype')
+      or vim.bo.filetype
     local is_focused = focused ~= nil and focused or modules.utils.is_focused()
     if
       vim.tbl_contains(
@@ -299,7 +308,7 @@ end
 ---@class LualineRefreshOpts
 ---@field kind LualineRefreshOptsKind
 ---@field place LualineRefreshOptsPlace[]
----@field trigger 'autocmd'|'autocmd_redired|timer'|'unknown'
+---@field trigger 'autocmd'|'autocmd_redired'|'timer'|'unknown'
 --- Refresh contents of lualine
 ---@param opts LualineRefreshOpts
 local function refresh(opts)
@@ -324,7 +333,50 @@ local function refresh(opts)
 
   local wins = {}
   local old_actual_curwin = vim.g.actual_curwin
-  vim.g.actual_curwin = vim.api.nvim_get_current_win()
+
+  -- ignore focus on filetypes listes in options.ignore_focus
+  local curwin = vim.api.nvim_get_current_win()
+  local curtab = vim.api.nvim_get_current_tabpage()
+  if last_focus[curtab] == nil or not vim.api.nvim_win_is_valid(last_focus[curtab]) then
+    if
+      not vim.tbl_contains(
+        config.options.ignore_focus,
+        vim.api.nvim_buf_get_option(vim.api.nvim_win_get_buf(curwin), 'filetype')
+      )
+    then
+      last_focus[curtab] = curwin
+    else
+      local tab_wins = vim.api.nvim_tabpage_list_wins(curtab)
+      if #tab_wins == 1 then
+        last_focus[curtab] = curwin
+      else
+        local focusable_win = curwin
+        for _, win in ipairs(tab_wins) do
+          if
+            not vim.tbl_contains(
+              config.options.ignore_focus,
+              vim.api.nvim_buf_get_option(vim.api.nvim_win_get_buf(win), 'filetype')
+            )
+          then
+            focusable_win = win
+            break
+          end
+        end
+        last_focus[curtab] = focusable_win
+      end
+    end
+  else
+    if
+      not vim.tbl_contains(
+        config.options.ignore_focus,
+        vim.api.nvim_buf_get_option(vim.api.nvim_win_get_buf(curwin), 'filetype')
+      )
+    then
+      last_focus[curtab] = curwin
+    end
+  end
+  vim.g.actual_curwin = last_focus[curtab]
+
   -- gather which windows needs update
   if opts.kind == 'all' then
     if vim.tbl_contains(opts.place, 'statusline') or vim.tbl_contains(opts.place, 'winbar') then
@@ -339,13 +391,14 @@ local function refresh(opts)
       end, vim.api.nvim_tabpage_list_wins(0))
     end
   elseif opts.kind == 'window' then
-    wins = { vim.api.nvim_get_current_win() }
+    wins = { curwin }
   end
 
   -- update them
   if vim.tbl_contains(opts.place, 'statusline') then
     for _, win in ipairs(wins) do
-      local stl_cur = vim.api.nvim_win_call(win, M.statusline)
+      refresh_real_curwin = config.options.globalstatus and last_focus[curtab] or win
+      local stl_cur = vim.api.nvim_win_call(refresh_real_curwin, M.statusline)
       local stl_last = modules.nvim_opts.get_cache('statusline', { window = win })
       if stl_cur or stl_last then
         modules.nvim_opts.set('statusline', stl_cur, { window = win })
@@ -354,8 +407,9 @@ local function refresh(opts)
   end
   if vim.tbl_contains(opts.place, 'winbar') then
     for _, win in ipairs(wins) do
+      refresh_real_curwin = config.options.globalstatus and last_focus[curtab] or win
       if vim.api.nvim_win_get_height(win) > 1 then
-        local wbr_cur = vim.api.nvim_win_call(win, M.winbar)
+        local wbr_cur = vim.api.nvim_win_call(refresh_real_curwin, M.winbar)
         local wbr_last = modules.nvim_opts.get_cache('winbar', { window = win })
         if wbr_cur or wbr_last then
           modules.nvim_opts.set('winbar', wbr_cur, { window = win })
@@ -364,7 +418,8 @@ local function refresh(opts)
     end
   end
   if vim.tbl_contains(opts.place, 'tabline') then
-    local tbl_cur = vim.api.nvim_win_call(vim.api.nvim_get_current_win(), tabline)
+    refresh_real_curwin = curwin
+    local tbl_cur = vim.api.nvim_win_call(curwin, tabline)
     local tbl_last = modules.nvim_opts.get_cache('tabline', { global = true })
     if tbl_cur or tbl_last then
       modules.nvim_opts.set('tabline', tbl_cur, { global = true })
@@ -372,6 +427,7 @@ local function refresh(opts)
   end
 
   vim.g.actual_curwin = old_actual_curwin
+  refresh_real_curwin = nil
 end
 
 --- Sets &tabline option to lualine
diff --git a/lua/lualine/components/location.lua b/lua/lualine/components/location.lua
index 3c467906d..413bf9e1e 100644
--- a/lua/lualine/components/location.lua
+++ b/lua/lualine/components/location.lua
@@ -1,7 +1,9 @@
 -- Copyright (c) 2020-2021 hoob3rt
 -- MIT license, see LICENSE for more details.
 local function location()
-  return '%3l:%-2v'
+  local line = vim.fn.line('.')
+  local col = vim.fn.col('.')
+  return string.format('%3d:%-2d', line, col)
 end
 
 return location
diff --git a/lua/lualine/components/progress.lua b/lua/lualine/components/progress.lua
index 7946a6ce9..5611fbe78 100644
--- a/lua/lualine/components/progress.lua
+++ b/lua/lualine/components/progress.lua
@@ -1,7 +1,15 @@
 -- Copyright (c) 2020-2021 hoob3rt
 -- MIT license, see LICENSE for more details.
 local function progress()
-  return '%3p%%'
+  local cur = vim.fn.line('.')
+  local total = vim.fn.line('$')
+  if cur == 1 then
+    return 'Top'
+  elseif cur == total then
+    return 'Bot'
+  else
+    return math.floor(cur / total * 100) .. '%%'
+  end
 end
 
 return progress
diff --git a/lua/lualine/config.lua b/lua/lualine/config.lua
index dce1070a6..5ee6e042b 100644
--- a/lua/lualine/config.lua
+++ b/lua/lualine/config.lua
@@ -16,6 +16,7 @@ local config = {
       statusline = {},
       winbar = {},
     },
+    ignore_focus = {},
     always_divide_middle = true,
     globalstatus = vim.go.laststatus == 3,
     refresh = {


Test patch:
diff --git a/tests/spec/component_spec.lua b/tests/spec/component_spec.lua
index b21dc5677..4b7d1e9c1 100644
--- a/tests/spec/component_spec.lua
+++ b/tests/spec/component_spec.lua
@@ -400,7 +400,12 @@ describe('Location component', function()
       component_separators = { left = '', right = '' },
       padding = 0,
     }
-    assert_component('location', opts, '%3l:%-2v')
+    assert_component('location', opts, '  1:1 ')
+    vim.cmd('normal! 9o')
+    assert_component('location', opts, ' 10:1 ')
+    vim.api.nvim_win_set_cursor(0, {5, 0})
+    assert_component('location', opts, '  5:1 ')
+    vim.cmd('bdelete!')
   end)
 end)
 
@@ -410,7 +415,12 @@ describe('Progress component', function()
       component_separators = { left = '', right = '' },
       padding = 0,
     }
-    assert_component('progress', opts, '%3p%%')
+    assert_component('progress', opts, 'Top')
+    vim.cmd('normal! 9o')
+    assert_component('progress', opts, 'Bot')
+    vim.api.nvim_win_set_cursor(0, {5, 0})
+    assert_component('progress', opts, '50%%')
+    vim.cmd('bdelete!')
   end)
 end)
 
diff --git a/tests/spec/lualine_spec.lua b/tests/spec/lualine_spec.lua
index f433c7dca..6ba5d5f8f 100644
--- a/tests/spec/lualine_spec.lua
+++ b/tests/spec/lualine_spec.lua
@@ -19,6 +19,7 @@ describe('Lualine', function()
           statusline = {},
           winbar = {},
         },
+        ignore_focus = {},
         always_divide_middle = true,
         globalstatus = false,
         refresh = {
@@ -81,12 +82,12 @@ describe('Lualine', function()
     {3:  master }
     {4:}
     {5: [No Name] }
-    {5:                                                                      }
+    {5:                                                                       }
     {5:  }
     {4:}
-    {3: 100% }
+    {3: Top }
     {2:}
-    {1:   0:1  }|
+    {1:   1:1  }|
     ]===])
   end)
 
@@ -97,7 +98,7 @@ describe('Lualine', function()
     }
     |{1: [No Name] }
     {1:                                                                                                     }
-    {1:   0:1  }|
+    {1:   1:1  }|
     ]===])
   end)
 
@@ -120,12 +121,12 @@ describe('Lualine', function()
     |{1:  master }
     {2:}
     {3: [No Name] }
-    {3:                                                                               }
+    {3:                                                                                }
     {3:  }
     {2:}
-    {1: 100% }
+    {1: Top }
     {4:}
-    {5:   0:1  }|
+    {5:   1:1  }|
     ]===])
   end)
 
@@ -141,10 +142,10 @@ describe('Lualine', function()
     |{1: NORMAL }
     {2:  master }
     {3: [No Name] }
-    {3:                                                                          }
+    {3:                                                                           }
     {3:  }
-    {2: 100% }
-    {1:   0:1  }|
+    {2: Top }
+    {1:   1:1  }|
     ]===])
   end)
 
@@ -171,12 +172,12 @@ describe('Lualine', function()
     {3:  master }
     {4:}
     {5: [No Name] }
-    {5:                                            }
+    {5:                                             }
     {5:  }
     {4:}
-    {3: 100% }
+    {3: Top }
     {2:}
-    {1:   0:1  }
+    {1:   1:1  }
     {1: test_comp2 }|
     ]===])
 
@@ -196,12 +197,12 @@ describe('Lualine', function()
     {3:  master }
     {4:}
     {5: [No Name] }
-    {5:                                              }
+    {5:                                               }
     {5:  }
     {4:}
-    {3: 100% }
+    {3: Top }
     {2:}
-    {1:   0:1  }
+    {1:   1:1  }
     {1: test_comp2 }|
     ]===])
   end)
@@ -241,10 +242,10 @@ describe('Lualine', function()
     |{1: NORMAL }
     {2: master }
     {3: [No Name] }
-    {3:                                                                         }
+    {3:                                                                          }
     {3: unix }
-    {2: 100% }
-    {1:   0:1  }|
+    {2: Top }
+    {1:   1:1  }|
     ]===])
   end)
 
@@ -322,14 +323,13 @@ describe('Lualine', function()
     {3:  master }
     {4:}
     {5: [No Name] }
-    {5:                                                                      }
+    {5:                                                                       }
     {5:  }
     {4:}
-    {3: 100% }
+    {3: Top }
     {2:}
-    {1:   0:1  }|
+    {1:   1:1  }|
     ]===])
-
     vim.bo.ft = 'test_ft2'
     statusline:expect([===[
     highlights = {
@@ -403,12 +403,12 @@ describe('Lualine', function()
       {3:  master }
       {4:}
       {5: [No Name] }
-      {5:                                                                      }
+      {5:                                                                       }
       {5:  }
       {4:}
-      {3: 100% }
+      {3: Top }
       {2:}
-      {1:   0:1  }|
+      {1:   1:1  }|
       ]===])
     end)
     describe('tabs component', function()