Skip to content

Commit 207ba9d

Browse files
authored
feat: oldfiles builtin (#8)
* feat: oldfiles builtin * feat: skippable headers for sections * docs: update demo and defaults
1 parent 03dc8e4 commit 207ba9d

File tree

5 files changed

+173
-31
lines changed

5 files changed

+173
-31
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ A blazingly fast, animated, and infinitely customizeable startup / dashboard plu
1010
- [x] Animated sections rendered with virtual text
1111
- [x] Builtin "standard library"
1212
- [x] Buttons builtin
13-
- [ ] Oldfiles builtin
13+
- [X] Oldfiles builtin
1414
- [ ] Current dir builtin
1515
- [ ] Floating widget builtin
1616
- [x] Ascii frame anim builtin
@@ -33,8 +33,13 @@ A blazingly fast, animated, and infinitely customizeable startup / dashboard plu
3333
## Demo (default config)
3434

3535
<!--https://user-images.githubusercontent.com/38540736/227105511-7988cd83-be56-4606-a32d-07d6245d1307.mp4-->
36+
<!--https://user-images.githubusercontent.com/38540736/227207398-b8f7af6a-0e88-4874-93fa-196e78c14938.mp4-->
37+
38+
39+
40+
https://user-images.githubusercontent.com/38540736/228553706-b68e99a7-c4d6-4803-a06e-4e3bb12109ea.mp4
41+
3642

37-
https://user-images.githubusercontent.com/38540736/227207398-b8f7af6a-0e88-4874-93fa-196e78c14938.mp4
3843

3944
## Installation
4045

@@ -113,6 +118,7 @@ local default = {
113118
},
114119
}),
115120
},
121+
builtin.sections.oldfiles(),
116122
mappings = {},
117123
startup = true,
118124
listed = false

lua/veil.lua

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,25 @@ local veil = {
1010
vcursor = 0,
1111
height = 0,
1212
},
13+
win = nil,
14+
buf = nil,
1315
}
1416

17+
---@return table veil.state
18+
function veil.get_state()
19+
return veil.state
20+
end
21+
22+
---@return bufnr veil.buf
23+
function veil.get_buf()
24+
return veil.buf
25+
end
26+
27+
---@return winnr veil.win
28+
function veil.get_win()
29+
return veil.win
30+
end
31+
1532
function veil:configure(opt)
1633
local opts = vim.tbl_deep_extend("force", require("veil.default"), opt or {})
1734
self.settings.sections = opts.sections or {}
@@ -54,6 +71,9 @@ function veil:move(dir)
5471
end
5572
if loc ~= nil and loc.interactive then
5673
self.state.vcursor = self.state.vcursor - count
74+
if loc.int_start > 1 and veil:section_offset(self.loclist[idx]) < loc.int_start then
75+
self.state.vcursor = self.state.vcursor - loc.int_start + 1
76+
end
5777
return true
5878
end
5979
else
@@ -68,6 +88,9 @@ function veil:move(dir)
6888
end
6989
if loc ~= nil and loc.interactive then
7090
self.state.vcursor = self.state.vcursor + count
91+
if loc.int_start > 1 and veil:section_offset(self.loclist[idx]) < loc.int_start then
92+
self.state.vcursor = self.state.vcursor + loc.int_start - 1
93+
end
7194
return true
7295
end
7396
end
@@ -117,6 +140,7 @@ function veil:setup_buffer(replace)
117140

118141
local hl = vim.api.nvim_get_hl_by_name("Cursor", true)
119142
hl.blend = 100
143+
120144
vim.api.nvim_set_hl(veil.ns, "VeilCursor", hl)
121145
vim.api.nvim_set_hl(veil.ns, "Cursor", hl)
122146

@@ -275,25 +299,26 @@ function veil:redraw(init)
275299
local focused = (not section.virt) and (self.state.vcursor == current_height + i)
276300
local sep = self.settings.selection.separators
277301
if focused then
278-
local fhl = vim.fn.hlID(section.focused_hl)
302+
local fhl = vim.api.nvim_get_hl_by_id(section.focused_hl, true)
279303
local inv_hl = {
280-
fg = vim.fn.synIDattr(fhl, "bg"),
304+
fg = fhl.guibg or fhl.bg or fhl.background,
281305
bg = "none",
282306
}
283307
vim.api.nvim_set_hl(0, section.focused_hl .. "Inv", inv_hl)
284308
end
285-
table.insert(virt, {
286-
{ leading, "Normal" },
287-
{ focused and sep.left or " ", focused and section.focused_hl .. "Inv" or "Normal" },
288-
{ rest, focused and section.focused_hl or section.hl },
289-
{ focused and sep.right or " ", focused and section.focused_hl .. "Inv" or "Normal" },
290-
})
291-
end
292-
for i, line in ipairs(virt) do
293-
if #line ~= 2 then
294-
virt[i][3][1] = line[3][1] .. string.rep(" ", math.max(max_width - #line[3][1], 0))
309+
if #rest > 0 then
310+
table.insert(virt, {
311+
{ leading, "Normal" },
312+
{ focused and sep.left or " ", focused and section.focused_hl .. "Inv" or "Normal" },
313+
{ rest, focused and section.focused_hl or section.hl },
314+
{ focused and sep.right or " ", focused and section.focused_hl .. "Inv" or "Normal" },
315+
})
295316
else
296-
virt[i][2][1] = line[2][1] .. string.rep(" ", math.max(max_width - #line[2][1], 0))
317+
table.insert(virt, {
318+
{ leading, "Normal" },
319+
-- { focused and sep.left or " ", focused and section.focused_hl .. "Inv" or "Normal" },
320+
-- { focused and sep.right or " ", focused and section.focused_hl .. "Inv" or "Normal" },
321+
})
297322
end
298323
end
299324

@@ -309,6 +334,7 @@ function veil:redraw(init)
309334
nlines = section.nlines,
310335
handle = section,
311336
interactive = not section.virt,
337+
int_start = section.int_start,
312338
}
313339

314340
current_height = current_height + section.nlines
@@ -365,4 +391,13 @@ return {
365391
up = up,
366392
down = down,
367393
},
394+
api = {
395+
move = {
396+
up = up,
397+
down = down,
398+
},
399+
get_buf = veil.get_buf,
400+
get_win = veil.get_win,
401+
get_state = veil.get_state,
402+
},
368403
}

lua/veil/builtin.lua

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@ local map = require("veil").map
55
local builtin = {
66
sections = {},
77
headers = {},
8+
highlight = {
9+
normal = function()
10+
local v = require("veil").api.get_buf()
11+
local b = vim.api.nvim_get_current_buf()
12+
if v == b then
13+
local norm = vim.fn.hlID("Normal")
14+
return { fg = vim.fn.synIDattr(norm, "fg"), bg = vim.fn.synIDattr(norm, "bg") }
15+
else
16+
local nc = vim.fn.hlID("NormalNC")
17+
return { fg = vim.fn.synIDattr(nc, "fg"), bg = vim.fn.synIDattr(nc, "bg") }
18+
end
19+
end,
20+
visual = function()
21+
local v = require("veil").api.get_buf()
22+
local b = vim.api.nvim_get_current_buf()
23+
local norm = vim.api.nvim_get_hl_by_name("Visual", true)
24+
local nc = vim.api.nvim_get_hl_by_name("NormalNC", true)
25+
if v == b then
26+
return { fg = norm.guifg or norm.fg or norm.foreground, bg = norm.guibg or norm.bg or norm.background }
27+
else
28+
return { fg = nc.guifg or nc.fg or nc.foreground, bg = norm.guibg or norm.bg or norm.background }
29+
end
30+
end,
31+
},
832
}
933

1034
function builtin.sections.animated(frames, opts)
@@ -30,6 +54,68 @@ function builtin.sections.animated(frames, opts)
3054
})
3155
end
3256

57+
function builtin.sections.oldfiles(options)
58+
local opts = options or {}
59+
local has_icons, icons = pcall(require, "nvim-web-devicons")
60+
return Section:new({
61+
header_size = 2,
62+
state = {
63+
files = vim.v.oldfiles,
64+
line_nrs = {},
65+
max = opts.max or 5,
66+
home = vim.loop.os_homedir(),
67+
icons = has_icons and icons or nil,
68+
},
69+
contents = function(self)
70+
local lines = {}
71+
local align = opts.align or "center"
72+
self.files = vim.v.oldfiles
73+
local maxwidth = 0
74+
for i, file in ipairs(self.files) do
75+
if string.match(file, self.home) ~= nil then
76+
local f, e = vim.loop.fs_stat(vim.fn.fnamemodify(file, ":p:s?" .. self.home .. "?"))
77+
if f ~= nil and e == nil then
78+
local s = vim.fn.fnamemodify(file, ":~:.")
79+
if self.icons then
80+
local icon = self.icons.get_icon(s, vim.fn.fnamemodify(s, ":e"), { default = true })
81+
s = icon .. " " .. s
82+
end
83+
table.insert(lines, s)
84+
table.insert(self.line_nrs, i)
85+
maxwidth = math.max(maxwidth, #s)
86+
if #lines >= self.max then
87+
break
88+
end
89+
end
90+
end
91+
end
92+
table.insert(lines, 1, "Recent files")
93+
table.insert(lines, 2, "")
94+
for i, line in ipairs(lines) do
95+
if align == "center" and line ~= "" then
96+
lines[i] = string.rep(" ", math.floor((maxwidth - #line) / 2)) .. line
97+
elseif align == "right" and line ~= "" then
98+
lines[i] = string.rep(" ", maxwidth - #line) .. line
99+
end
100+
end
101+
102+
return lines
103+
end,
104+
hl = builtin.highlight.normal,
105+
focused_hl = opts.focused_hl or builtin.highlight.visual,
106+
interactive = true,
107+
on_interact = function(self, line, _col)
108+
if line <= 2 then
109+
return
110+
end
111+
-- open the file
112+
vim.cmd(string.format("edit %s", self.files[self.line_nrs[line - 2]]))
113+
-- go to last place in file
114+
vim.api.nvim_feedkeys("'.", "n", false)
115+
end,
116+
})
117+
end
118+
33119
function builtin.sections.buttons(buttons, options)
34120
local opts = options or {}
35121
for _, button in ipairs(buttons) do
@@ -46,6 +132,8 @@ function builtin.sections.buttons(buttons, options)
46132
end,
47133
contents = function(self)
48134
local lines = {}
135+
local align = opts.align or "center"
136+
local maxwidth = 0
49137
for _, button in ipairs(self.buttons) do
50138
local s = string.format(
51139
"%s%s %s",
@@ -56,12 +144,23 @@ function builtin.sections.buttons(buttons, options)
56144
if #s % 2 ~= 0 then
57145
s = s .. " "
58146
end
147+
maxwidth = math.max(maxwidth, #s)
59148
table.insert(lines, s)
60149
end
150+
for i, line in ipairs(lines) do
151+
if align == "center" then
152+
-- lines[i] = string.rep(" ", math.floor((maxwidth - #line) / 2)) .. line
153+
if #lines[i] < maxwidth then
154+
lines[i] = lines[i] .. string.rep(" ", maxwidth - #lines[i])
155+
end
156+
elseif align == "right" then
157+
lines[i] = string.rep(" ", maxwidth - #line) .. line
158+
end
159+
end
61160
return lines
62161
end,
63-
hl = opts.hl or "Normal",
64-
focused_hl = opts.focused_hl or "Visual",
162+
hl = opts.hl or builtin.highlight.normal,
163+
focused_hl = opts.focused_hl or builtin.highlight.visual,
65164
interactive = true,
66165
})
67166
end

lua/veil/default.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ local default = {
4343
end,
4444
},
4545
}, { spacing = 6 }),
46+
builtin.sections.oldfiles(),
4647
-- builtin.sections.padding(3),
4748
},
4849
selection = {

lua/veil/section.lua

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ local Rendered = {
88
hl = "Normal",
99
on_interact = nil,
1010
super = nil,
11+
int_start = 1,
1112
}
1213

1314
function Rendered:pad(width)
@@ -34,15 +35,14 @@ end
3435
---@alias Highlight { fg: string|nil, bg: string|nil }
3536
---@class Section
3637
---@field interactive boolean Whether or not the section is interactive.
38+
---@field header_size number Skip the first n lines of section when moving vcursor (for titles)
3739
---@field hl string | Highlight | fun(self: Section):Highlight Highlight group to use for the section.
3840
---@field focused_hl string | Highlight | fun(self: Section):Highlight HL for focused interactive section
3941
---@field contents string[]|string|fun(self:Section):string[] The line or lines to be displayed
4042
local Section = {
4143
---@type table<string, any>
4244
state = {},
4345
interactive = false,
44-
hl = "Normal",
45-
focused_hl = "Visual",
4646
}
4747

4848
---@type fun(self: Section) Called when <CR> is entered with the cursor over a line in this section
@@ -84,25 +84,25 @@ function Section:new(opts)
8484
-- Build the section and render function
8585
mt.__index.contents = new.contents
8686
mt.__index.interactive = new.interactive
87+
mt.__index.interaction_start = (opts.header_size or 0) + 1
8788
mt.__index.on_interact = new.on_interact
8889
mt.__index.hl = hl_id
89-
mt.__index.hl_val = new.hl
90+
mt.__index.hl_val = new.hl or "Normal"
9091
mt.__index.focused_hl = focused_hl_id
91-
mt.__index.focused_hl_val = new.focused_hl
92+
mt.__index.focused_hl_val = new.focused_hl or "Visual"
9293
---@type fun(tbl:Section):Rendered
9394
mt.__index.render = function(tbl)
9495
-- Create the new hlgroup
9596
local function eval(hl)
9697
if type(hl) == "function" then
97-
return hl(tbl)
98+
local hlfn = hl(tbl)
99+
if type(hlfn) == "string" then
100+
return vim.api.nvim_get_hl_by_name(hlfn, true)
101+
else
102+
return hlfn
103+
end
98104
elseif type(hl) == "string" then
99-
return {
100-
fg = vim.fn.synIDattr(vim.fn.hlID(hl), "fg"),
101-
bg = vim.fn.synIDattr(vim.fn.hlID(hl), "bg"),
102-
bold = vim.fn.synIDattr(vim.fn.hlID(hl), "bold") == 1,
103-
italic = vim.fn.synIDattr(vim.fn.hlID(hl), "italic") == 1,
104-
underline = vim.fn.synIDattr(vim.fn.hlID(hl), "underline") == 1,
105-
}
105+
return vim.api.nvim_get_hl_by_name(hl, true)
106106
else
107107
return hl
108108
end
@@ -113,7 +113,7 @@ function Section:new(opts)
113113
veil.ns = vim.api.nvim_create_namespace("veil")
114114
end
115115
vim.api.nvim_set_hl(veil.ns, tbl.hl, eval(tbl.hl_val))
116-
vim.api.nvim_set_hl(veil.ns, tbl.focused_hl, eval(tbl.focused_hl_val))
116+
vim.api.nvim_set_hl(veil.ns, focused_hl_id, eval(tbl.focused_hl_val))
117117

118118
local contents = nil
119119
if type(tbl.contents) == "function" then
@@ -132,10 +132,11 @@ function Section:new(opts)
132132
longest = utils.longest_line(contents),
133133
virt = not tbl.interactive,
134134
hl = tbl.hl,
135-
focused_hl = tbl.focused_hl_val,
135+
focused_hl = vim.api.nvim_get_hl_id_by_name(focused_hl_id),
136136
on_interact = new.on_interact ~= nil and function(relno, col)
137137
instance:on_interact(relno, col)
138138
end or nil,
139+
int_start = (new.header_size or 0) + 1,
139140
})
140141
end
141142

0 commit comments

Comments
 (0)