Skip to content

Usage_Statusline

Shawon edited this page May 28, 2025 · 3 revisions

🚀 Usage: Statusline

Tip

You can disable this module for a buffer via vim.b[buffer].bars_statusline = false. You can also disable this module for a window via vim.w[buffer].bars_statusline = false.

Usage guide for the Statusline module.

The relevant files are shown below,

📂 bars.nvim
├── 🔐 ///////
├── 📂 lua
│   ├── 📂 bars
│   │   ├── 📂 components
│   │   │   ├── 📄 ////////////////
│   │   │   ├── 📄 statusline.lua      # Components
│   │   │   ├── 📄 ///////////
│   │   │   └── 📄 //////////
│   │   ├── 📄 global.lua              # Click functions
│   │   ├── 📄 ////////////////
│   │   ├── 📄 statusline.lua          # Statusline module
│   │   ├── 📄 ///////////
│   │   ├── 📄 utils.lua               # Utilities
│   │   └── 📄 //////////
│   ├── 📄 ////////
│   └── 📂 definitions
│       ├── 📄 ////////
│       ├── 📄 ////////////////
│       ├── 📄 statusline.lua          # Type definitions
│       ├── 📄 ///////////
│       └── 📄 //////////
├── 📂 plugin
│   └── 📄 ////////
└── 📄 /////////

🧭 Configuration

This module can be configured via the statuscolumn option in require("bars").setup() or via require("bars.statuscolumn").setup() directly.

Default configuration is given below,

See type definition
--- Statusline configuration table.
---@class statusline.config
---
--- Filetypes to ignore.
---@field ignore_filetypes? string[]
--- Buftypes to ignore.
---@field ignore_buftypes? string[]
---
--- Additional condition for attaching to new windows.
---@field condition? fun(buffer: integer, window: integer): boolean | nil
---
--- Default style.
---@field default statusline_style
---
--- Custom style.
---@field [string] statusline_style


---@alias statusline_style
---| statusline.components.section
---| statusline.components.ruler
---| statusline.components.mode
---| statusline.components.diagnostics
---| statusline.components.branch
---| statusline.components.bufname
---| statusline.components.custom
---@type statusline.config
statusline.config = {
    ignore_filetypes = {},
    ignore_buftypes = {},

    default = {
        ---|fS "Default configuration"

        components = {
            {
                kind = "mode",

                compact = function (_, window)
                    if window ~= vim.api.nvim_get_current_win() then
                        return true;
                    else
                        return vim.api.nvim_win_get_width(window) < math.ceil(vim.o.columns * 0.5);
                    end
                end,

                ---|fS "Mode configuration"

                default = {
                    padding_left = " ",
                    padding_right = " ",

                    icon = "",

                    hl = "Color8R",
                },

                ["^n"] = { text = "Normal" },

                ["^t"] = { text = "Terminal" },

                ["^v$"] = {
                    icon = "󰸿 ",
                    text = "Visual",

                    hl = "Color9R",
                },
                ["^V$"]    = {
                    icon = "󰹀 ",
                    text = "Visual",

                    hl = "Color7R",
                },
                ["^$"]   = {
                    icon = "󰸽 ",
                    text = "Visual",

                    hl = "Color2R",
                },

                ["^s$"]    = {
                    icon = "󰕠 ",
                    text = "Select",

                    hl = "Color9R",
                },
                ["^S$"]    = {
                    icon = "󰕞 ",
                    text = "Select",

                    hl = "Color7R",
                },
                ["^$"]   = {
                    icon = "",
                    text = "Select",

                    hl = "Color2R",
                },

                ["^i$"]    = {
                    icon = "",
                    text = "Insert",

                    hl = "Color10R",
                },
                ["^ic$"]   = {
                    icon = "",
                    text = "Completion",

                    hl = "Color10R",
                },
                ["^ix$"]   = {
                    text = "Inser8",

                    hl = "Color10R",
                },

                ["^R$"]    = {
                    icon = "",
                    text = "Replace",

                    hl = "Color8R",
                },
                ["^Rc$"]   = {
                    icon = "",
                    text = "Completion",

                    hl = "Color8R",
                },

                ["^c"]    = {
                    icon = "",
                    text = "Command",

                    hl = "Color4R",
                },

                ["^r"] = { text = "Prompt" },

                ["^%!"] = {
                    icon = "",
                    text = "Shell",

                    hl = "Color4R"
                },

                ---|fE
            },
            { kind = "section", hl = "Normal" },
            {
                kind = "bufname",
                condition = function (_, win)
                    return vim.api.nvim_win_get_width(win) >= 42;
                end,

                max_len = 25,

                default = {
                    padding_left = " ",
                    padding_right = " ",

                    icon = "",
                    nomodifiable_icon_hl = "Color1B",
                    nomodifiable_icon = "󰌾 ",
                    icon_hl = {
                        "Color0B",
                        "Color1B", "Color2B", "Color3B",
                        "Color4B", "Color5B", "Color6B",
                    },

                    -- corner_left_hl = "Normal",
                    -- corner_right_hl = "Normal",
                    hl = "Layer1"
                },

                ["^$"] = {
                    icon = "󰂵 ",
                    text = "New file",

                    hl = "Layer0"
                },

                ["^fish"] = {
                    icon = "󰐂 ",
                },
            },
            { kind = "section", hl = "Normal" },
            {
                kind = "diagnostics",
                default_mode = 5,

                padding_left = " ",
                padding_right = " ",

                empty_icon = "󰂓 ",
                empty_hl = "Comment",

                error_icon = "󰅙 ",
                error_hl = "DiagnosticError",

                warn_icon = "󰀦 ",
                warn_hl = "DiagnosticWarn",

                hint_icon = "󰁨 ",
                hint_hl = "DiagnosticHint",

                info_icon = "󰁤 ",
                info_hl = "DiagnosticInfo"
            },
            { kind = "empty", hl = "Normal" },
            {
                kind = "branch",
                condition = function (_, win)
                    return win == vim.api.nvim_get_current_win();
                end,

                default = {
                    padding_left = " ",
                    padding_right = " ",
                    icon = "󰊢 ",

                    hl = "Color0"
                }
            },
            {
                kind = "ruler",
                mode = function ()
                    local mode = vim.api.nvim_get_mode().mode;
                    local visual_modes = { "v", "V", "" };

                    return vim.list_contains(visual_modes, mode) and "visual" or "normal";
                end,

                default = {
                    padding_left = " ",
                    padding_right = " ",
                    icon = "",

                    separator = "",

                    hl = "Color1R"
                },

                visual = {
                    icon = "",

                    hl = "Color6R"
                }
            }
        }

        ---|fE
    },
    ["help"] = {
        ---|fS "Help statusline"

        condition = function (buffer)
            return vim.bo[buffer].buftype == "help";
        end,
        components = {
            { kind = "empty", hl = "Normal" },
            {
                kind = "mode",

                ---|fS "Mode configuration"

                default = {
                    padding_left = " ",
                    padding_right = " ",

                    icon = "",

                    hl = "Color8R",
                },

                ["^n"] = { text = "Normal" },

                ["^t"] = { text = "Terminal" },

                ["^v$"] = {
                    icon = "󰸿 ",
                    text = "Visual",

                    hl = "Color9R",
                },
                ["^V$"]    = {
                    icon = "󰹀 ",
                    text = "Visual",

                    hl = "Color7R",
                },
                ["^$"]   = {
                    icon = "󰸽 ",
                    text = "Visual",

                    hl = "Color2R",
                },

                ["^s$"]    = {
                    icon = "󰕠 ",
                    text = "Select",

                    hl = "Color9R",
                },
                ["^S$"]    = {
                    icon = "󰕞 ",
                    text = "Select",

                    hl = "Color4R",
                },
                ["^$"]   = {
                    icon = "",
                    text = "Select",

                    hl = "Color9R",
                },

                ["^i$"]    = {
                    icon = "",
                    text = "Insert",

                    hl = "Color10R",
                },
                ["^ic$"]   = {
                    icon = "",
                    text = "Completion",

                    hl = "Color10R",
                },
                ["^ix$"]   = {
                    text = "Inser8",

                    hl = "Color10R",
                },

                ["^R$"]    = {
                    icon = "",
                    text = "Replace",

                    hl = "Color8R",
                },
                ["^Rc$"]   = {
                    icon = "",
                    text = "Completion",

                    hl = "Color8R",
                },

                ["^c"]    = {
                    icon = "",
                    text = "Command",

                    hl = "Color4R",
                },

                ["^r"] = { text = "Prompt" },

                ["^%!"] = {
                    icon = "",
                    text = "Shell",

                    hl = "Color4R"
                },

                ---|fE
            },
            {
                kind = "ruler",
                condition = function ()
                    local mode = vim.api.nvim_get_mode().mode;
                    local visual_modes = { "v", "V", "" };

                    return vim.list_contains(visual_modes, mode);
                end,

                default = {
                    padding_left = " ",
                    padding_right = " ",
                    icon = "",

                    separator = "",

                    hl = "Color6R"
                },

                visual = {
                    icon = "",

                    hl = "Color6R"
                }
            },
            {
                kind = "bufname",
                condition = function (_, win)
                    return vim.api.nvim_win_get_width(win) >= 42;
                end,

                default = {
                    padding_left = " ",
                    padding_right = " ",

                    icon = "",
                    nomodifiable_icon_hl = "Color1B",
                    nomodifiable_icon = "󰌾 ",
                    icon_hl = {
                        "Color0B",
                        "Color1B", "Color2B", "Color3B",
                        "Color4B", "Color5B", "Color6B",
                    },

                    -- corner_left_hl = "Normal",
                    -- corner_right_hl = "Normal",
                    hl = "Layer1"
                },

                ["^$"] = {
                    icon = "󰂵 ",
                    text = "New file",

                    hl = "Layer0"
                },

                ["^fish"] = {
                    icon = "󰐂 ",
            },
            },
            { kind = "empty", hl = "Normal" },
        }

        ---|fE
    }
};

🧩 Components

bars.nvim comes with the following components by default,

💡 Git branch(branch)

Shows the current git branch.

See type definition
--- Shows current git branch.
---@class statusline.components.branch
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "branch"
---
--- Delay(in milliseconds) between branch
--- name updates.
---@field throttle? integer
---
--- Default configuration for git branch.
---@field default branch.opts
---
--- Configuration for branches whose name
--- matches `string`.
---@field [string] branch.opts


--- Git branch component options.
--- Drawn like so,
---
--- abc----de
--- │││    │└ corner_right
--- │││    └ padding_right
--- ││└ icon
--- │└ padding_left
--- └ corner_left
---
---@class branch.opts
---
---@field corner_left? string
---@field padding_left? string
---
--- Alternate branch name.
---@field text? string
---@field icon? string
---
---@field padding_right? string
---@field corner_right? string
---
--- Primary highlight group.
---@field hl? string
---
---@field corner_left_hl? string
---@field padding_left_hl? string
---
---@field icon_hl? string
---
---@field padding_right_hl? string
---@field corner_right_hl? string
{
    kind = "branch",
    condition = function (_, win)
        return win == vim.api.nvim_get_current_win();
    end,

    default = {
        padding_left = " ",
        padding_right = " ",
        icon = "󰊢 ",

        hl = "Color0"
    }
},

💡 Buffer name(bufname)

Shows the buffer's name.

See type definition
--- Shows buffer name.
---@class statusline.components.bufname
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "bufname"
---
--- Maximum name length.
---@field max_len? integer
---
--- Symbol used to show truncation.
---@field truncate_symbol? string
---
---@field default bufname.opts
---@field [string] bufname.opts


--- Buffer name component options.
--- Drawn like so,
---
--- abc----de
--- │││    │└ corner_right
--- │││    └ padding_right
--- ││└ icon / nomodifiable_icon
--- │└ padding_left
--- └ corner_left
---
---@class bufname.opts
---
---@field corner_left? string
---@field padding_left? string
---
--- Alternate branch name.
---@field text? string
---@field icon? string
---
--- Icon for 'nomodifiable' buffers.
---@field nomodifiable_icon? string
---
---@field padding_right? string
---@field corner_right? string
---
--- Primary highlight group.
---@field hl? string
---
---@field corner_left_hl? string
---@field padding_left_hl? string
---
---@field icon_hl? string
---
--- Highlight group for `nomodifiable_icon`
---@field nomodifiable_icon_hl? string
---
---@field padding_right_hl? string
---@field corner_right_hl? string
{
    kind = "bufname",
    condition = function (_, win)
        return vim.api.nvim_win_get_width(win) >= 42;
    end,

    default = {
        padding_left = " ",
        padding_right = " ",

        icon = "",
        nomodifiable_icon_hl = "Color1B",
        nomodifiable_icon = "󰌾 ",
        icon_hl = {
            "Color0B",
            "Color1B", "Color2B", "Color3B",
            "Color4B", "Color5B", "Color6B",
        },

        hl = "Layer1"
    },

    ["^$"] = {
        icon = "󰂵 ",
        text = "New file",

        hl = "Layer0"
    },

    ["^fish"] = {
        icon = "󰐂 ",
    },
},

💡 Diagnostics

Shows the diagnostic count for different alert level(s).

Tip

This has mouse click support.

global.__change_diagnostic_state() is used for going to line.

See type definition
--- Shows diagnostics count.
---@class statusline.components.diagnostics
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "diagnostics"
---
--- Should this component be automatically hidden?
---
--- > This component gets hidden if a buffer has
--- > no client attached to it.
---@field auto_hide? boolean
---
--- Determines what type of diagnostics are
--- shown.
---@field default_mode?
---| 1 Error
---| 2 Warning
---| 3 Info
---| 4 Hint
---| 5 All of the above
---
---@field error_icon? string
---@field error_hl? string
---
---@field warn_icon? string
---@field warn_hl? string
---
---@field info_icon? string
---@field info_hl? string
---
---@field hint_icon? string
---@field hint_hl? string
---
--- Icon to show when no diagnostics are available.
---@field empty_icon? string
---
--- Text to show when no diagnostics are available.
---@field empty_text? string
---
--- Highlight group to use when no diagnostics are
--- available.
---@field empty_hl? string
---
--- Text used as separator between each diagnostics
--- type.
---@field separator? string
---
--- Highlight group for the separator.
---@field separator_hl? string
---
--- Left corner of the component. 
---@field corner_left? string
---@field corner_left_hl? string
---
--- Left padding of the component. 
---@field padding_left? string
---@field padding_left_hl? string
---
--- Right padding of the component. 
---@field padding_right? string
---@field padding_right_hl? string
---
--- Right corner of the component. 
---@field corner_right? string
---@field corner_right_hl? string
---
--- Primary highlight group for the component
---@field hl? string
{
    kind = "diagnostics",
    default_mode = 5,

    padding_left = " ",
    padding_right = " ",

    empty_icon = "󰂓 ",
    empty_hl = "Comment",

    error_icon = "󰅙 ",
    error_hl = "DiagnosticError",

    warn_icon = "󰀦 ",
    warn_hl = "DiagnosticWarn",

    hint_icon = "󰁨 ",
    hint_hl = "DiagnosticHint",

    info_icon = "󰁤 ",
    info_hl = "DiagnosticInfo"
},

💡 Empty

Empty space between other section.

See type definition
--- Empty space.
---@class statusline.components.empty
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "empty"
---
--- Highlight group for this component.
---@field hl? string
{
    kind = "empty",
    hl = "Normal"
},

💡 Mode

Shows current mode.

See type definition
--- Shows current mode.
---@class statusline.components.mode
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "mode"
---
--- Should we show a compact version?
---@field compact? boolean | fun(buffer: integer, window: integer): boolean
---
---@field default mode.opts
---@field [string] mode.opts


--- Mode name component options.
--- Drawn like so,
---
--- abc----de
--- │││    │└ corner_right
--- │││    └ padding_right
--- ││└ icon
--- │└ padding_left
--- └ corner_left
---
---@class mode.opts
---
---@field corner_left? string
---@field padding_left? string
---
--- Mode name.
---@field text? string
---@field icon? string
---
---@field padding_right? string
---@field corner_right? string
---
--- Primary highlight group.
---@field hl? string
---
---@field corner_left_hl? string
---@field padding_left_hl? string
---
---@field icon_hl? string
---
---@field padding_right_hl? string
---@field corner_right_hl? string
{
    kind = "mode",

    ---|fS "Mode configuration"

    default = {
        padding_left = " ",
        padding_right = " ",

        icon = "",

        hl = "Color8R",
    },

    ["^n"] = { text = "Normal" },

    ["^t"] = { text = "Terminal" },

    ["^v$"] = {
        icon = "󰸿 ",
        text = "Visual",

        hl = "Color9R",
    },
    ["^V$"]    = {
        icon = "󰹀 ",
        text = "Visual",

        hl = "Color7R",
    },
    ["^$"]   = {
        icon = "󰸽 ",
        text = "Visual",

        hl = "Color2R",
    },

    ["^s$"]    = {
        icon = "󰕠 ",
        text = "Select",

        hl = "Color9R",
    },
    ["^S$"]    = {
        icon = "󰕞 ",
        text = "Select",

        hl = "Color4R",
    },
    ["^$"]   = {
        icon = "",
        text = "Select",

        hl = "Color9R",
    },

    ["^i$"]    = {
        icon = "",
        text = "Insert",

        hl = "Color10R",
    },
    ["^ic$"]   = {
        icon = "",
        text = "Completion",

        hl = "Color10R",
    },
    ["^ix$"]   = {
        text = "Inser8",

        hl = "Color10R",
    },

    ["^R$"]    = {
        icon = "",
        text = "Replace",

        hl = "Color8R",
    },
    ["^Rc$"]   = {
        icon = "",
        text = "Completion",

        hl = "Color8R",
    },

    ["^c"]    = {
        icon = "",
        text = "Command",

        hl = "Color4R",
    },

    ["^r"] = { text = "Prompt" },

    ["^%!"] = {
        icon = "",
        text = "Shell",

        hl = "Color4R"
    },

    ---|fE
},

💡 Section

Custom section(a structured version of the custom component).

See type definition
--- Custom section for the statusline.
--- Drawn like so,
---
--- abc-de
--- │││││└ corner_right
--- ││││└ padding_right
--- │││└ text
--- ││└ icon
--- │└ padding_left
--- └ corner_left
---@class statusline.components.section
---
--- Condition for this component.
---@field condition? fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind? "section"
---
--- Reference to a click handler.
---@field click? string
---
---@field corner_left? string
---@field padding_left? string
---@field icon? string
---
---@field text? string
---
---@field padding_right? string
---@field corner_right? string
---
--- Primary highlight group
---@field hl? string
---
---@field corner_left_hl? string
---@field padding_left_hl? string
---@field icon_hl? string
---
---@field text_hl? string
---
---@field padding_right_hl? string
---@field corner_right_hl? string
{
    kind = "section",
    hl = "Normal"
},

💡 Ruler

Custom ruler.

See type definition
--- Custom ruler.
---@class statusline.components.ruler
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "ruler"
---
--- Should visual modes be shown
---@field mode
---| "normal" Show cursor position.
---| "visual" Show selection size.
---| fun(buffer: integer, window: integer): ( "normal" | "visual" )
---
--- Default configuration.
---@field default ruler.opts
---
--- Configuration for visual modes.
---@field visual ruler.opts


--- Ruler component options.
--- Drawn like so,
---
---```txt
--- abcXX-YYde
--- │││  │  │└ corner_right
--- │││  │  └ padding_right
--- │││  └ separator
--- ││└ icon
--- │└ padding_left
--- └ corner_left
---@class ruler.opts
---
---@field corner_left? string
---@field padding_left? string
---
---@field icon? string
---
--- Separator between texts.
---@field separator? string
---
---@field padding_right? string
---@field corner_right? string
---
---
---@field corner_left_hl? string
---@field padding_left_hl? string
---
---@field icon_hl? string
---@field separator_hl? string
---
---@field padding_right_hl? string
---@field corner_right_hl? string
---
--- Primary highlight group.
---@field hl? string
{
    kind = "ruler",
    condition = function ()
        local mode = vim.api.nvim_get_mode().mode;
        local visual_modes = { "v", "V", "" };

        return vim.list_contains(visual_modes, mode);
    end,

    default = {
        padding_left = " ",
        padding_right = " ",
        icon = "",

        separator = "",

        hl = "Color6R"
    },

    visual = {
        icon = "",

        hl = "Color6R"
    }
},

💡 Progress

Allows showing progress bars/spinners.

See type definition
---@class statusline.components.progress
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "progress"
---
---@field check? string The variable that holds the progress state, default is "progress_state".
---
---@field finish string Text used as the indicator for progress finish.
---@field finish_hl string Highlight group for the progress finish indicator.
---
---@field progress string[] Text used as the indicator for progress.
---@field progress_hl string[] Highlight group for the progress indicator.
---
---@field start string Text used as the indicator for progress start.
---@field start_hl string Highlight group for the progress start indicator.
---
---@field update_delay? integer Delay in milliseconds between state updates.

Note

The following example by itself doesn't do anything!

{
    kind = "progress",

    check = "lsp_loader_state",
    update_delay = 250,

    start = " ",
    progress = { "|", "/", "-", "\\" },
    finish = "",

    start_hl = "@comment",
    progress_hl = "@comment",
    finish_hl = "DiagnosticOk"
}

To get it to indicate LspProgress you can use this autocmd,

vim.api.nvim_create_autocmd("LspProgress", {
    callback = function (event)
        local kind = event.data.params.value.kind;
        local attached = vim.lsp.get_buffers_by_client_id(event.data.client_id);

        --- Sets buffer state
        ---@param state "start" | "progress" | "finish" | nil
        local function set_state (state)
            for _, buf in ipairs(attached) do
                vim.b[buf].lsp_loader_state = state;
            end
        end

        --- Gets the general state.
        ---@return "start" | "progress" | "finish" | nil
        local function get_state ()
            local states = {};

            for _, buf in ipairs(attached) do
                table.insert(states, vim.b[buf].lsp_loader_state);
            end

            local state = states[1];

            for _, item in ipairs(states) do
                if item ~= state then
                    return nil;
                end
            end

            return state;
        end

        if kind == "begin" then
            set_state("start");

            local lsp_timer = vim.uv.new_timer();

            lsp_timer:start(0, 200, vim.schedule_wrap(function ()
                if get_state() == nil then
                    timer:stop();
                    return;
                end

                vim.api.nvim__redraw({ statusline = true });
            end));

            vim.api.nvim__redraw({ statusline = true });
        elseif kind == "report" then
            set_state("progress");
        else
            set_state("finish");

            -- We defer this so that we can see the finish
            -- indicator.
            vim.defer_fn(function ()
                if get_state() == "finish" then
                    set_state(nil);
                end

                vim.api.nvim__redraw({ statusline = true });
            end, 500);
        end
    end
});

💡 Custom

Custom component.

See type definition
--- Custom statusline component.
---@class statusline.components.custom
---
--- Optional condition for this component.
---@field condition? boolean | fun(buffer: integer, window: integer): boolean
---
--- What kind of component is this?
---@field kind "ruler"
---
--- Text to show for this component.
---@field value fun(buffer: integer, window: integer): string
{
    kind = "ruler",

    value = "Hello, Neovim!"
}

Also in vimdoc, :h bars-statusline.

Clone this wiki locally