feature(dashboard): Disable caching for terminal command
Did you check the docs?
- [x] I have read all the snacks.nvim docs
Is your feature request related to a problem? Please describe.
Snacks.nvim's dashboard module caches the dashboard per folder. So if I have a command like fortune, it shows the same thing for multiple nvim's or terminals.
Describe the solution you'd like
The cache option disables the per folder caching of the command output, so if the command output is always different, it doesn't show the same output from last time.
require("snacks").setup({
dashboard = {
sections = {
{,
section = "terminal",
cmd = 'FORTUNE=$(fortune -n 25 -s) && printf "%*s\n" $(( ($(tput cols) + ${#FORTUNE}) / 2 )) "$FORTUNE"',
cache = false,
},
}
}
})
Describe alternatives you've considered
Creating a temporary directory, going into it, then going back into the original directory.
Additional context
I think that should be all! Actually... I am just a random guy
I believe if you set ttl = 0 it should do what you want.
That worked!!!
What does ttl exactly do?
It defines the amount of time the cache will be preserved if I'm not mistaken.
Wait, when I resize the window it reruns the command
That's probaly how it works. It must have an autocmd that does this. No idea.
Well then this feature should be added.
When Neovim is resized then the Dashboard gets updated. That means the sections will be recalculated and the terminal section will run the command again. With ttl = 0, that means that whenever the command is run a different output will be available. I thought that's what you wanted.
Sorry, was at a doctors appointment. I actually wanted to use a different output per Dashboard. Which means when it recalculates size and sections, then the command should not run again. But when I do nvim in one terminal and nvim in another terminal, in the same folder, or nvim twice in the same terminal, in the same folder, it should use a different output. That also when Snacks.dashboard() (instead of nvim) is used.
Which means when it recalculates size and sections, then the command should not run again.
I don't believe that's possible with how the current Dashboard is implemented. Of course I might be mistaken, so you better wait for maintainer's input on that.
That is how the cache is created. I think if you would add an option and check if it's true, then you could stop this process
local cache_parts = {
table.concat(type(cmd) == "table" and cmd or { cmd }, " "),
uv.cwd(),
opts.random and math.random(1, opts.random) or "",
}
local hashed_cache_key = vim.fn.sha256(table.concat(cache_parts, "."))
local cache_dir = vim.fn.stdpath("cache") .. "/snacks"
local cache_file = cache_dir .. "/" .. hashed_cache_key .. ".txt"
local stat = uv.fs_stat(cache_file)
local buf = vim.api.nvim_create_buf(false, true)
local chan = vim.api.nvim_open_term(buf, {})
local function send(data, refresh)
vim.api.nvim_chan_send(chan, data)
if refresh then
-- HACK: this forces a refresh of the terminal buffer and prevents flickering
vim.bo[buf].scrollback = 9999
vim.bo[buf].scrollback = 9998
end
end
local jid, stopped ---@type number?, boolean?
local has_cache = stat and stat.type == "file" and stat.size > 0
local is_expired = has_cache and stat and os.time() - stat.mtime.sec >= ttl
if has_cache and stat then
local fin = assert(uv.fs_open(cache_file, "r", 438))
send(uv.fs_read(fin, stat.size, 0) or "", true)
uv.fs_close(fin)
end
if not has_cache or is_expired then
local output, recording = {}, assert(uv.new_timer())
-- record output for max 5 seconds. otherwise assume its streaming
recording:start(5000, 0, function()
output = {}
end)
local first = true
jid = vim.fn.jobstart(cmd, {
height = height,
width = width,
pty = true,
on_stdout = function(_, data)
data = table.concat(data, "\n")
if recording:is_active() then
table.insert(output, data)
end
That is how the cache is **created**. I think if you would add an option and check if it's true, then you could stop this process
if first and has_cache then -- clear the screen if cache was expired
first = false
data = "\27[2J\27[H" .. data -- clear screen
end
pcall(send, data)
end,
on_exit = function(_, code)
if not recording:is_active() or stopped then
return
end
if code ~= 0 then
Snacks.notify.error(
("Terminal **cmd** `%s` failed with code `%d`:\n- `vim.o.shell = %q`\n\nOutput:\n%s"):format(
cmd,
code,
vim.o.shell,
vim.trim(table.concat(output, ""))
)
)
elseif ttl > 0 then -- save the output
vim.fn.mkdir(cache_dir, "p")
local fout = assert(uv.fs_open(cache_file, "w", 438))
uv.fs_write(fout, table.concat(output, ""))
uv.fs_close(fout)
end
end,
})
Something like this maybe?
if not has_cache or is_expired and cache then
local output, recording = {}, assert(uv.new_timer())
-- record output for max 5 seconds. otherwise assume its streaming
recording:start(5000, 0, function()
output = {}
end)
local first = true
jid = vim.fn.jobstart(cmd, {
height = height,
width = width,
pty = true,
on_stdout = function(_, data)
data = table.concat(data, "\n")
if recording:is_active() then
table.insert(output, data)
end
That is how the cache is **created**. I think if you would add an option and check if it's true, then you could stop this process
if first and has_cache then -- clear the screen if cache was expired
first = false
data = "\27[2J\27[H" .. data -- clear screen
end
pcall(send, data)
end,
on_exit = function(_, code)
if not recording:is_active() or stopped then
return
end
if code ~= 0 then
Snacks.notify.error(
("Terminal **cmd** `%s` failed with code `%d`:\n- `vim.o.shell = %q`\n\nOutput:\n%s"):format(
cmd,
code,
vim.o.shell,
vim.trim(table.concat(output, ""))
)
)
elseif ttl > 0 then -- save the output
vim.fn.mkdir(cache_dir, "p")
local fout = assert(uv.fs_open(cache_file, "w", 438))
uv.fs_write(fout, table.concat(output, ""))
uv.fs_close(fout)
end
end,
Even without cache the command will be rerun when updating the terminal section when the window will get resized and will thus give you a different output when you resize.
But only when ttl is set to 0, my code checks if cache is set to true beforehand.
Yes, you have a point about that. Didn't think it through.
However, I'm just a simple user like you, so it would be best to wait for maintainer's feedback on that.
I do know that, but at least we have an idea of how this would work! But @folke hasn't been active that much recently...
He probably needs a long break to avoid burn-out. I'm sure he will either come back or make a proper announcement if he doesn't intend to. I remember last year he took off 1,5-2 months hiatus before coming back. We just have to be patient.
Next week I'll do some maintenance. I've been mostly doing lots of training for a big ultra I'm running in September in Kenia. I also have two new vacations lined up. In two weeks from now, two weeks Madeira and then a week after that I'm leaving for Borneo. Mid May I'll be back doing more Neovim stuff. Till at least end of June. In the summer I also have quite a lot of trips planned.
I hope you have a lot of fun!
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
Man I hate the stale bot
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
no
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
Man please be quietttttt
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
No.
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.
BlaBlaCar
soon will be stale
You can add random = 100 or whatever. or use ttl = 0.