mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-11-12 15:53:33 -04:00
Add support for pasting text in integration tests
The commit message panel handles pasted text differently from typed
text (see ba6cfc1f85), but integration tests couldn't simulate a
paste, so this had no tests. Let tests replay the events that a
terminal sends for a bracketed paste: the start of the paste, a key
press for each character, and the end of the paste.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b65298c3b1
commit
dec9e49162
@@ -119,6 +119,7 @@ type replayedEvents struct {
|
||||
Resizes chan *TcellResizeEventWrapper
|
||||
MouseEvents chan *TcellMouseEventWrapper
|
||||
FocusEvents chan *TcellFocusEventWrapper
|
||||
PasteEvents chan *TcellPasteEventWrapper
|
||||
}
|
||||
|
||||
type RecordingConfig struct {
|
||||
@@ -305,6 +306,7 @@ func NewGui(opts NewGuiOpts) (*Gui, error) {
|
||||
Resizes: make(chan *TcellResizeEventWrapper),
|
||||
MouseEvents: make(chan *TcellMouseEventWrapper),
|
||||
FocusEvents: make(chan *TcellFocusEventWrapper),
|
||||
PasteEvents: make(chan *TcellPasteEventWrapper),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +386,13 @@ func (g *Gui) ReplayFocusEvent(ev *TcellFocusEventWrapper) {
|
||||
g.replayedEvents.FocusEvents <- ev
|
||||
}
|
||||
|
||||
// ReplayPasteEvent is like ReplayKeyEvent, but for the events that mark the
|
||||
// start and the end of a paste.
|
||||
func (g *Gui) ReplayPasteEvent(ev *TcellPasteEventWrapper) {
|
||||
ev.task = g.NewTask()
|
||||
g.replayedEvents.PasteEvents <- ev
|
||||
}
|
||||
|
||||
// Busy reports whether any foreground work is in flight, ignoring the event
|
||||
// currently being processed on the main goroutine (see currentTask). Background
|
||||
// routines (auto-fetch etc.) don't count. It's used to decide whether it's safe
|
||||
|
||||
@@ -302,6 +302,22 @@ func (wrapper TcellFocusEventWrapper) toTcellEvent() tcell.Event {
|
||||
return tcell.NewEventFocus(wrapper.Focused)
|
||||
}
|
||||
|
||||
type TcellPasteEventWrapper struct {
|
||||
Start bool
|
||||
|
||||
task Task // see GocuiEvent.task
|
||||
}
|
||||
|
||||
func NewTcellPasteEventWrapper(event *tcell.EventPaste) *TcellPasteEventWrapper {
|
||||
return &TcellPasteEventWrapper{
|
||||
Start: event.Start(),
|
||||
}
|
||||
}
|
||||
|
||||
func (wrapper TcellPasteEventWrapper) toTcellEvent() tcell.Event {
|
||||
return tcell.NewEventPaste(wrapper.Start)
|
||||
}
|
||||
|
||||
// pollEvent get tcell.Event and transform it into gocuiEvent
|
||||
func (g *Gui) pollEvent() GocuiEvent {
|
||||
var tev tcell.Event
|
||||
@@ -319,6 +335,9 @@ func (g *Gui) pollEvent() GocuiEvent {
|
||||
case ev := <-g.replayedEvents.FocusEvents:
|
||||
tev = ev.toTcellEvent()
|
||||
task = ev.task
|
||||
case ev := <-g.replayedEvents.PasteEvents:
|
||||
tev = ev.toTcellEvent()
|
||||
task = ev.task
|
||||
}
|
||||
} else {
|
||||
tev = <-Screen.EventQ()
|
||||
|
||||
@@ -138,6 +138,31 @@ func (self *GuiDriver) FocusIn() {
|
||||
self.waitTillIdle()
|
||||
}
|
||||
|
||||
// Paste sends the events that a terminal with bracketed paste mode sends: the
|
||||
// start of the paste, a key press for each character, and the end of the paste.
|
||||
func (self *GuiDriver) Paste(text string) {
|
||||
self.CheckAllToastsAcknowledged()
|
||||
|
||||
self.gui.g.ReplayPasteEvent(gocui.NewTcellPasteEventWrapper(tcell.NewEventPaste(true)))
|
||||
for _, char := range text {
|
||||
self.gui.g.ReplayKeyEvent(gocui.NewTcellKeyEventWrapper(keyEventForPastedCharacter(char)))
|
||||
}
|
||||
self.gui.g.ReplayPasteEvent(gocui.NewTcellPasteEventWrapper(tcell.NewEventPaste(false)))
|
||||
|
||||
self.waitTillIdle()
|
||||
}
|
||||
|
||||
func keyEventForPastedCharacter(char rune) *tcell.EventKey {
|
||||
switch char {
|
||||
case '\n':
|
||||
return tcell.NewEventKey(tcell.KeyEnter, "", tcell.ModNone)
|
||||
case '\t':
|
||||
return tcell.NewEventKey(tcell.KeyTab, "", tcell.ModNone)
|
||||
default:
|
||||
return tcell.NewEventKey(tcell.KeyRune, string(char), tcell.ModNone)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *GuiDriver) FocusInAndClick(x, y int) {
|
||||
self.CheckAllToastsAcknowledged()
|
||||
|
||||
|
||||
@@ -21,6 +21,14 @@ func (self *CommitDescriptionPanelDriver) Type(value string) *CommitDescriptionP
|
||||
return self
|
||||
}
|
||||
|
||||
// Paste the text the way a terminal does it, as opposed to pasting it with the
|
||||
// commit menu
|
||||
func (self *CommitDescriptionPanelDriver) Paste(text string) *CommitDescriptionPanelDriver {
|
||||
self.t.paste(text)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *CommitDescriptionPanelDriver) SwitchToSummary() *CommitMessagePanelDriver {
|
||||
self.getViewDriver().PressTab()
|
||||
return &CommitMessagePanelDriver{t: self.t}
|
||||
|
||||
@@ -33,6 +33,14 @@ func (self *CommitMessagePanelDriver) Type(value string) *CommitMessagePanelDriv
|
||||
return self
|
||||
}
|
||||
|
||||
// Paste the text the way a terminal does it, as opposed to pasting it with the
|
||||
// commit menu
|
||||
func (self *CommitMessagePanelDriver) Paste(text string) *CommitMessagePanelDriver {
|
||||
self.t.paste(text)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *CommitMessagePanelDriver) SwitchToDescription() *CommitDescriptionPanelDriver {
|
||||
self.getViewDriver().PressTab()
|
||||
return &CommitDescriptionPanelDriver{t: self.t}
|
||||
|
||||
@@ -136,6 +136,12 @@ func (self *TestDriver) FocusIn() {
|
||||
self.Wait(self.inputDelay)
|
||||
}
|
||||
|
||||
func (self *TestDriver) paste(text string) {
|
||||
self.SetCaption(fmt.Sprintf("Pasting %q", text))
|
||||
self.gui.Paste(text)
|
||||
self.Wait(self.inputDelay)
|
||||
}
|
||||
|
||||
func (self *TestDriver) focusInAndClick(x, y int) {
|
||||
self.SetCaption(fmt.Sprintf("Focusing window and clicking %d, %d", x, y))
|
||||
self.gui.FocusInAndClick(x, y)
|
||||
|
||||
@@ -84,6 +84,9 @@ func (self *fakeGuiDriver) OnUIThreadAndWait(f func()) {
|
||||
func (self *fakeGuiDriver) FocusIn() {
|
||||
}
|
||||
|
||||
func (self *fakeGuiDriver) Paste(text string) {
|
||||
}
|
||||
|
||||
func (self *fakeGuiDriver) FocusInAndClick(x, y int) {
|
||||
self.clickedCoordinates = append(self.clickedCoordinates, coordinate{x: x, y: y})
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ type GuiDriver interface {
|
||||
// Simulate the terminal window regaining focus (which triggers a reload of
|
||||
// changed config files)
|
||||
FocusIn()
|
||||
// Simulate pasting text in a terminal that supports bracketed paste
|
||||
Paste(string)
|
||||
// Simulate a terminal dispatching focus-in immediately followed by a click,
|
||||
// without waiting for the focus refresh to finish in between.
|
||||
FocusInAndClick(int, int)
|
||||
|
||||
Reference in New Issue
Block a user