🪴 a tiny, customizable statusline for neovim
1# lylla.nvim
2
3a minimal statusline plugin for neovim with extensive configuration; simple by default, flexible if needed.
4
5## features
6
7- minimal default look, based on neovim default statusline implementation
8- flexible configuration; define your own components
9- lightweight design; no required dependencies
10
11## goals
12
13lylla is designed to be:
14
15- minimal in features (no clutter)
16- maximal in configuration
17- stable and predictable; i wanted to prevent any hidden logic that i got
18 annoyed by in other statusline plugins
19
20## installation
21
22###### `vim.pack`
23
24```lua
25vim.pack.add({ src = "comfysage/lylla.nvim" })
26```
27
28###### `lazy.nvim`
29
30```lua
31{
32 "comfysage/lylla.nvim", lazy = false,
33}
34```
35
36### dependencies
37
38some of the utilities included in lylla use
39[mini.nvim](https://github.com/mini-nvim/mini.nvim) but these are not required
40in the default implementation.
41
42## configuration
43
44the default configuration is as follows:
45
46```lua
47require("lylla").setup({
48 refresh_rate = 300,
49 hls = {},
50 modules = {
51 "%<%f %h%w%m%r",
52 "%=",
53 {
54 fn = function()
55 if vim.o.showcmdloc == "statusline" then
56 return "%-10.S"
57 end
58 return ""
59 end,
60 },
61 { " " },
62 {
63 fn = function()
64 if not vim.b.keymap_name then
65 return ""
66 end
67 return "<" .. vim.b.keymap_name .. ">"
68 end,
69 },
70 { " " },
71 {
72 fn = function()
73 if vim.bo.busy > 0 then
74 return "◐ "
75 end
76 return ""
77 end,
78 },
79 { " " },
80 {
81 fn = function()
82 if not package.loaded["vim.diagnostic"] then
83 return ""
84 end
85 return vim.diagnostic.status()
86 end,
87 opts = {
88 events = { "DiagnosticChanged" },
89 },
90 },
91 { " " },
92 {
93 fn = function()
94 if not vim.o.ruler then
95 return ""
96 end
97 if vim.o.rulerformat == "" then
98 return "%-14.(%l,%c%V%) %P"
99 end
100 return vim.o.rulerformat
101 end,
102 },
103 },
104 winbar = {},
105})
106```
107
108### example configuration
109
110for a fully fletched example, look at my personal config: [`config/lylla.lua`](https://codeberg.org/comfysage/ivy/src/commit/bf572e5b6c73d6f0021956b28ec55667c272f6fa/config/config/lylla.lua).
111
112#### use `mini.icons` for colors
113
114some nice highlights that i personally use:
115
116```lua
117 hls = {
118 normal = { link = "MiniIconsAzure" },
119 visual = { link = "MiniIconsPurple" },
120 command = { link = "MiniIconsOrange" },
121 insert = { link = "MiniIconsGrey" },
122 replace = { link = "MiniIconsGrey" },
123 operator = { link = "NonText" },
124 },
125```
126
127### example components
128
129you can define custom components by passing lua functions:
130
131```lua
132local lylla = require("lylla")
133
134lylla.setup({
135 modules = {
136 lylla.component(function()
137 return "hi " .. vim.env.USER
138 end, { events = { "VimEnter" } }),
139 },
140})
141```
142
143components return strings to be shown in the statusline and can register
144autocmds to refresh them.
145
146components can also return a tuple combining text with a highlight group:
147
148```lua
149{
150 {
151 { "meow", "ModeMsg" },
152 { " | ", "WinSeparator" },
153 },
154 { fn = function() return { vim.bo.filetype, "MsgArea" } end },
155}
156```
157
158these tables can be nested to any amount; they all get folded down on refresh.
159
160### change refresh rate and events
161
162```lua
163require("lylla").setup {
164 refresh_rate = 100, -- update faster
165 events = { "WinEnter", "BufEnter", "CursorMoved" }, -- only update on these
166}
167```
168
169(events control when the statusline is redrawn)
170
171### add a custom module
172
173modules are just tables that return strings.
174this example shows your current working directory:
175
176```lua
177local lylla = require("lylla")
178
179lylla.setup {
180 modules = {
181 "%<%f %h%w%m%r", -- filename etc
182 "%=", -- spacer
183 {
184 fn = function()
185 return vim.fn.fnamemodify(vim.fn.getcwd(), ":t")
186 end, opts = {
187 events = { "DirChanged" },
188 },
189 },
190 },
191}
192```
193
194### conditional modules
195
196modules can react to options, buffers, or plugins.
197example: only show diagnostics if `vim.diagnostic` is loaded:
198
199```lua
200{
201 lylla.component(function()
202 if not package.loaded["vim.diagnostic"] then
203 return ""
204 end
205 return vim.diagnostic.status()
206 end, { events = { "DiagnosticChanged" } }),
207}
208```
209
210### sections
211
212modules can handle different highlights for a section. ~ highlights inside will inherit the background color.
213
214```lua
215{
216 lylla.component(function()
217 return {
218 { section = "CursorLine" }, -- highlights after this will inherit the CursorLine bg
219 { "meow", "Title" },
220 { " :3", "Constant" },
221 { section = false }, -- denotes the end of a section
222 }
223 end)
224}
225```
226
227### lsp information
228
229lylla components has a builtin helper for getting the current lsp client.
230
231```lua
232local components = require("lylla.components")
233
234{
235 lylla.component(function()
236 local clients = components.lsp_clients()
237 return clients and {
238 { { "lsp :: " }, { client } },
239 }
240 end, { events = { "FileType", "LspAttach" } }),
241}
242```
243
244### winbar
245
246the winbar can be configured in the same way as the statusline:
247
248```lua
249winbar = {
250 lylla.component(function()
251 return {
252 utils.getfilepath(),
253 utils.getfilename(),
254 { " " },
255 "%h%w%m%r",
256 }
257 end, {
258 events = {
259 "WinEnter",
260 "BufEnter",
261 "BufWritePost",
262 "FileChangedShellPost",
263 "Filetype",
264 },
265 }),
266 { " " },
267 lylla.component(function()
268 return utils.get_searchcount()
269 end),
270},
271```
272
273### tabline
274
275similarly, the tabline can be configured with the help of the `lylla.tabline` module:
276
277```lua
278local H = require('lylla.tabline')
279
280tabline = function()
281 return H.fortabs(function(tabidx, t_iscurrent)
282 return {
283 { string.format(" %d "), t_iscurrent and "TabLineSel" or "TabLine" },
284 }
285 end)
286end
287```