@@ -1592,4 +1592,249 @@ func TestDSR996ColorSchemeQuery(t *testing.T) {
15921592 })
15931593}
15941594
1595+ func TestWindowOptionsTitleStackLimit (t * testing.T ) {
1596+ t .Parallel ()
1597+
1598+ t .Run ("title_stack_capped_at_10" , func (t * testing.T ) {
1599+ t .Parallel ()
1600+ h := newTestInputHandler (80 , 24 )
1601+
1602+ // Set and push 15 titles.
1603+ for i := 0 ; i < 15 ; i ++ {
1604+ h .ParseString ("\x1b ]2;title\x07 " )
1605+ h .ParseString ("\x1b [22;2t" ) // push title
1606+ }
1607+
1608+ // Pop all — should get at most 10.
1609+ popCount := 0
1610+ for i := 0 ; i < 15 ; i ++ {
1611+ fired := false
1612+ d := h .OnTitleChangeEmitter .Event (func (s string ) { fired = true })
1613+ h .ParseString ("\x1b [23;2t" ) // pop title
1614+ if fired {
1615+ popCount ++
1616+ }
1617+ d .Dispose ()
1618+ }
1619+ if popCount != titleStackLimit {
1620+ t .Errorf ("popped %d titles, want exactly %d" , popCount , titleStackLimit )
1621+ }
1622+ })
1623+
1624+ t .Run ("icon_name_stack_capped_at_10" , func (t * testing.T ) {
1625+ t .Parallel ()
1626+ h := newTestInputHandler (80 , 24 )
1627+
1628+ // Set and push 15 icon names.
1629+ for i := 0 ; i < 15 ; i ++ {
1630+ h .ParseString ("\x1b ]1;icon\x07 " )
1631+ h .ParseString ("\x1b [22;1t" ) // push icon name
1632+ }
1633+
1634+ // Pop all — should get at most 10.
1635+ popCount := 0
1636+ for i := 0 ; i < 15 ; i ++ {
1637+ fired := false
1638+ d := h .OnIconNameChangeEmitter .Event (func (s string ) { fired = true })
1639+ h .ParseString ("\x1b [23;1t" ) // pop icon name
1640+ if fired {
1641+ popCount ++
1642+ }
1643+ d .Dispose ()
1644+ }
1645+ if popCount != titleStackLimit {
1646+ t .Errorf ("popped %d icon names, want exactly %d" , popCount , titleStackLimit )
1647+ }
1648+ })
1649+
1650+ t .Run ("both_stacks_capped_at_10" , func (t * testing.T ) {
1651+ t .Parallel ()
1652+ h := newTestInputHandler (80 , 24 )
1653+
1654+ // Push 12 entries for both title and icon name (ps2=0).
1655+ for i := 0 ; i < 12 ; i ++ {
1656+ h .ParseString ("\x1b ]0;both\x07 " ) // OSC 0 sets both
1657+ h .ParseString ("\x1b [22;0t" ) // push both
1658+ }
1659+
1660+ titlePops := 0
1661+ iconPops := 0
1662+ for i := 0 ; i < 12 ; i ++ {
1663+ tFired := false
1664+ iFired := false
1665+ dt := h .OnTitleChangeEmitter .Event (func (s string ) { tFired = true })
1666+ di := h .OnIconNameChangeEmitter .Event (func (s string ) { iFired = true })
1667+ h .ParseString ("\x1b [23;0t" ) // pop both
1668+ if tFired {
1669+ titlePops ++
1670+ }
1671+ if iFired {
1672+ iconPops ++
1673+ }
1674+ dt .Dispose ()
1675+ di .Dispose ()
1676+ }
1677+ if titlePops != titleStackLimit {
1678+ t .Errorf ("title pops = %d, want %d" , titlePops , titleStackLimit )
1679+ }
1680+ if iconPops != titleStackLimit {
1681+ t .Errorf ("icon pops = %d, want %d" , iconPops , titleStackLimit )
1682+ }
1683+ })
1684+
1685+ t .Run ("stack_preserves_most_recent_entries" , func (t * testing.T ) {
1686+ t .Parallel ()
1687+ h := newTestInputHandler (80 , 24 )
1688+
1689+ // Push 12 titles with distinct values; the first 2 should be evicted.
1690+ for i := 0 ; i < 12 ; i ++ {
1691+ h .ParseString ("\x1b ]2;t" + string (rune ('A' + i )) + "\x07 " )
1692+ h .ParseString ("\x1b [22;2t" )
1693+ }
1694+
1695+ // Pop returns from top of stack (most recent push first).
1696+ // Pushed: tA tB tC tD tE tF tG tH tI tJ tK tL
1697+ // After trim: tC tD tE tF tG tH tI tJ tK tL (oldest 2 evicted)
1698+ // Pop order: tL, tK, tJ, ...
1699+ var got string
1700+ d := h .OnTitleChangeEmitter .Event (func (s string ) { got = s })
1701+ h .ParseString ("\x1b [23;2t" )
1702+ d .Dispose ()
1703+
1704+ expected := "tL"
1705+ if got != expected {
1706+ t .Errorf ("first pop = %q, want %q" , got , expected )
1707+ }
1708+ })
1709+ }
1710+
1711+ func TestWindowOptionsCSI14t (t * testing.T ) {
1712+ t .Parallel ()
1713+
1714+ t .Run ("fires_GetWinSizePixels" , func (t * testing.T ) {
1715+ t .Parallel ()
1716+ h := newTestInputHandler (80 , 24 )
1717+
1718+ var got WindowsOptionsReportType
1719+ fired := false
1720+ d := h .OnRequestWindowsOptionsReportEmitter .Event (func (rt WindowsOptionsReportType ) {
1721+ fired = true
1722+ got = rt
1723+ })
1724+ defer d .Dispose ()
1725+
1726+ h .ParseString ("\x1b [14t" )
1727+ if ! fired {
1728+ t .Fatal ("OnRequestWindowsOptionsReport not fired for CSI 14 t" )
1729+ }
1730+ if got != GetWinSizePixels {
1731+ t .Errorf ("report type = %d, want GetWinSizePixels (%d)" , got , GetWinSizePixels )
1732+ }
1733+ })
1734+
1735+ t .Run ("ps2_not_2_fires_GetWinSizePixels" , func (t * testing.T ) {
1736+ t .Parallel ()
1737+ h := newTestInputHandler (80 , 24 )
1738+
1739+ fired := false
1740+ d := h .OnRequestWindowsOptionsReportEmitter .Event (func (rt WindowsOptionsReportType ) {
1741+ fired = true
1742+ })
1743+ defer d .Dispose ()
1744+
1745+ h .ParseString ("\x1b [14;1t" )
1746+ if ! fired {
1747+ t .Fatal ("OnRequestWindowsOptionsReport not fired for CSI 14;1 t" )
1748+ }
1749+ })
1750+
1751+ t .Run ("ps2_eq_2_does_not_fire" , func (t * testing.T ) {
1752+ t .Parallel ()
1753+ h := newTestInputHandler (80 , 24 )
1754+
1755+ fired := false
1756+ d := h .OnRequestWindowsOptionsReportEmitter .Event (func (rt WindowsOptionsReportType ) {
1757+ fired = true
1758+ })
1759+ defer d .Dispose ()
1760+
1761+ h .ParseString ("\x1b [14;2t" )
1762+ if fired {
1763+ t .Error ("OnRequestWindowsOptionsReport should not fire for CSI 14;2 t" )
1764+ }
1765+ })
1766+ }
1767+
1768+ func TestWindowOptionsCSI16t (t * testing.T ) {
1769+ t .Parallel ()
1770+
1771+ t .Run ("fires_GetCellSizePixels" , func (t * testing.T ) {
1772+ t .Parallel ()
1773+ h := newTestInputHandler (80 , 24 )
1774+
1775+ var got WindowsOptionsReportType
1776+ fired := false
1777+ d := h .OnRequestWindowsOptionsReportEmitter .Event (func (rt WindowsOptionsReportType ) {
1778+ fired = true
1779+ got = rt
1780+ })
1781+ defer d .Dispose ()
1782+
1783+ h .ParseString ("\x1b [16t" )
1784+ if ! fired {
1785+ t .Fatal ("OnRequestWindowsOptionsReport not fired for CSI 16 t" )
1786+ }
1787+ if got != GetCellSizePixels {
1788+ t .Errorf ("report type = %d, want GetCellSizePixels (%d)" , got , GetCellSizePixels )
1789+ }
1790+ })
1791+ }
1792+
1793+ func TestWindowOptionsReportTerminalLevel (t * testing.T ) {
1794+ t .Parallel ()
1795+
1796+ t .Run ("CSI_14t_forwarded_to_terminal" , func (t * testing.T ) {
1797+ t .Parallel ()
1798+ term := newTestTerminal (80 , 24 )
1799+ defer term .Dispose ()
1800+
1801+ var got WindowsOptionsReportType
1802+ fired := false
1803+ d := term .OnRequestWindowsOptionsReport (func (rt WindowsOptionsReportType ) {
1804+ fired = true
1805+ got = rt
1806+ })
1807+ defer d .Dispose ()
1808+
1809+ term .WriteString ("\x1b [14t" )
1810+ if ! fired {
1811+ t .Fatal ("Terminal.OnRequestWindowsOptionsReport not fired for CSI 14 t" )
1812+ }
1813+ if got != GetWinSizePixels {
1814+ t .Errorf ("report type = %d, want GetWinSizePixels (%d)" , got , GetWinSizePixels )
1815+ }
1816+ })
1817+
1818+ t .Run ("CSI_16t_forwarded_to_terminal" , func (t * testing.T ) {
1819+ t .Parallel ()
1820+ term := newTestTerminal (80 , 24 )
1821+ defer term .Dispose ()
1822+
1823+ var got WindowsOptionsReportType
1824+ fired := false
1825+ d := term .OnRequestWindowsOptionsReport (func (rt WindowsOptionsReportType ) {
1826+ fired = true
1827+ got = rt
1828+ })
1829+ defer d .Dispose ()
1830+
1831+ term .WriteString ("\x1b [16t" )
1832+ if ! fired {
1833+ t .Fatal ("Terminal.OnRequestWindowsOptionsReport not fired for CSI 16 t" )
1834+ }
1835+ if got != GetCellSizePixels {
1836+ t .Errorf ("report type = %d, want GetCellSizePixels (%d)" , got , GetCellSizePixels )
1837+ }
1838+ })
1839+ }
15951840
0 commit comments