Files
MujicaUI/chat/regenerate_menu.go
ZacharyZhang-NYandClaude Opus 5.5 bcce34cda1 Upgrade MyGo to v0.5.5
MyGo v0.5.5 returns ui.Element as a checked value handle instead of a
pointer. Migrated with `mygo migrate-ui`, then fixed what the codemod
leaves to review:

- Element nil checks become .Valid(); absent elements are ui.Element{}.
- Input handlers and paint callbacks run outside the build pass, where
  elements expire and Context methods are inert: read IsDisabled into a
  local during the build, keep a ui.Handle for Focus, use c.Services()
  for clipboard access, create ui.Local state during the build.
- Add core.AutoFocus: v0.5.5 records an overlay's opener after its
  content builds, so same-frame autofocus lost focus restore on close.
  It focuses one frame later; cascader rows defer their focus likewise.
- core.OverlayLayer identifies build passes by the root element, not
  c.Now(), which repeats across passes and under the Tester clock.
- Context menus survive the opening press counted as PressedOutside;
  split button tooltip no longer reorders its open menu; disabled
  menubar rows pass presses to the panel; Form defers blur-started
  async checks so the growing message no longer moves Submit away
  from the release; Combobox drops its disabled copy now that MyGo
  blocks typing under a disabled wrapper (canary flipped to a guard).
- The Tester clock is virtual: tests use Advance/Now instead of
  time.Sleep/time.Now and read element state inside the view. The web
  mirror advances the clock to wall time before each frame and input.
- AGENTS.md and docs describe the value Element API and the new pin.

Snapshot goldens are darwin-only and were not re-verified here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 01:37:54 -04:00

94 lines
2.9 KiB
Go

package chat
import (
"log/slog"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/core"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/icons"
"git.zacharyzhang.com/ZacharyZhang-NY/MujicaUI/overlay"
)
// RegenerateKind is what a RegenerateMenu choice asks for.
type RegenerateKind int
const (
// RegenerateAgain retries with the same model.
RegenerateAgain RegenerateKind = iota
// RegenerateModel retries with Choice.Model.
RegenerateModel
// RegenerateVariant retries asking for Choice.Variant, such as longer or shorter.
RegenerateVariant
)
// RegenerateChoice is the retry the user picked.
type RegenerateChoice struct {
Kind RegenerateKind
Model string
Variant string
}
// RegenerateMenuOptions configure a RegenerateMenu.
type RegenerateMenuOptions struct {
// Models lists models to retry with; Current is left out.
Models []string
Current string
// Variants replaces the built-in Longer, Shorter, Simpler and More detailed.
Variants []string
Disabled bool
}
// RegenerateMenuView is a built menu and the chosen retry.
type RegenerateMenuView struct {
Element ui.Element
Chosen bool
Choice RegenerateChoice
}
// RegenerateMenu offers retry, another model, and rewrite variants.
func RegenerateMenu(c *ui.Context, opts RegenerateMenuOptions) RegenerateMenuView {
variants := opts.Variants
if variants == nil {
for _, key := range []string{"regenerate_menu.longer", "regenerate_menu.shorter", "regenerate_menu.simpler", "regenerate_menu.detailed"} {
variants = append(variants, core.Msg(c, key))
}
}
var v RegenerateMenuView
pick := func(ch RegenerateChoice) { v.Chosen, v.Choice = true, ch }
v.Element = overlay.DropdownMenu(c, core.Msg(c, "regenerate_menu.regenerate"), overlay.DropdownMenuOptions{Icon: icons.Must("refresh-cw"), Disabled: opts.Disabled}, func(m *overlay.PopupMenu) {
if m.Item(core.Msg(c, "regenerate_menu.again"), overlay.PopupMenuItemOptions{}) {
pick(RegenerateChoice{Kind: RegenerateAgain})
}
others := 0
for _, model := range opts.Models {
if model != opts.Current {
others++
}
}
m.Submenu(core.Msg(c, "regenerate_menu.model"), overlay.PopupMenuItemOptions{Disabled: others == 0}, func(m *overlay.PopupMenu) {
for _, model := range opts.Models {
if model != opts.Current && m.Item(model, overlay.PopupMenuItemOptions{}) {
pick(RegenerateChoice{Kind: RegenerateModel, Model: model})
}
}
})
m.Separator()
m.Group(core.Msg(c, "regenerate_menu.variants"), func() {
for _, variant := range variants {
if m.Item(variant, overlay.PopupMenuItemOptions{}) {
pick(RegenerateChoice{Kind: RegenerateVariant, Variant: variant})
}
}
})
})
v.Element.AlignSelf(ui.Start)
if v.Element.IsDisabled() {
v.Chosen = false
}
if v.Chosen {
slog.Debug("mujica: regenerate_menu choose", "kind", v.Choice.Kind, "model", v.Choice.Model, "variant", v.Choice.Variant)
}
return v
}