@@ -301,6 +301,23 @@ <h3>📜 Scrolling Features</h3>
301301 </ div >
302302 </ div >
303303
304+ < div class ="feature-panel ">
305+ < h3 > 🔍 Buffer Access API (NEW!)</ h3 >
306+ < div class ="button-grid ">
307+ < button class ="test-button " id ="btn-testAlternateScreen "> 🔄 Test Alternate Screen</ button >
308+ < button class ="test-button " id ="btn-testWrapping "> 📏 Test Line Wrapping</ button >
309+ < button class ="test-button " id ="btn-testEdgeCases "> ⚠️ Test Edge Cases</ button >
310+ < button class ="test-button " id ="btn-showBufferInfo "> ℹ️ Show Buffer Info</ button >
311+ </ div >
312+ < div >
313+ < strong style ="display: block; margin-bottom: 8px "> API Test Results:</ strong >
314+ < div class ="event-log " id ="buffer-api-log ">
315+ < div style ="opacity: 0.5; text-align: center "> Test results will appear here...</ div >
316+ </ div >
317+ < button class ="clear-log " id ="btn-clear-buffer-log "> Clear Results</ button >
318+ </ div >
319+ </ div >
320+
304321 < div class ="warning ">
305322 < strong > ⚠️ Warning: Full Filesystem Access</ strong >
306323 This demo has unrestricted access to your entire filesystem. It's meant for local
@@ -692,6 +709,167 @@ <h3>📜 Scrolling Features</h3>
692709 } , 100 ) ;
693710 } ) ;
694711
712+ // =========================================================================
713+ // Buffer Access API Handlers (NEW!)
714+ // =========================================================================
715+
716+ function logBufferEvent ( message , isSuccess = true ) {
717+ const bufferLog = document . getElementById ( 'buffer-api-log' ) ;
718+ const eventDiv = document . createElement ( 'div' ) ;
719+ eventDiv . className = 'event' ;
720+ eventDiv . innerHTML = `
721+ <span class="event-type" style="color: ${ isSuccess ? '#4caf50' : '#ff9800' } ">${ isSuccess ? '✓' : '→' } </span>
722+ <span class="event-data">${ message } </span>
723+ ` ;
724+ bufferLog . appendChild ( eventDiv ) ;
725+ bufferLog . scrollTop = bufferLog . scrollHeight ;
726+ }
727+
728+ document . getElementById ( 'btn-clear-buffer-log' ) . addEventListener ( 'click' , ( ) => {
729+ const bufferLog = document . getElementById ( 'buffer-api-log' ) ;
730+ bufferLog . innerHTML =
731+ '<div style="opacity: 0.5; text-align: center">Test results will appear here...</div>' ;
732+ } ) ;
733+
734+ document . getElementById ( 'btn-testAlternateScreen' ) . addEventListener ( 'click' , async ( ) => {
735+ const bufferLog = document . getElementById ( 'buffer-api-log' ) ;
736+ bufferLog . innerHTML = '' ; // Clear log
737+
738+ logBufferEvent ( 'Testing alternate screen detection...' , false ) ;
739+
740+ // Check initial state
741+ const initial = term . wasmTerm ?. isAlternateScreen ( ) ;
742+ logBufferEvent (
743+ `Initial (normal mode): ${ initial === false ? '✓ PASS' : '✗ FAIL' } (${ initial } )`
744+ ) ;
745+
746+ // Enter alternate screen
747+ term . write ( '\x1b[?1049h' ) ;
748+ term . write ( '\x1b[2J\x1b[H' ) ; // Clear and home
749+ term . write ( '\x1b[1;32m╔════════════════════════════════════════╗\r\n' ) ;
750+ term . write ( '║ ALTERNATE SCREEN MODE ACTIVE ║\r\n' ) ;
751+ term . write ( '║ (Like vim/less/htop) ║\r\n' ) ;
752+ term . write ( '║ ║\r\n' ) ;
753+ term . write ( '║ Normal buffer is preserved! ║\r\n' ) ;
754+ term . write ( '║ Exiting in 3 seconds... ║\r\n' ) ;
755+ term . write ( '╚════════════════════════════════════════╝\x1b[0m\r\n' ) ;
756+
757+ const inAlt = term . wasmTerm ?. isAlternateScreen ( ) ;
758+ logBufferEvent ( `In alternate mode: ${ inAlt === true ? '✓ PASS' : '✗ FAIL' } (${ inAlt } )` ) ;
759+
760+ // Exit after delay
761+ await new Promise ( ( r ) => setTimeout ( r , 3000 ) ) ;
762+ term . write ( '\x1b[?1049l' ) ;
763+
764+ const afterExit = term . wasmTerm ?. isAlternateScreen ( ) ;
765+ logBufferEvent (
766+ `After exit (normal mode): ${ afterExit === false ? '✓ PASS' : '✗ FAIL' } (${ afterExit } )`
767+ ) ;
768+
769+ if ( initial === false && inAlt === true && afterExit === false ) {
770+ logBufferEvent ( '🎉 All alternate screen tests PASSED!' , true ) ;
771+ }
772+ } ) ;
773+
774+ document . getElementById ( 'btn-testWrapping' ) . addEventListener ( 'click' , ( ) => {
775+ const bufferLog = document . getElementById ( 'buffer-api-log' ) ;
776+ bufferLog . innerHTML = '' ; // Clear log
777+
778+ logBufferEvent ( 'Testing line wrapping detection...' , false ) ;
779+
780+ term . write ( '\x1b[2J\x1b[H' ) ; // Clear screen
781+
782+ // Write short lines (no wrap)
783+ term . write ( 'Short line 1\r\n' ) ;
784+ term . write ( 'Short line 2\r\n' ) ;
785+
786+ const row0 = term . wasmTerm ?. isRowWrapped ( 0 ) ;
787+ const row1 = term . wasmTerm ?. isRowWrapped ( 1 ) ;
788+ logBufferEvent (
789+ `Row 0 (short line): ${ row0 === false ? '✓ PASS' : '✗ FAIL' } (wrapped=${ row0 } )`
790+ ) ;
791+ logBufferEvent (
792+ `Row 1 (short line): ${ row1 === false ? '✓ PASS' : '✗ FAIL' } (wrapped=${ row1 } )`
793+ ) ;
794+
795+ // Write long line that wraps
796+ term . write (
797+ '\x1b[33mThis is a very long line that will definitely wrap to the next line because it is much longer than the terminal width allows for a single line of text!\x1b[0m\r\n'
798+ ) ;
799+
800+ // Check wrapping (row 2 starts long line, row 3+ are continuations)
801+ const results = [ ] ;
802+ for ( let i = 2 ; i < 6 ; i ++ ) {
803+ const wrapped = term . wasmTerm ?. isRowWrapped ( i ) ;
804+ results . push ( { row : i , wrapped } ) ;
805+ logBufferEvent (
806+ `Row ${ i } : ${ wrapped ? 'WRAPPED ↪' : 'NEW LINE ↓' } (wrapped=${ wrapped } )`
807+ ) ;
808+ }
809+
810+ const row2correct = results [ 0 ] . wrapped === false ; // Start of line
811+ const row3correct = results [ 1 ] . wrapped === true ; // Continuation
812+
813+ if ( row0 === false && row1 === false && row2correct && row3correct ) {
814+ logBufferEvent ( '🎉 Line wrapping tests PASSED!' , true ) ;
815+ }
816+ } ) ;
817+
818+ document . getElementById ( 'btn-testEdgeCases' ) . addEventListener ( 'click' , ( ) => {
819+ const bufferLog = document . getElementById ( 'buffer-api-log' ) ;
820+ bufferLog . innerHTML = '' ; // Clear log
821+
822+ logBufferEvent ( 'Testing edge cases...' , false ) ;
823+
824+ // Row 0 can never be wrapped
825+ const row0 = term . wasmTerm ?. isRowWrapped ( 0 ) ;
826+ logBufferEvent ( `Row 0 (never wraps): ${ row0 === false ? '✓ PASS' : '✗ FAIL' } (${ row0 } )` ) ;
827+
828+ // Negative row
829+ const negRow = term . wasmTerm ?. isRowWrapped ( - 1 ) ;
830+ logBufferEvent ( `Row -1 (invalid): ${ negRow === false ? '✓ PASS' : '✗ FAIL' } (${ negRow } )` ) ;
831+
832+ // Out of bounds
833+ const largeRow = term . wasmTerm ?. isRowWrapped ( 9999 ) ;
834+ logBufferEvent (
835+ `Row 9999 (out of bounds): ${ largeRow === false ? '✓ PASS' : '✗ FAIL' } (${ largeRow } )`
836+ ) ;
837+
838+ if ( row0 === false && negRow === false && largeRow === false ) {
839+ logBufferEvent ( '🎉 All edge case tests PASSED!' , true ) ;
840+ }
841+ } ) ;
842+
843+ document . getElementById ( 'btn-showBufferInfo' ) . addEventListener ( 'click' , ( ) => {
844+ const bufferLog = document . getElementById ( 'buffer-api-log' ) ;
845+ bufferLog . innerHTML = '' ; // Clear log
846+
847+ logBufferEvent ( '📊 Current Buffer Information:' , false ) ;
848+
849+ const isAlt = term . wasmTerm ?. isAlternateScreen ( ) ;
850+ const mode = isAlt
851+ ? 'Alternate Screen (vim/less/htop mode)'
852+ : 'Normal Screen (shell mode)' ;
853+ logBufferEvent ( `Screen Mode: ${ mode } ` , true ) ;
854+
855+ logBufferEvent ( `Terminal Size: ${ term . cols } x${ term . rows } ` , true ) ;
856+
857+ // Check wrapping for visible rows
858+ let wrappedCount = 0 ;
859+ for ( let i = 0 ; i < term . rows ; i ++ ) {
860+ if ( term . wasmTerm ?. isRowWrapped ( i ) ) {
861+ wrappedCount ++ ;
862+ }
863+ }
864+ logBufferEvent ( `Wrapped Rows: ${ wrappedCount } /${ term . rows } visible rows` , true ) ;
865+
866+ // Show first 10 rows wrap status
867+ logBufferEvent ( 'First 10 rows wrap status:' , false ) ;
868+ for ( let i = 0 ; i < Math . min ( 10 , term . rows ) ; i ++ ) {
869+ const wrapped = term . wasmTerm ?. isRowWrapped ( i ) ;
870+ logBufferEvent ( ` Row ${ i } : ${ wrapped ? '↪ wrapped' : '↓ new line' } ` , true ) ;
871+ }
872+ } ) ;
695873 // Expose terminal to console for debugging
696874 window . term = term ;
697875 }
0 commit comments