mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-11 23:40:28 -10:00
* fix(tui): right-click pastes the clipboard directly (no menu) A right-click now pastes the OS clipboard straight into the focused input — composer, provider/MCP wizard, or setup — with no context menu, mirroring the bracketed-paste behavior. Keyboard and selection copy/paste are unchanged. - clipboard.go: pasteFromClipboardCmd reads the clipboard off the Update goroutine; routePaste is the shared router for both bracketed paste (PasteMsg) and right-click paste (clipboardReadMsg), so the two behave identically. - mouse.go: a right-click returns pasteFromClipboardCmd; input_compat.go adds the mouseRightPress helper. - model.go: PasteMsg now routes through routePaste; clipboardReadMsg inserts on success or shows a brief "Paste failed" status when the clipboard can't be read (e.g. no clipboard utility on a remote session). Tests: right-click returns the read command (chat + wizard), clipboard content routes to the focused field, read errors surface a status, empty is a no-op. * fix(tui): right-click paste in setup mode + scope the paste test Setup mode routes mouse events to handleSetupMouse, which only handled left-click and wheel — right-clicks were swallowed, so paste never fired during onboarding. Add the same mouseRightPress -> pasteFromClipboardCmd branch handleMouse uses; routePaste already targets the setup field. Test: assert the right-click contract at handleMouse/handleSetupMouse scope instead of via Update (which batches unrelated commands and masks a regression), and cover the new setup-mode path. Addresses review on #231: mouse.go (setup paste, critical) and clipboard_test.go (weak Update-level assertion, minor).
95 lines
1.9 KiB
Go
95 lines
1.9 KiB
Go
package tui
|
|
|
|
import tea "charm.land/bubbletea/v2"
|
|
|
|
func keyCode(msg tea.KeyMsg) rune {
|
|
return msg.Key().Code
|
|
}
|
|
|
|
func keyText(msg tea.KeyMsg) string {
|
|
return msg.Key().Text
|
|
}
|
|
|
|
func keyRunes(msg tea.KeyMsg) []rune {
|
|
return []rune(keyText(msg))
|
|
}
|
|
|
|
func keyHasMod(msg tea.KeyMsg, mod tea.KeyMod) bool {
|
|
return msg.Key().Mod.Contains(mod)
|
|
}
|
|
|
|
func keyAlt(msg tea.KeyMsg) bool {
|
|
return keyHasMod(msg, tea.ModAlt)
|
|
}
|
|
|
|
func keyShift(msg tea.KeyMsg) bool {
|
|
return keyHasMod(msg, tea.ModShift)
|
|
}
|
|
|
|
func keyIs(msg tea.KeyMsg, code rune) bool {
|
|
return keyCode(msg) == code
|
|
}
|
|
|
|
func keyCtrl(msg tea.KeyMsg, code rune) bool {
|
|
return keyCode(msg) == code && keyHasMod(msg, tea.ModCtrl)
|
|
}
|
|
|
|
func keyCtrlArrow(msg tea.KeyMsg, code rune) bool {
|
|
return keyIs(msg, code) && keyHasMod(msg, tea.ModCtrl)
|
|
}
|
|
|
|
func keyPrintable(msg tea.KeyMsg) bool {
|
|
return keyText(msg) != "" && !keyAlt(msg) && !keyHasMod(msg, tea.ModCtrl)
|
|
}
|
|
|
|
func keyBackspace(msg tea.KeyMsg) bool {
|
|
return keyIs(msg, tea.KeyBackspace) || keyCtrl(msg, 'h')
|
|
}
|
|
|
|
func mouseEvent(msg tea.MouseMsg) tea.Mouse {
|
|
return msg.Mouse()
|
|
}
|
|
|
|
func mouseX(msg tea.MouseMsg) int {
|
|
return mouseEvent(msg).X
|
|
}
|
|
|
|
func mouseY(msg tea.MouseMsg) int {
|
|
return mouseEvent(msg).Y
|
|
}
|
|
|
|
func mouseLeftPress(msg tea.MouseMsg) bool {
|
|
event := mouseEvent(msg)
|
|
return event.Button == tea.MouseLeft && isMouseClick(msg)
|
|
}
|
|
|
|
func mouseRightPress(msg tea.MouseMsg) bool {
|
|
event := mouseEvent(msg)
|
|
return event.Button == tea.MouseRight && isMouseClick(msg)
|
|
}
|
|
|
|
func mouseMotion(msg tea.MouseMsg) bool {
|
|
_, ok := msg.(tea.MouseMotionMsg)
|
|
return ok
|
|
}
|
|
|
|
func mouseRelease(msg tea.MouseMsg) bool {
|
|
_, ok := msg.(tea.MouseReleaseMsg)
|
|
return ok
|
|
}
|
|
|
|
func mouseWheelUp(msg tea.MouseMsg) bool {
|
|
event := mouseEvent(msg)
|
|
return event.Button == tea.MouseWheelUp
|
|
}
|
|
|
|
func mouseWheelDown(msg tea.MouseMsg) bool {
|
|
event := mouseEvent(msg)
|
|
return event.Button == tea.MouseWheelDown
|
|
}
|
|
|
|
func isMouseClick(msg tea.MouseMsg) bool {
|
|
_, ok := msg.(tea.MouseClickMsg)
|
|
return ok
|
|
}
|