bacon icon indicating copy to clipboard operation
bacon copied to clipboard

Implement changing `command`s via keyboard shortcut

Open narpfel opened this issue 6 months ago • 5 comments
trafficstars

This PR implements a feature to change job commands via keyboard shortcut, instead of changing bacon.toml or switching between different jobs.

This is done by allowing simple conditionals of the form { if = <option>, then = <optional-value-if-option-is-set>, else = <optional-value-if-option-is-unset> } as elements of the command array for jobs.

Options start out as unset and can be toggled by the toggle-option(...) action. If the option is set, the then branch is passed to the command; else the else value is passed.

If the then or else clause is not given, the element is removed from the command invocation if that branch would have been taken.

Example:

default_job = "demo"

[jobs.demo]
command = [
    "echo", "Can", "be",
    { if = "first-option", then = "changed", else = "altered" },
    "based", "on", "keyboard",
    { if = "second-option", then = "shortcuts", else = "input" },
    { if = "full-sentence", then = "." },
]
need_stdout = true

[keybindings]
1 = "toggle-option(first-option)"
2 = "toggle-option(second-option)"
"." = "toggle-option(full-sentence)"

Initially, this starts out as printing Can be altered based on keyboard input, but pressing 1 or 2 toggles between altered/changed and input/shortcuts respectively. Pressing . adds a . to the end of the sentence.

For a real world application of this, see https://github.com/narpfel/panko/commit/023466def41b5d4b5e09b7704f47bf35b7f25ebc. I use bacon run to run the application, and sometimes I want to pass an optional command line flag, but most of the time, I don’t want that flag.

TODO

(I wanted to get feedback if this is a feature you’re interested in before spending time on these items.)

  • [ ] documentation
  • [ ] changelog entry
  • [ ] anything else?

narpfel avatar May 16 '25 20:05 narpfel

I welcome other user's feedback on this but having such controls in the command is not a direction I like.

Comments welcome both on this specific approach and on other ones regarding the general need.

Canop avatar Jun 01 '25 08:06 Canop

It's an interesting idea, however I'm not sure what advantage it has over separate jobs. I'd propose that separate jobs would be easier to understand overall. Only advantage that stands out to me is everything would be closer to each other but I'm not sure that makes up for the additional complexity.

That said one thing I have wanted is a way to be able to get a list of the available jobs while bacon is running without needing to set shortcuts for each of them. If there were a list I could scroll with up and down that would make my life easier and maybe also address this need. @narpfel would that make this no longer needed in your opinion?

c-git avatar Jun 01 '25 13:06 c-git

That said one thing I have wanted is a way to be able to get a list of the available jobs while bacon is running without needing to set shortcuts for each of them

This looks like a (good and) completely distinct problem that would be better discussed either directly in a dedicated issue or on the chat.

Canop avatar Jun 01 '25 13:06 Canop

I'm open to both. This issue just reminded me of that. That's all. It's a thing I want but only just a little as I only need to setup the shortcuts once per project and then I can get a list in the help.

c-git avatar Jun 01 '25 13:06 c-git

It's an interesting idea, however I'm not sure what advantage it has over separate jobs.

For just a single option I agree, separate jobs are simpler (though even then I’d prefer to not duplicate anything if possible). However, each additional option increases the number of jobs (and the number of keyboard shortcuts necessary to trigger them) by a factor of two.

My personal use case (which would require four copies) looks like this (https://github.com/narpfel/panko/compare/main...bacon-maybe-treat-error-as-bug):

[jobs.run]
command = [
    "cargo", "run",
    "--profile=clif",
    "--color", "always",
    "--",
    { if = "treat-error-as-bug", then = "--treat-error-as-bug" },
    "--print=layout",
    "--print=codegen",
    "-o/tmp/main.S",
    { if = "second-input-file", then = "c/test.c", else = "c/main.c"},
]
need_stdout = true
allow_warnings = true
background = true
watch = ["../c"]
env.CLICOLOR_FORCE = "1"

[keybindings]
g = "toggle-option(treat-error-as-bug)"
2 = "toggle-option(second-input-file)"

Another advantage this PR has over duplicating jobs is that transitions between jobs become easier: if I want to toggle --treat-error-as-bug on/off without this PR, this would require two different keys depending on whether I’m in the c/main.c or c/test.c job. With this PR, it’s always the same key, regardless of which other options are toggled on or off.

Here’s an example with two options (four copies of the job) that I randomly found through the Github search: https://github.com/itsscb/posh-parser/blob/f54a302118ff931b0e4ca63c3737536c50e359f6/bacon.toml#L19-L114 With this PR, it could be written as

[jobs.clippy]
command = [
    "cargo",
    "clippy",
    { if = "all-targets", then = "--all-targets" },
    "--color",
    "always",
    { if = "workspace", then = "--workspace" },
    "--",
    "-W",
    "clippy::all",
    "-W",
    "clippy::pedantic",
    "-W",
    "clippy::nursery",
    "-W",
    "clippy::expect_used",
    "-W",
    "clippy::unwrap_used",
]
need_stdout = false

Here’s an example with six copies of basically the same job: https://github.com/kaleidawave/ezno/blob/506be8be8b6f1de2423ecab6413b31e3cb0ce58c/bacon.toml#L73-L169. This PR does not directly help in simplifying this, but it’s a relatively simple extension to allow options with dynamic values (none/staging/all) or to allow options in other fields than command (in this case watch and default_watch).

Most bacon.toml files that I looked at wouldn’t gain anything from this feature though, so it’s probably rather niche.

narpfel avatar Jun 01 '25 16:06 narpfel