overseer.nvim
overseer.nvim copied to clipboard
[feature] tasks with dynamic parameter specifications
this one is a long shot, and I would totally understand if you decide that it's just too much for overseer, bloaty, and so on. Overseer is already great as it is, I would totally understand!
But I thought, why not mentioning it. I wrote a custom task for a script I'm using at work.. Well technically I'm registering a template:
require('overseer').register_template(
{
name = "my task",
params = {
branch = { type = "string"},
},
builder = function(params)
...
Now the parameter, branch
, is in fact the name of a branch for a git repository i have somewhere else on my disk. So currently I'm typing the branch name by hand, or pasting it. But in an ideal world, for instance, params, instead of being a constant, could optionally be a function.. in there i would make a plenary sync() call to git to get the list of branch names for that repo.. then I would return a single parameter, but instead of being of type string, it would be of type enum, enumerating all the possible branch names (I'm not sure how much overseer enums can scale in terms of number of members though.. presumably it would be OK).
That way, with the recent cmp completion for task parameters, I could have nice completion and validation for the 'branch name' parameter. But obviously the 'params' function would have to be called again every time the user would invoke the task.
So yes, as I said... I think it would be totally valid to reject this as completely out of scope for overseer, but I thought i'd mention it :)
And thank you again for an amazing tool!
I love this use case, and it would be great to support it somehow. It sounds like the ideal would be to insert some sort of async step in between selecting the task and doing the UI prompt + run logic. I'd have to do some thinking to figure out what a good API would be for that.
Something you could try now: instead of registering this as a template, instead use a template provider. Then you can run the git branch
command as part of the async logic of the provider, and use the branches to set the schema of the template. The downside is that you incur the latency of the git command before your tasks will show up in the list, but the upside is that it will work today!
Thank you for the answer! Regarding the template provider idea, I think there may be an issue, that that the template provider will presumably be invoked only once when overseer is set up, and not every time the user asks for the task list? Or is it possible I'm wrong and it's invoked every time?
(It would be bad if I'm not offered a branch as option if it was added after the task list was first retrieved)
Yeah actually I realized that template providers of course must be invoked for task discovery each time, otherwise mix rake and other new tasks wouldn't be detected. So of course that would be a solution!
Yep, it's invoked every time. Thus the caching logic that I added a while back. So that comes with the caveat that if the provider is slow, the results may become cached and then the branches won't be refreshed until you clear the cache.
Hello, I have the same use case with a cmake based build system for c++.
I have a task to configure cmake and then I have another task for building the project that uses input parameters (compiler, build type and target).
And instead of entering those by typing a string I would be querying the cmake-file-api to create an enum for the available options.
@emmanueltouzery did you manage to make a temporary solution work for this use case ? If so, could you provide some snippet of you solution ?
yes, I used that to great effect, here is an edited portion of code where I take advantage of this:
-- get the list of branches and offer to pick one
require('overseer').register_template(
{
name = "branch-using-task",
cache_key = function(opts)
return "branch-using-task"
end,
generator = function(opts, cb)
local branches = {}
local jid = vim.fn.jobstart({
"git",
"branch",
"--sort=-committerdate",
"--format=%(refname:short)"
}, {
cwd = opts.dir,
stdout_buffered = true,
on_stdout = vim.schedule_wrap(function(j, output)
for _, line in ipairs(output) do
table.insert(branches, line)
end
end),
on_exit = vim.schedule_wrap(function(j, output)
cb({{
name = "name of the task",
params = {
branch = { type = "enum", choices = branches},
},
builder = function(params)
local args = {"rake taskname"}
return {
cmd = {'rake'},
args = args,
env = {
BRANCH = params['branch'],
},
}
end,
}})
end)
})
if jid == 0 then
log:error("Passed invalid arguments to 'git'")
cb({})
elseif jid == -1 then
log:error("'git' is not executable")
cb({})
end
end
})
I'd argue that this is bad practice, because there is no unique history job id<-> status <-> output log <-> command
anymore.
Consider 3 jobs:
RUNNING: gen3
out: waitForMsg: msgty: StopTransaction
────────────────────────────────────────
RUNNING: gen2
out: last_timeline_append 2023-09-22 10:16:47.742601
────────────────────────────────────────
FAILURE: simu16
out: FATAL: port 12000 already used.
────────────────────────────────────────
FAILURE: gen3
out: socket.timeout: timed out
────────────────────────────────────────
RUNNING: simu16
out: 2023-09-22 12:16:38: TestTransactions - 6 - Wait for 21 seconds to avoid too early deauthorization
I do want each task name have a unique meaning in terms of what cmd arguments have been used (ideally also with storing the file hash after the artifacts have been produced meaning build system integration, but that sounds complex to implement).
@matu3ba I don't know what part of this you're referring to is bad practice. Dynamically generating enums for the parameter of a task? Your complaint seems to be that tasks can have the same name, which doesn't have any bearing on this issue. Also, task names can be completely user defined, and default to the executable + all arguments. Doesn't that already do what you want?
Also, task names can be completely user defined, and default to the executable + all arguments. Doesn't that already do what you want?
Agreed, but more so since the design of overseer is to not do execution book keeping besides what the user (recently) started.
I've added support for defining template params as a function. It is not async though, so all i/o operations must be blocking.