@@ -116,6 +116,8 @@ type screenManager struct {
116116 matchPrefix string
117117 hideUnmatched bool
118118 subgridCell * domainGrid.Cell
119+ subgridPointer renderrecursivegrid.VirtualPointerState
120+ subgridOpens int
119121
120122 recursiveGrid recursiveGridDraw
121123 recursiveGridDraws int
@@ -203,8 +205,14 @@ func (m *screenManager) UpdateGridMatches(prefix string) {
203205
204206func (m * screenManager ) SetHideUnmatched (hide bool ) { m .hideUnmatched = hide }
205207
206- func (m * screenManager ) ShowSubgrid (cell * domainGrid.Cell , _ rendergrid.Style ) {
208+ func (m * screenManager ) ShowSubgrid (
209+ cell * domainGrid.Cell ,
210+ _ rendergrid.Style ,
211+ virtualPointer renderrecursivegrid.VirtualPointerState ,
212+ ) {
207213 m .subgridCell = cell
214+ m .subgridPointer = virtualPointer
215+ m .subgridOpens ++
208216}
209217
210218func (m * screenManager ) DrawRecursiveGrid (
@@ -499,7 +507,7 @@ func TestAdapterRedrawFrame_ErasesASubgridTheGridReplaces(t *testing.T) {
499507 t .Fatal ("fixture grid has no cells" )
500508 }
501509
502- adapter .ShowGridSubgrid (cells [0 ])
510+ adapter .ShowGridSubgrid (cells [0 ], ports. GridPointer {} )
503511
504512 err := adapter .RedrawFrame (context .Background (), gridFrame (t , "" ))
505513 if err != nil {
@@ -651,13 +659,59 @@ func TestAdapterGridUpdates_ReachTheOverlayWithoutAFrame(t *testing.T) {
651659 t .Fatal ("fixture grid has no cells" )
652660 }
653661
654- adapter .ShowGridSubgrid (cells [0 ])
662+ adapter .ShowGridSubgrid (cells [0 ], ports. GridPointer {} )
655663
656664 if manager .subgridCell != cells [0 ] {
657665 t .Error ("the subgrid's cell never reached the overlay" )
658666 }
659667}
660668
669+ // TestAdapterShowGridSubgrid_CarriesThePointerIntoTheSameCall is what #1492
670+ // asks of this seam: the keystroke that picks a cell moves the selection too,
671+ // and a backend that paints both into one surface must be told both at once or
672+ // it repaints that surface twice for one key.
673+ //
674+ // The appearance is asserted with the cell, because the pointer travels as
675+ // position alone from a mode: a subgrid open that carried the position and left
676+ // the Style behind would draw the default glyph rather than the user's.
677+ func TestAdapterShowGridSubgrid_CarriesThePointerIntoTheSameCall (t * testing.T ) {
678+ t .Parallel ()
679+
680+ manager := newScreenManager ()
681+ adapter := overlay .NewAdapter (manager , pointerStyles {}, zap .NewNop ())
682+
683+ cells := gridFrame (t , "" ).Grid .Cells ()
684+ if len (cells ) == 0 {
685+ t .Fatal ("fixture grid has no cells" )
686+ }
687+
688+ adapter .ShowGridSubgrid (cells [0 ], ports.GridPointer {
689+ Visible : true ,
690+ Position : image .Pt (120 , 240 ),
691+ })
692+
693+ if manager .subgridOpens != 1 {
694+ t .Fatalf ("subgrid opened %d times, want 1" , manager .subgridOpens )
695+ }
696+
697+ want := renderrecursivegrid.VirtualPointerState {
698+ Visible : true ,
699+ Position : image .Pt (120 , 240 ),
700+ Size : pointerSize ,
701+ FillColor : pointerFill ,
702+ Char : pointerChar ,
703+ FontName : pointerFontFamily ,
704+ }
705+ if manager .subgridPointer != want {
706+ t .Errorf ("subgrid opened with pointer %+v, want %+v" , manager .subgridPointer , want )
707+ }
708+
709+ if manager .pointer .mode != "" {
710+ t .Errorf ("the open also made a pointer call of its own (%+v); one call paints both" ,
711+ manager .pointer )
712+ }
713+ }
714+
661715// TestAdapterUpdateGridPointer_CarriesTheWholeResolvedAppearance pins what a
662716// backend that paints the glyph itself needs and used to be denied: the char
663717// and the font family travel with the size and the fill, so a backend with no
@@ -790,6 +844,47 @@ func TestAdapterClearFrame_TakesTheFrameOffScreen(t *testing.T) {
790844 }
791845}
792846
847+ // TestAdapterClearFrame_DropsWhatTheGridUpdatesLeft is the other half of "content
848+ // and all" (#1492): the hide-unmatched flag and the pointer stand-in outlive a
849+ // clear unless this call drops them, and grid mode used to drop them itself —
850+ // which meant repainting a grid on the way to taking it off the screen.
851+ //
852+ // It is also what makes that free: both run after the surface is cleared, so a
853+ // backend that repaints on a pointer change has nothing left to repaint and its
854+ // own record is already empty. Losing this call would put the flag back on the
855+ // next session's first draw.
856+ func TestAdapterClearFrame_DropsWhatTheGridUpdatesLeft (t * testing.T ) {
857+ t .Parallel ()
858+
859+ manager := newScreenManager ()
860+ adapter := overlay .NewAdapter (manager , pointerStyles {}, zap .NewNop ())
861+
862+ adapter .SetGridHideUnmatched (true )
863+ adapter .UpdateGridPointer (
864+ domain .ModeGrid ,
865+ ports.GridPointer {Visible : true , Position : image .Pt (12 , 34 )},
866+ )
867+
868+ clearErr := adapter .ClearFrame (context .Background ())
869+ if clearErr != nil {
870+ t .Fatalf ("ClearFrame() error = %v" , clearErr )
871+ }
872+
873+ if manager .hideUnmatched {
874+ t .Error ("unmatched cells are still asked to hide after the frame was cleared" )
875+ }
876+
877+ if manager .pointer .mode != overlay .ModeGrid || manager .pointer .visible {
878+ t .Errorf ("grid pointer left as %+v, want it taken off the grid surface" ,
879+ manager .pointer )
880+ }
881+
882+ // The clear comes first, so neither reset had a surface to paint on.
883+ if manager .cleared == 0 {
884+ t .Error ("the surface was never cleared, so the resets ran against a live one" )
885+ }
886+ }
887+
793888// TestAdapterFrame_ReportsACanceledContext keeps a canceled activation from
794889// drawing over whatever replaced it.
795890func TestAdapterFrame_ReportsACanceledContext (t * testing.T ) {
0 commit comments