Skip to content

Usage_Statuscolumn

Shawon edited this page May 3, 2025 · 2 revisions

🚀 Usage: Statuscolumn

Tip

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

Usage guide for the statuscolumn module.

The relevant files are shown below,

📂 bars.nvim
├── 🔐 ///////
├── 📂 lua
│   ├── 📂 bars
│   │   ├── 📂 components
│   │   │   ├── 📄 statuscolumn.lua    # Components
│   │   │   ├── 📄 //////////////
│   │   │   ├── 📄 ///////////
│   │   │   └── 📄 //////////
│   │   ├── 📄 global.lua              # Click functions
│   │   ├── 📄 statuscolumn.lua        # Statuscolumn module
│   │   ├── 📄 //////////////
│   │   ├── 📄 ///////////
│   │   ├── 📄 utils.lua               # Utilities
│   │   └── 📄 //////////
│   ├── 📄 ////////
│   └── 📂 definitions
│       ├── 📄 ////////
│       ├── 📄 statuscolumn.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
--- Configuration table for the statuscolumn.
---@class statuscolumn.config
---
--- Filetypes to ignore.
---@field ignore_filetypes string[]
--- Buftypes to ignore.
---@field ignore_buftypes string[]
---
--- Additional condition for attaching to
--- windows.
---@field condition? fun(buffer: integer, window: integer): boolean | nil
---
--- Default style.
---@field default statuscolumn.style
---
--- Configuration style.
---@field [string] statuscolumn.style


--- A configuration style.
--- Must have a condition(unless `default`)
--- and a list of components.
---@class statuscolumn.style
---
--- Condition for this style.
---@field condition? fun(buffer: integer, window: integer): boolean
---
--- Parts for this style.
---@field components statuscolumn_component[]


---@alias statuscolumn_component
---| statuscolumn.components.lnum
---| statuscolumn.components.folds
---| statuscolumn.components.signs
---| statuscolumn.components.empty
---| statuscolumn.components.border
---| statuscolumn.components.custom
---@type statuscolumn.config
statuscolumn.config = {
    ignore_filetypes = { "blink-cmp-menu" },
    ignore_buftypes = { "help" },

    condition = function (buffer)
        local ft, bt = vim.bo[buffer].ft, vim.bo[buffer].bt;

        if bt == "nofile" and ft == "query" then
            --- Buffer for `:InspectTree`
            return true;
        elseif bt == "nofile" then
            --- Normal nofile buffer.
            return false;
        else
            return true;
        end
    end,

    default = {
        components = {
            ---|fS

            {
                kind = "empty",
                width = 1,

                hl = "Normal"
            },
            {
                kind = "signs",
                width = 1,
                hl = "Normal",

                filter = function (buffer, namespaces, _, _, _, details)
                    ---@type string
                    local mode = vim.api.nvim_get_mode().mode;
                    local name = namespaces[details.ns_id] or "";

                    if package.loaded["markview"] and vim.bo[buffer].ft == "markdown" then
                        --- On markdown files when on normal
                        --- mode only show markview signs.
                        if mode == "n" then
                            return string.match(name, "^markview") ~= nil;
                        else
                            return true;
                        end
                    elseif package.loaded["helpview"] and vim.bo[buffer].ft == "help" then
                        --- On help files when on normal
                        --- mode only show helpview signs.
                        if mode == "n" then
                            return string.match(name, "^helpview") ~= nil;
                        else
                            return true;
                        end
                    else
                        if mode == "n" then
                            --- On normal mode only show LSP signs.
                            return string.match(name, "^vim[%._]lsp") ~= nil;
                        elseif vim.list_contains({ "i", "v", "V", "" }, mode) then
                            --- On visual mode only show git signs.
                            return string.match(name, "^gitsigns") ~= nil;
                        end

                        return true;
                    end
                end
            },
            {
                kind = "folds",

                close_text = { "󰌶" },
                close_hl = "Color0",
                open_text = { "󱠂" },
                open_hl = { "Color1", "Color2", "Color3", "Color4", "Color5", "Color6", "Color7" },

                scope_text = "",
                scope_end_text = "",
                scope_merge_text = "",

                fill_text = " ",

                scope_hl = { "Gradient1N2", "Gradient2N2", "Gradient3N2", "Gradient4N2", "Gradient5N2", "Gradient6N2", "Gradient7" },
                scope_end_hl = { "Gradient1N2", "Gradient2N2", "Gradient3N2", "Gradient4N2", "Gradient5N2", "Gradient6N2", "Gradient7" },
                scope_merge_hl = { "Gradient1N2", "Gradient2N2", "Gradient3N2", "Gradient4N2", "Gradient5N2", "Gradient6N2", "Gradient7" },
            },
            {
                kind = "empty",
                width = 1,
                hl = "Normal"
            },
            {
                kind = "lnum",
                mode = 3,

                click = function (_, window)
                    return window == vim.api.nvim_get_current_win();
                end,

                wrap_markers = "",
                virt_markers = "",

                wrap_hl = {
                    "Gradient4N0", "Gradient4N0", "Gradient4N1", "Gradient4N1",
                    "Gradient4N2", "Gradient4N2", "Gradient4N3", "Gradient4N3",
                    "Gradient4N4", "Gradient4N4"
                },
                virt_hl = {
                    "Gradient5N0", "Gradient5N0", "Gradient5N1", "Gradient5N1",
                    "Gradient5N2", "Gradient5N2", "Gradient5N3", "Gradient5N3",
                    "Gradient5N4", "Gradient5N4"
                },
                hl = {
                    "Lnum",
                    "Shadow5", "Shadow4", "Shadow3",
                    "Shadow2", "Shadow1", "Shadow0"
                }
            },
            {
                kind = "empty",
                width = 1,
                hl = "Normal"
            },
            {
                kind = "border",
                text = "",
                hl = function (_, window)
                    ---|fS "Color matching the mode"
                    if vim.api.nvim_get_current_win() ~= window then
                        return "Layer2I";
                    end

                    local _o = {};
                    local gr_map = {
                        default = "Gradient8N%d",

                        ["v"] = "Gradient9N%d",
                        ["V"] = "Gradient7N%d",
                        [""] = "Gradient2N%d",

                        ["s"] = "Gradient9N%d",
                        ["S"] = "Gradient7N%d",
                        [""] = "Gradient2N%d",

                        ["i"] = "Gradient10N%d",
                        ["ic"] = "Gradient10N%d",
                        ["ix"] = "Gradient10N%d",

                        ["R"] = "Gradient8N%d",
                        ["Rc"] = "Gradient8N%d",

                        ["c"] = "Gradient4N%d",
                        ["!"] = "Gradient4N%d",
                    };

                    ---@type string
                    local mode = vim.api.nvim_get_mode().mode;

                    for g = 0, 4 do
                        ---@type string
                        local hl = gr_map[mode] or gr_map.default;

                        table.insert(_o, string.format(hl, g));
                    end

                    return _o;
                    ---|fE
                end
            },

            ---|fE
        }
    },

    query = {
        ---|fS

        condition = function (buffer)
            return vim.bo[buffer].ft == "query" and vim.bo[buffer].bt == "nofile";
        end,

        components = {
            {
                kind = "empty",
                width = 1,
                hl = "LineNr"
            },
        }

        ---|fE
    }
};

🧩 Components

By default, bars.nvim ships with a bunch of components. These components are,

💡 Line number(lnum)

Shows the line number.

Tip

This has mouse click support.

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

See type definition
--- Line number for statuscolumn.
---@class statuscolumn.components.lnum
---
--- Condition for this component.
---@field condition? fun(buffer: integer, window: integer, statuscolumn: string): boolean
---
--- What kind of component is this?
---@field kind "lnum"
---
---@field click? boolean | fun(buffer: integer, window: integer, statuscolumn: string): boolean
---
---@field mode
---| 1 Line number.
---| 2 Relative line number.
---| 3 Hybrid line number.
---
--- Text used for the wrapped lines.
--- Can be a list to create a *fake* gradient effect.
---@field wrap_markers string | string[]
---
--- Text used for the virtual lines.
--- Can be a list to create a *fake* gradient effect.
---@field virt_markers string | string[]
---
--- Highlight group for `wrap_markers`.
--- Can be a list to create a color gradient.
---@field wrap_hl? string | string[]
---
--- Highlight group for `virt_markers`.
--- Can be a list to create a color gradient.
---@field virt_hl? string | string[]
---
--- Highlight group for the line numbers.
--- Can be a list to create a color gradient.
---@field hl? string | string[] | fun(buffer: integer, window: integer): ( string | string[] )
{
    kind = "lnum",
    mode = 3,

    click = function (_, window)
        return window == vim.api.nvim_get_current_win();
    end,

    wrap_markers = "",
    virt_markers = "",

    wrap_hl = {
        "Gradient4N0", "Gradient4N0", "Gradient4N1", "Gradient4N1",
        "Gradient4N2", "Gradient4N2", "Gradient4N3", "Gradient4N3",
        "Gradient4N4", "Gradient4N4"
    },
    virt_hl = {
        "Gradient5N0", "Gradient5N0", "Gradient5N1", "Gradient5N1",
        "Gradient5N2", "Gradient5N2", "Gradient5N3", "Gradient5N3",
        "Gradient5N4", "Gradient5N4"
    },
    hl = {
        "Lnum",
        "Shadow5", "Shadow4", "Shadow3",
        "Shadow2", "Shadow1", "Shadow0"
    }
},

💡 Empty

Empty space.

See type definition
--- Empty component.
---@class statuscolumn.components.empty
---
--- Condition for this component.
---@field condition? fun(buffer: integer, window: integer, statuscolumn: string): boolean
---
--- What kind of component is this?
---@field kind "empty"
---
--- How many columns should this span?
---@field width integer
---
--- Highlight group for this section.
---@field hl? string
{
    kind = "empty",
    width = 1,
    hl = "LineNr"
},

💡 Border

Border(like empty but shows some character).

See type definition
--- Border for the statuscolumn.
---@class statuscolumn.components.border
---
--- Condition for this component.
---@field condition? fun(buffer: integer, window: integer, statuscolumn: string): boolean
---
--- What kind of component is this?
---@field kind "border"
---
--- Text to use for the border.
--- Can be a list to create a gradient.
---@field text string | string[]
---
--- Highlight group for the border.
--- Can be a list to create a gradient.
---@field hl? string | string[]
{
    kind = "border",
    text = "",
    hl = function (_, window)
        ---|fS "Color matching the mode"
        if vim.api.nvim_get_current_win() ~= window then
            return "Layer2I";
        end

        local _o = {};
        local gr_map = {
            default = "Gradient8N%d",

            ["v"] = "Gradient9N%d",
            ["V"] = "Gradient7N%d",
            [""] = "Gradient2N%d",

            ["s"] = "Gradient9N%d",
            ["S"] = "Gradient7N%d",
            [""] = "Gradient2N%d",

            ["i"] = "Gradient10N%d",
            ["ic"] = "Gradient10N%d",
            ["ix"] = "Gradient10N%d",

            ["R"] = "Gradient8N%d",
            ["Rc"] = "Gradient8N%d",

            ["c"] = "Gradient4N%d",
            ["!"] = "Gradient4N%d",
        };

        ---@type string
        local mode = vim.api.nvim_get_mode().mode;

        for g = 0, 4 do
            ---@type string
            local hl = gr_map[mode] or gr_map.default;

            table.insert(_o, string.format(hl, g));
        end

        return _o;
        ---|fE
    end
},

💡 Folds

Custom foldcolumn.

See type definition
--- Fold column for the statuscolumn.
---@class statuscolumn.components.folds
---
--- Condition for this component.
---@field condition? fun(buffer: integer, window: integer, statuscolumn: string): boolean
---
--- What kind of component is this?
---@field kind "folds"
---
--- Text to show for closed fold.
--- Can be a list to use a different
--- text for different levels of folds.
---@field close_text string | string[]
---
--- Highlight group for the `close_text`.
--- Can be a list to assign different
--- colors to different fold level.
---@field close_hl? string | string[]
---
--- Text to show for opened fold.
--- Can be a list to use a different
--- text for different levels of folds.
---@field open_text string | string[]
---
--- Highlight group for the `open_text`.
--- Can be a list to assign different
--- colors to different fold level.
---@field open_hl? string | string[]
---
--- Text to show the scope of opened fold.
--- Can be a list to use a different
--- text for different levels of folds.
---@field scope_text string | string[]
---
--- Highlight group for the `scope_text`.
--- Can be a list to assign different
--- colors to different fold level.
---@field scope_hl? string | string[]
---
--- Text to show at the end of opened fold.
--- Can be a list to use a different
--- text for different levels of folds.
---@field scope_end_text string | string[]
---
--- Highlight group for the `scope_end_text`.
--- Can be a list to assign different
--- colors to different fold level.
---@field scope_end_hl? string | string[]
---
--- Text to show where fold level changes.
--- Can be a list to use a different
--- text for different levels of folds.
---@field scope_merge_text string | string[]
---
--- Highlight group for the `scope_merge_text`.
--- Can be a list to assign different
--- colors to different fold level.
---@field scope_merge_hl? string | string[]
---
--- Text for normal lines.
---@field fill_text string
---
--- Highlight group for `fill_text`.
---@field fill_hl? string
{
    kind = "folds",

    close_text = { "󰌶" },
    close_hl = "Color0",
    open_text = { "󱠂" },
    open_hl = { "Color1", "Color2", "Color3", "Color4", "Color5", "Color6", "Color7" },

    scope_text = "",
    scope_end_text = "",
    scope_merge_text = "",

    fill_text = " ",

    scope_hl = { "Gradient1N2", "Gradient2N2", "Gradient3N2", "Gradient4N2", "Gradient5N2", "Gradient6N2", "Gradient7" },
    scope_end_hl = { "Gradient1N2", "Gradient2N2", "Gradient3N2", "Gradient4N2", "Gradient5N2", "Gradient6N2", "Gradient7" },
    scope_merge_hl = { "Gradient1N2", "Gradient2N2", "Gradient3N2", "Gradient4N2", "Gradient5N2", "Gradient6N2", "Gradient7" },
},

💡 Signs

Custom signcolumn.

See type definition
--- Custom signcolumn.
---@class statuscolumn.components.signs
---
--- Condition for this component.
---@field condition? fun(buffer: integer, window: integer, statuscolumn: string): boolean
---
--- What kind of component is this?
---@field kind "signs"
---
--- Filter for signs.
---@field filter? fun(buffer: integer, ns_map: table<integer, string>, ns: integer, row: integer, col: integer, extmark: table): boolean
---
--- Highlight group for the signs.
--- NOTE, This will overwrite the
--- sign's original highlight group.
---@field hl? string
{
    kind = "signs",
    width = 1,
    hl = "Normal",

    filter = function (buffer, namespaces, _, _, _, details)
        ---@type string
        local mode = vim.api.nvim_get_mode().mode;
        local name = namespaces[details.ns_id] or "";

        if package.loaded["markview"] and vim.bo[buffer].ft == "markdown" then
            --- On markdown files when on normal
            --- mode only show markview signs.
            if mode == "n" then
                return string.match(name, "^markview") ~= nil;
            else
                return true;
            end
        elseif package.loaded["helpview"] and vim.bo[buffer].ft == "help" then
            --- On help files when on normal
            --- mode only show helpview signs.
            if mode == "n" then
                return string.match(name, "^helpview") ~= nil;
            else
                return true;
            end
        else
            if mode == "n" then
                --- On normal mode only show LSP signs.
                return string.match(name, "^vim[%._]lsp") ~= nil;
            elseif vim.list_contains({ "i", "v", "V", "" }, mode) then
                --- On visual mode only show git signs.
                return string.match(name, "^gitsigns") ~= nil;
            end

            return true;
        end
    end
},

💡 Custom

Custom component. Create whatever type of component using it.

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

    value = ""
}

Also in vimdoc, :h bars-statuscolumn.

Clone this wiki locally