@@ -109,4 +109,129 @@ mod tests {
109109 assert ! ( !content. contains( "\x1b [31m" ) ) ;
110110 assert ! ( !content. contains( "[31m" ) ) ;
111111 }
112+
113+ // =========================================================================
114+ // Alternate screen integration tests (simulating vim/vi behavior)
115+ // =========================================================================
116+
117+ /// When entering alternate screen, only alternate content should be visible
118+ #[ test]
119+ fn test_alternate_screen_shows_only_alternate_content ( ) {
120+ let mut buf = ScrollbackBuffer :: new ( ) ;
121+
122+ // Write content to main screen
123+ buf. push ( b"main line 1\r \n main line 2\r \n main line 3" ) ;
124+
125+ // Enter alternate screen (like vim does)
126+ buf. push ( b"\x1b [?1049h" ) ;
127+
128+ // Write content to alternate screen
129+ buf. push ( b"alternate content here" ) ;
130+
131+ // Should show ONLY alternate content, NOT main content
132+ let content = buf. get_lines ( None ) ;
133+ assert ! (
134+ content. contains( "alternate content here" ) ,
135+ "should contain alternate content"
136+ ) ;
137+ assert ! (
138+ !content. contains( "main line 1" ) ,
139+ "should NOT contain main screen content when in alternate mode"
140+ ) ;
141+ assert ! (
142+ !content. contains( "main line 2" ) ,
143+ "should NOT contain main screen content when in alternate mode"
144+ ) ;
145+ }
146+
147+ /// Simulates vim workflow: enter alternate, show file, exit, restore main
148+ #[ test]
149+ fn test_vim_like_workflow ( ) {
150+ let mut buf = ScrollbackBuffer :: new ( ) ;
151+
152+ // User types some commands in shell
153+ buf. push ( b"$ ls -la\r \n file1.txt\r \n file2.txt\r \n $ vim file1.txt\r \n " ) ;
154+
155+ // Vim enters alternate screen
156+ buf. push ( b"\x1b [?1049h" ) ;
157+
158+ // Vim shows file content (simplified)
159+ buf. push ( b"Hello from file1.txt\r \n This is vim editing mode" ) ;
160+
161+ // While in vim, should only see vim content
162+ let content_in_vim = buf. get_lines ( None ) ;
163+ assert ! ( content_in_vim. contains( "Hello from file1.txt" ) ) ;
164+ assert ! (
165+ !content_in_vim. contains( "$ ls -la" ) ,
166+ "shell history should not be visible while in vim"
167+ ) ;
168+
169+ // User exits vim (:q)
170+ buf. push ( b"\x1b [?1049l" ) ;
171+
172+ // Back to main screen, should see original shell content
173+ let content_after_vim = buf. get_lines ( None ) ;
174+ assert ! (
175+ content_after_vim. contains( "$ ls -la" ) ,
176+ "shell history should be restored after exiting vim"
177+ ) ;
178+ assert ! (
179+ content_after_vim. contains( "file1.txt" ) ,
180+ "ls output should be visible after exiting vim"
181+ ) ;
182+ }
183+
184+ /// Test multiple alternate screen enter/exit cycles
185+ #[ test]
186+ fn test_multiple_alternate_screen_cycles ( ) {
187+ let mut buf = ScrollbackBuffer :: new ( ) ;
188+
189+ // Initial main screen content
190+ buf. push ( b"session start\r \n " ) ;
191+
192+ for i in 1 ..=3 {
193+ // Enter alternate screen
194+ buf. push ( b"\x1b [?1049h" ) ;
195+ buf. push ( format ! ( "editor session {i}" ) . as_bytes ( ) ) ;
196+
197+ // Should only see current editor session
198+ let in_alt = buf. get_lines ( None ) ;
199+ assert ! ( in_alt. contains( & format!( "editor session {i}" ) ) ) ;
200+ assert ! ( !in_alt. contains( "session start" ) ) ;
201+
202+ // Exit alternate screen
203+ buf. push ( b"\x1b [?1049l" ) ;
204+
205+ // Should be back to main
206+ let in_main = buf. get_lines ( None ) ;
207+ assert ! ( in_main. contains( "session start" ) ) ;
208+ }
209+ }
210+
211+ /// Test that alternate screen content is isolated
212+ #[ test]
213+ fn test_alternate_screen_isolation ( ) {
214+ let mut buf = ScrollbackBuffer :: new ( ) ;
215+
216+ // Main screen has scrollback history
217+ for i in 1 ..=50 {
218+ buf. push ( format ! ( "history line {i}\r \n " ) . as_bytes ( ) ) ;
219+ }
220+
221+ // Enter alternate screen (TUI app)
222+ buf. push ( b"\x1b [?1049h" ) ;
223+ buf. push ( b"TUI application interface" ) ;
224+
225+ // Alt-e equivalent: get_lines should return ONLY the TUI content
226+ let content = buf. get_lines ( None ) ;
227+ assert ! ( content. contains( "TUI application interface" ) ) ;
228+ assert ! (
229+ !content. contains( "history line 1" ) ,
230+ "scrollback history should not leak into alternate screen view"
231+ ) ;
232+ assert ! (
233+ !content. contains( "history line 50" ) ,
234+ "scrollback history should not leak into alternate screen view"
235+ ) ;
236+ }
112237}
0 commit comments