Skip to content

Commit

Permalink
fix: make statusline update in all windows (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
famiu authored Sep 11, 2021
1 parent 9c6ada0 commit a870c07
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 67 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ components.active[3][2] = {

**NOTE:** If you use the index instead of table.insert, remember to put the correct index. Also keep in mind that unlike most other programming languages, Lua indices start at `1` instead of `0`.

Now you can customize each component to your liking. Most values that a component requires can also use a function without arguments, with the exception of the `provider` value, which can take one argument, more about that below. Feline will automatically evaluate the function if it is given a function. But in case a function is provided, the type of value the function returns must be the same as the type of value required by the component. For example, since `enabled` requires a boolean value, if you set it to a function, the function must also return a boolean value. Note that you can omit all of the component values except `provider`, in which case the defaults would be used instead. A component can have the following values:
Now you can customize each component to your liking. Most values that a component requires can also use a function without arguments, with the exception of the `provider` value, which can take arguments (more about that below). Feline will automatically evaluate the function if it is given a function. But in case a function is provided, the type of value the function returns must be the same as the type of value required by the component. For example, since `enabled` requires a boolean value, if you set it to a function, the function must also return a boolean value. Note that you can omit all of the component values except `provider`, in which case the defaults would be used instead. A component can have the following values:

- `provider` (string or function): If it's a string, it represents the text to show. If it's a function, it must return a string when called. As a function it may also optionally return an `icon` component alongside the string when called, which would represent the provider's icon, possibly along with the icon highlight group configuration. The function can take either no arguments, or one argument which would contain the component itself.
- `provider` (string or function): If it's a string, it represents the text to show. If it's a function, it must return a string when called. As a function it may also optionally return an `icon` component alongside the string when called, which would represent the provider's icon, possibly along with the icon highlight group configuration. The function can take either no arguments, or one argument which would contain the component itself, or it can take two arguments, the component and the window handler of the window for which the statusline is being generated.

```lua
-- Provider that shows current line in file
Expand All @@ -238,7 +238,17 @@ provider = function(component)
end
end

-- Providers can also just contain a simple string, such as:
-- Providers can also take the window handler as an argument
provider = function(component, winid)
return (component.icon or '') .. tostring(vim.api.nvim_win_get_buf(winid))
end

-- If you only need the window handler, you can avoid using the component value like this:
provider = function(_, winid)
return vim.api.nvim_win_get_cursor(winid)[1]
end

-- Providers can also simply just contain a string, such as:
provider = 'some text here'
```

Expand Down Expand Up @@ -542,6 +552,8 @@ Now that we've learned to set up both the components table and the properties ta
- `preset` - Set it to use a preconfigured statusline. Currently it can be equal to either `default` for the default statusline or `noicon` for the default statusline without icons. You don't have to put any of the other values if you use a preset, but if you do, your settings will override the preset's settings. To see more info such as how to modify a preset to build a statusline, see: [Modifying an existing preset](#3.-modifying-an-existing-preset)
- `colors` - A table containing custom [color value presets](#value-presets).
- `separators` - A table containing custom [separator value presets](#value-presets).
- `update_triggers` - A list of autocmds that trigger an update of the statusline in inactive windows.<br>
Default: `{'VimEnter', 'WinEnter', 'WinClosed', 'FileChangedShellPost'}`
- `components` - The components table.
- `properties` - The properties table.
- `vi_mode_colors` - A table containing colors associated with Vi modes. It can later be used to get the color associated with the current Vim mode using `require('feline.providers.vi_mode').get_mode_color()`. For more info on it see the [Vi-mode](#vi-mode) section.<br><br>Here is a list of all possible vi_mode names used with the default color associated with them:
Expand Down
7 changes: 7 additions & 0 deletions lua/feline/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,11 @@ M.vi_mode_colors = {
['NONE'] = 'yellow'
}

M.update_triggers = {
'VimEnter',
'WinEnter',
'WinClosed',
'FileChangedShellPost'
}

return M
31 changes: 15 additions & 16 deletions lua/feline/generator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,12 @@ local function parse_icon(icon, parent_hl)
end

-- Parse component provider
local function parse_provider(provider, component)
local function parse_provider(provider, component, winid)
local icon
if type(provider) == "string" and type(providers[provider]) == "function" then
provider, icon = providers[provider](component)
provider, icon = providers[provider](component, winid)
elseif type(provider) == "function" then
provider, icon = provider(component)
provider, icon = provider(component, winid)
end

if type(provider) ~= "string" then
Expand All @@ -158,18 +158,17 @@ local function parse_provider(provider, component)
end

-- Parses a component alongside its highlight
local function parse_component(component)
local function parse_component(component, winid)
local enabled = evaluate_if_function(component.enabled, true)

if not enabled then return '' end


local hl = evaluate_if_function(component.hl, {})

local left_sep_str = parse_sep_list(component.left_sep, hl.bg)
local right_sep_str = parse_sep_list(component.right_sep, hl.bg)

local str, icon = parse_provider(component.provider, component)
local str, icon = parse_provider(component.provider, component, winid)

local hlname = parse_hl(hl)

Expand All @@ -184,12 +183,12 @@ end

-- Parse components of a section of the statusline
-- (For old component table format)
local function parse_statusline_section_old(section, type)
local function parse_statusline_section_old(section, type, winid)
if feline.components[section] and feline.components[section][type] then
local section_components = {}

for _, v in ipairs(feline.components[section][type]) do
section_components[#section_components+1] = parse_component(v)
section_components[#section_components+1] = parse_component(v, winid)
end

return table.concat(section_components)
Expand All @@ -199,25 +198,25 @@ local function parse_statusline_section_old(section, type)
end

-- Parse components of a section of the statusline
local function parse_statusline_section(section)
local function parse_statusline_section(section, winid)
local components = {}

for _, component in ipairs(section) do
components[#components+1] = parse_component(component)
components[#components+1] = parse_component(component, winid)
end

return table.concat(components)
end

-- Generate statusline by parsing all components and return a string
function M.generate_statusline(is_active)
function M.generate_statusline(winid)
if not feline.components then
return ''
end

local statusline_type

if is_active and not is_forced_inactive() then
if winid == vim.api.nvim_get_current_win() and not is_forced_inactive() then
statusline_type='active'
else
statusline_type='inactive'
Expand All @@ -229,16 +228,16 @@ function M.generate_statusline(is_active)
local sections = {}

for _, section in ipairs(feline.components[statusline_type]) do
sections[#sections+1] = parse_statusline_section(section)
sections[#sections+1] = parse_statusline_section(section, winid)
end

return table.concat(sections, '%=')
else
return string.format(
"%s%%=%s%%=%s",
parse_statusline_section_old('left', statusline_type),
parse_statusline_section_old('mid', statusline_type),
parse_statusline_section_old('right', statusline_type)
parse_statusline_section_old('left', statusline_type, winid),
parse_statusline_section_old('mid', statusline_type, winid),
parse_statusline_section_old('right', statusline_type, winid)
)
end
end
Expand Down
41 changes: 35 additions & 6 deletions lua/feline/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ local function create_augroup(autocmds, name)
cmd('augroup END')
end

-- Update statusline of inactive windows on the current tabpage
function M.update_inactive_windows()
-- Uses vim.schedule to defer executing the function until after
-- all other autocommands have run. This will ensure that inactive windows
-- are updated after any changes.
vim.schedule(function()
local current_win = api.nvim_get_current_win()

for _, winid in ipairs(api.nvim_tabpage_list_wins(0)) do
if api.nvim_win_get_config(winid).relative == '' and winid ~= current_win
then
vim.wo[winid].statusline = M.statusline(winid)
end
end

-- Reset local statusline of current window to use the global statusline for it
vim.wo.statusline = nil
end)
end

function M.setup(config)
-- Check if Neovim version is 0.5 or greater
if fn.has('nvim-0.5') ~= 1 then
Expand All @@ -60,7 +80,8 @@ function M.setup(config)
local config_opts = {
'colors',
'separators',
'vi_mode_colors'
'vi_mode_colors',
'update_triggers'
}

-- Parse the opts in config_opts by getting the default values and
Expand Down Expand Up @@ -128,14 +149,22 @@ function M.setup(config)
vim.o.statusline = '%!v:lua.require\'feline\'.statusline()'

create_augroup({
{'WinEnter,BufEnter', '*', 'set statusline<'},
{'WinLeave,BufLeave', '*', 'lua vim.wo.statusline=require\'feline\'.statusline()'},
{'ColorScheme', '*', 'lua require\'feline\'.reset_highlights()'}
{
table.concat(M.update_triggers, ','),
'*',
'lua require("feline").update_inactive_windows()'
},
{
'SessionLoadPost,ColorScheme',
'*',
'lua require("feline").reset_highlights()'
}
}, 'feline')
end

function M.statusline()
return require('feline.generator').generate_statusline(g.statusline_winid == fn.win_getid())
function M.statusline(winid)
winid = winid or vim.api.nvim_get_current_win()
return require('feline.generator').generate_statusline(winid)
end

return M
14 changes: 7 additions & 7 deletions lua/feline/providers/cursor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ function M.position()
return "%3l:%-2c"
end

function M.line_percentage()
local curr_line = api.nvim_win_get_cursor(0)[1]
local lines = api.nvim_buf_line_count(0)
function M.line_percentage(_, winid)
local curr_line = api.nvim_win_get_cursor(winid)[1]
local lines = api.nvim_buf_line_count(api.nvim_win_get_buf(winid))

if curr_line == 1 then
return "Top"
elseif curr_line == lines then
return "Bot"
else
return "%2p%%"
return string.format('%2d%%%%', math.ceil(curr_line / lines * 99))
end
end

function M.scroll_bar()
function M.scroll_bar(_, winid)
local blocks = {'', '', '', '', '', '', '', ''}
local width = 2

local curr_line = api.nvim_win_get_cursor(0)[1]
local lines = api.nvim_buf_line_count(0)
local curr_line = api.nvim_win_get_cursor(winid)[1]
local lines = api.nvim_buf_line_count(api.nvim_win_get_buf(winid))

local index = math.floor(curr_line / lines * (#blocks - 1)) + 1

Expand Down
19 changes: 11 additions & 8 deletions lua/feline/providers/file.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ local function get_unique_filename(filename, shorten)
return string.reverse(string.sub(filename, 1, index))
end

function M.file_info(component)
local filename = api.nvim_buf_get_name(0)
function M.file_info(component, winid)
local filename = api.nvim_buf_get_name(api.nvim_win_get_buf(winid))

component.type = component.type or 'base-only'

Expand Down Expand Up @@ -121,13 +121,15 @@ function M.file_info(component)

if filename == '' then filename = 'unnamed' end

if bo.readonly then
local bufnr = api.nvim_win_get_buf(winid)

if bo[bufnr].readonly then
readonly_str = component.file_readonly_icon or '🔒'
else
readonly_str = ''
end

if bo.modified then
if bo[bufnr].modified then
modified_str = (component.file_modified_icon or '') .. ' '
else
modified_str = ''
Expand All @@ -150,12 +152,13 @@ function M.file_size()
return string.format(index == 1 and '%g' or '%.2f', fsize) .. suffix[index]
end

function M.file_type()
return bo.filetype:upper()
function M.file_type(_, winid)
return bo[api.nvim_win_get_buf(winid)].filetype:upper()
end

function M.file_encoding()
local enc = (bo.fenc ~= '' and bo.fenc) or vim.o.enc
function M.file_encoding(_, winid)
local bufnr = api.nvim_win_get_buf(winid)
local enc = (bo[bufnr].fenc ~= '' and bo[bufnr].fenc) or vim.o.enc
return enc:upper()
end

Expand Down
42 changes: 31 additions & 11 deletions lua/feline/providers/git.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
local api = vim.api

local M = {}

function M.git_branch(component)
function M.git_branch(component, winid)
local icon
local str = ''
local head = vim.b.gitsigns_head or vim.g.gitsigns_head or ''
local ok, head = pcall(
api.nvim_buf_get_var,
api.nvim_win_get_buf(winid),
'gitsigns_head'
)

if not ok then head = vim.g.gitsigns_head or '' end

if head ~= '' then
icon = component.icon or ''
Expand All @@ -13,41 +21,53 @@ function M.git_branch(component)
return str, icon
end

function M.git_diff_added(component)
local gsd = vim.b.gitsigns_status_dict
function M.git_diff_added(component, winid)
local ok, gsd = pcall(
api.nvim_buf_get_var,
api.nvim_win_get_buf(winid),
'gitsigns_status_dict'
)

local icon
local str = ''

if gsd and gsd['added'] and gsd['added'] > 0 then
if ok and gsd['added'] and gsd['added'] > 0 then
icon = component.icon or ''
str = str .. gsd.added
end

return str, icon
end

function M.git_diff_removed(component)
local gsd = vim.b.gitsigns_status_dict
function M.git_diff_removed(component, winid)
local ok, gsd = pcall(
api.nvim_buf_get_var,
api.nvim_win_get_buf(winid),
'gitsigns_status_dict'
)

local icon
local str = ''

if gsd and gsd['removed'] and gsd['removed'] > 0 then
if ok and gsd['removed'] and gsd['removed'] > 0 then
icon = component.icon or ''
str = str .. gsd.removed
end

return str, icon
end

function M.git_diff_changed(component)
local gsd = vim.b.gitsigns_status_dict
function M.git_diff_changed(component, winid)
local ok, gsd = pcall(
api.nvim_buf_get_var,
api.nvim_win_get_buf(winid),
'gitsigns_status_dict'
)

local icon
local str = ''

if gsd and gsd['changed'] and gsd['changed'] > 0 then
if ok and gsd['changed'] and gsd['changed'] > 0 then
icon = component.icon or ''
str = str .. gsd.changed
end
Expand Down
Loading

0 comments on commit a870c07

Please sign in to comment.