aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/nvim/.config/nvim/lua/tobyvin/utils/dashboard.lua
blob: cab39602fb766dd792fe389da1dc1c39ea6ce109 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
---@type string[][]
local dashboard = {}

---@type table<string,integer>
local _index = {
	header = 1,
	lazy = 2,
	cowsay = 3,
}

---@type string[]
local sections = setmetatable({}, {
	__index = function(_, k)
		return dashboard[_index[k]]
	end,

	__newindex = function(_, k, v)
		if _index[k] then
			dashboard[_index[k]] = v
		else
			table.insert(dashboard, v)
			_index[k] = #dashboard
		end
		vim.api.nvim_exec_autocmds("User", { pattern = "DashboardUpdate" })
	end,
})

local function should_skip()
	-- don't start when opening a file
	if vim.fn.argc() > 0 then
		return true
	end

	-- skip stdin
	if vim.fn.line2byte(vim.fn.line("$")) ~= -1 then
		return true
	end

	-- Handle nvim -M
	if not vim.o.modifiable then
		return true
	end

	for _, arg in pairs(vim.v.argv) do
		-- whitelisted arguments
		-- always open
		if arg == "--startuptime" then
			return false
		end

		-- blacklisted arguments
		-- always skip
		if
			arg == "-b"
			-- commands, typically used for scripting
			or arg == "-c"
			or vim.startswith(arg, "+")
			or arg == "-S"
		then
			return true
		end
	end

	-- base case: don't skip
	return false
end

local function max_len(lines)
	local max = 0
	for _, line in ipairs(lines) do
		max = math.max(max, vim.fn.strdisplaywidth(line))
	end
	return max
end

local function pad_lines(lines)
	local max_line_len = max_len(lines)
	local width = vim.api.nvim_win_get_width(0)
	local padded = {}
	for _, line in ipairs(lines) do
		local line_len = max_line_len
		local pad_len = math.floor((width / 2) - (line_len / 2))
		table.insert(padded, string.rep(" ", pad_len) .. line)
	end
	return padded
end

local function render(buf)
	local rendered = {}
	for _, lines in pairs(dashboard) do
		vim.list_extend(rendered, pad_lines(lines))
	end
	vim.bo[buf].modifiable = true
	vim.api.nvim_buf_set_lines(buf, 0, -1, false, rendered)
	vim.bo[buf].modifiable = false
end

if should_skip() then
	return
end

local buf = vim.api.nvim_create_buf(false, true)

vim.api.nvim_set_current_buf(buf)

vim.opt_local.textwidth = 0
vim.opt_local.bufhidden = "wipe"
vim.opt_local.buflisted = false
vim.opt_local.matchpairs = ""
vim.opt_local.swapfile = false
vim.opt_local.buftype = "nofile"
vim.opt_local.filetype = "dashboard"
vim.opt_local.synmaxcol = 0
vim.opt_local.wrap = false
vim.opt_local.colorcolumn = ""
vim.opt_local.foldlevel = 999
vim.opt_local.foldcolumn = "0"
vim.opt_local.cursorcolumn = false
vim.opt_local.cursorline = false
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.opt_local.list = false
vim.opt_local.spell = false
vim.opt_local.signcolumn = "no"

local function with_spacer(lines, count)
	local spaced = lines
	while #spaced < count do
		table.insert(spaced, 1, "")
	end
	return spaced
end

local function cowsay()
	local Job = require("plenary.job")
	return Job:new({
		command = "cowsay",
		writer = Job:new({ command = "fortune", args = { "-s" } }),
	}):sync()
end

local augroup = vim.api.nvim_create_augroup("dashboard", { clear = true })

vim.api.nvim_create_autocmd("User", {
	group = augroup,
	pattern = { "DashboardUpdate" },
	callback = function()
		if vim.api.nvim_get_current_buf() == buf then
			render(buf)
		end
	end,
	desc = "render dashboard on updates",
})

vim.api.nvim_create_autocmd("BufHidden", {
	group = augroup,
	pattern = { "*" },
	callback = function(args)
		if args.buf == buf then
			vim.api.nvim_del_autocmd(augroup)
			return true
		end
	end,
	desc = "clear dashboard autocmds",
})

local c_ok, c_exe = pcall(vim.fn.executable, "cowsay")
local f_ok, f_exe = pcall(vim.fn.executable, "fortune")
if c_ok and 1 == c_exe and f_ok and 1 == f_exe then
	sections.cowsay = with_spacer(cowsay(), 15)

	vim.keymap.set("n", "<C-n>", function()
		sections.cowsay = with_spacer(cowsay(), 15)
	end, { desc = "next cowsay", buffer = buf })
end

sections.header = with_spacer({
	"                                                    ",
	" ███╗   ██╗███████╗ ██████╗ ██╗   ██╗██╗███╗   ███╗ ",
	" ████╗  ██║██╔════╝██╔═══██╗██║   ██║██║████╗ ████║ ",
	" ██╔██╗ ██║█████╗  ██║   ██║██║   ██║██║██╔████╔██║ ",
	" ██║╚██╗██║██╔══╝  ██║   ██║╚██╗ ██╔╝██║██║╚██╔╝██║ ",
	" ██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ ",
	" ╚═╝  ╚═══╝╚══════╝ ╚═════╝   ╚═══╝  ╚═╝╚═╝     ╚═╝ ",
	"                                                    ",
}, 15)

vim.api.nvim_create_autocmd("User", {
	group = augroup,
	pattern = { "Lazy*" },
	callback = function()
		local updates = nil
		if require("lazy.status").has_updates() then
			updates = string.format("updates: %s", require("lazy.status").updates())
		end

		local stats = require("lazy").stats()
		sections.lazy = {
			string.format("startup: %s ms", stats.startuptime),
			string.format("plugins: %s (%s loaded)", stats.count, stats.loaded),
			updates,
		}
	end,
	desc = "dashboard lazy stats",
})