🪴 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 events = {
50 "WinEnter",
51 "BufEnter",
52 "BufWritePost",
53 "SessionLoadPost",
54 "FileChangedShellPost",
55 "VimResized",
56 "Filetype",
57 "CursorMoved",
58 "CursorMovedI",
59 "ModeChanged",
60 "CmdlineEnter",
61 },
62 hls = {},
63 modules = {
64 "%<%f %h%w%m%r",
65 "%=",
66 {
67 fn = function()
68 if vim.o.showcmdloc == "statusline" then
69 return "%-10.S"
70 end
71 return ""
72 end,
73 },
74 { " " },
75 {
76 fn = function()
77 if not vim.b.keymap_name then
78 return ""
79 end
80 return "<" .. vim.b.keymap_name .. ">"
81 end,
82 },
83 { " " },
84 {
85 fn = function()
86 if vim.bo.busy > 0 then
87 return "◐ "
88 end
89 return ""
90 end,
91 },
92 { " " },
93 {
94 fn = function()
95 if not package.loaded["vim.diagnostic"] then
96 return ""
97 end
98 return vim.diagnostic.status()
99 end,
100 opts = {
101 events = { "DiagnosticChanged" },
102 },
103 },
104 { " " },
105 {
106 fn = function()
107 if not vim.o.ruler then
108 return ""
109 end
110 if vim.o.rulerformat == "" then
111 return "%-14.(%l,%c%V%) %P"
112 end
113 return vim.o.rulerformat
114 end,
115 },
116 },
117 winbar = {},
118})
119```
120
121### example configuration
122
123#### use `mini.icons` for colors
124
125some nice highlights that i personally use:
126
127```lua
128 hls = {
129 normal = { link = "MiniIconsAzure" },
130 visual = { link = "MiniIconsPurple" },
131 command = { link = "MiniIconsOrange" },
132 insert = { link = "MiniIconsGrey" },
133 },
134```
135
136### example components
137
138you can define custom components by passing lua functions:
139
140```lua
141local lylla = require("lylla")
142
143lylla.setup({
144 modules = {
145 lylla.component(function()
146 return "hi " .. vim.env.USER
147 end, { events = { "VimEnter" } }),
148 },
149})
150```
151
152components return strings to be shown in the statusline and can register
153autocmds to refresh them.
154
155components can also return a tuple combining text with a highlight group:
156
157```lua
158{
159 {
160 { "meow", "ModeMsg" },
161 { " | ", "WinSeparator" },
162 },
163 { fn = function() return { vim.bo.filetype, "MsgArea" } end },
164}
165```
166
167these tables can be nested to any amount; they all get folded down on refresh.
168
169### change refresh rate and events
170
171```lua
172require("lylla").setup {
173 refresh_rate = 100, -- update faster
174 events = { "WinEnter", "BufEnter", "CursorMoved" }, -- only update on these
175}
176```
177
178(events control when the statusline is redrawn)
179
180### add a custom module
181
182modules are just tables that return strings.
183this example shows your current working directory:
184
185```lua
186local lylla = require("lylla")
187
188lylla.setup {
189 modules = {
190 "%<%f %h%w%m%r", -- filename etc
191 "%=", -- spacer
192 {
193 fn = function()
194 return vim.fn.fnamemodify(vim.fn.getcwd(), ":t")
195 end, opts = {
196 events = { "DirChanged" },
197 },
198 },
199 },
200}
201```
202
203### conditional modules
204
205modules can react to options, buffers, or plugins.
206example: only show diagnostics if `vim.diagnostic` is loaded:
207
208```lua
209{
210 lylla.component(function()
211 if not package.loaded["vim.diagnostic"] then
212 return ""
213 end
214 return vim.diagnostic.status()
215 end, { events = { "DiagnosticChanged" } }),
216}
217```
218
219### lsp information
220
221lylla utils has a builtin helper for getting the current lsp client.
222
223```lua
224local utils = require("lylla.utils")
225
226{
227 lylla.component(function()
228 local client = utils.get_client()
229 return client and {
230 { { "lsp :: " }, { client } },
231 }
232 end, { events = { "FileType" } }),
233}
234```
235
236### winbar
237
238the winbar can be configured in the same way as the statusline:
239
240```lua
241winbar = {
242 lylla.component(function()
243 return {
244 utils.getfilepath(),
245 utils.getfilename(),
246 { " " },
247 "%h%w%m%r",
248 }
249 end, {
250 events = {
251 "WinEnter",
252 "BufEnter",
253 "BufWritePost",
254 "FileChangedShellPost",
255 "Filetype",
256 },
257 }),
258 { " " },
259 lylla.component(function()
260 return utils.get_searchcount()
261 end),
262},
263```