Skip to content

Conversation

hanoii
Copy link

@hanoii hanoii commented Jun 9, 2025

Note

I run this PR almost entirely through IA (Augment code). I am familiar with GO and all so thought it was a simple way to test drive it a bit, which I am recently doing. Nice take I think. Commit messages and PR description included.

  • Add --initial option to both choose and filter commands for setting initial cursor position
  • Fix critical bug in filter command where --selected with limit=1 would lock selection
  • When limit=1, --selected now behaves like cursor positioning (same as choose command)
  • Add comprehensive tests for initial positioning logic
  • Support environment variables GUM_CHOOSE_INITIAL and GUM_FILTER_INITIAL

Resolves #337

Changes:

  • choose: Add --initial option for cursor positioning (useful with --no-limit)
  • filter: Add --initial option and fix --selected behavior with limit=1
  • Both commands now have consistent behavior for --selected when limit=1
  • Tests added to ensure correct cursor positioning logic

…lected bug

- Add --initial option to both choose and filter commands for setting initial cursor position
- Fix critical bug in filter command where --selected with limit=1 would lock selection
- When limit=1, --selected now behaves like cursor positioning (same as choose command)
- Add comprehensive tests for initial positioning logic
- Support environment variables GUM_CHOOSE_INITIAL and GUM_FILTER_INITIAL

Resolves charmbracelet#337

Changes:
- choose: Add --initial option for cursor positioning (useful with --no-limit)
- filter: Add --initial option and fix --selected behavior with limit=1
- Both commands now have consistent behavior for --selected when limit=1
- Tests added to ensure correct cursor positioning logic

Breaking changes: None
Backward compatibility: Fully maintained
@hanoii hanoii requested a review from a team as a code owner June 9, 2025 15:50
@hanoii hanoii requested review from raphamorim and removed request for a team June 9, 2025 15:50
Copy link
Contributor

@sadamczyk sadamczyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking a try at this!
In general it seemed to be doing exactly what I wanted, which is great! :)


for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Simulate the logic from command.go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this test is very useful as it is, because it doesn't actually test the code running in the command, it just "simulates" it. If the command changes, this test will happily keep reporting a successful test.

Honestly, I would probably just remove both of the tests. There currently aren't many tests in this repo to begin with and adding them in this PR doesn't feel like the right place to start, especially because the structure of the code for the commands makes it kind of difficult to test only small parts of the functionality like this.
There is an open issue regarding adding tests: #818

Comment on lines 134 to +136
if o.Limit == 1 {
// When the user can choose only one option don't select the option but
// start with the cursor hovering over it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if o.Limit == 1 {
// When the user can choose only one option don't select the option but
// start with the cursor hovering over it.
if o.Initial != "" && option.Str == o.Initial {

Currently --selected has two different behaviors.

  1. If --no-limit or --limit=<any value above 1> then the cursor position isn't changed at all. This can stay.
  2. If --limit=1 (the default), then it only sets the initial cursor position. But that's exactly what the new option --initial does, so it does not make much sense to me to keep this behavior of --selected around. Because then there would be two ways to do the exact same thing, which seems confusing.
    This also saves us from having to loop over all the options again in the second loop, so that can be removed.

This would be a significant BC break though, because I imagine a lot of people rely on this behavior of --selected because it's the default. So it might be better to deprecate this behavior of --selected first, before just outright removing it.

@@ -21,6 +21,7 @@ type Options struct {
SelectedPrefix string `help:"Prefix to show on selected items (hidden if limit is 1)" default:"✓ " env:"GUM_CHOOSE_SELECTED_PREFIX"`
UnselectedPrefix string `help:"Prefix to show on unselected items (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_UNSELECTED_PREFIX"`
Selected []string `help:"Options that should start as selected (selects all if given *)" default:"" env:"GUM_CHOOSE_SELECTED"`
Initial string `help:"Option that should start with the cursor positioned on it" default:"" env:"GUM_CHOOSE_INITIAL"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally feel like --cursor might be the better name for this new option.
Especially in combination with --selected it communicates very clearly that it only affects the cursor position, whereas --inital feels a little ambigous to me.
But as always naming things is one of the hardest problems :), so I'd be curious to hear other people's input on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Filter/Choose: Set starting position of indicator by value
2 participants