@@ -31,6 +31,7 @@ export default class TerminalComponent {
3131 scrollOnUserInput : true ,
3232 rows : options . rows || 24 ,
3333 cols : options . cols || 80 ,
34+ port : options . port || 8767 ,
3435 fontSize : terminalSettings . fontSize ,
3536 fontFamily : terminalSettings . fontFamily ,
3637 fontWeight : terminalSettings . fontWeight ,
@@ -128,7 +129,7 @@ export default class TerminalComponent {
128129 let lastKnownScrollPosition = 0 ;
129130 let isResizing = false ;
130131 let resizeCount = 0 ;
131- const RESIZE_DEBOUNCE = 150 ;
132+ const RESIZE_DEBOUNCE = 100 ;
132133 const MAX_RAPID_RESIZES = 3 ;
133134
134135 // Store original dimensions for comparison
@@ -170,8 +171,37 @@ export default class TerminalComponent {
170171 await this . resizeTerminal ( size . cols , size . rows ) ;
171172 }
172173
173- // Preserve scroll position for content-heavy terminals
174- this . preserveViewportPosition ( lastKnownScrollPosition ) ;
174+ // Handle keyboard resize cursor positioning
175+ const heightRatio = size . rows / originalRows ;
176+ if (
177+ heightRatio < 0.75 &&
178+ this . terminal . buffer &&
179+ this . terminal . buffer . active
180+ ) {
181+ // Keyboard resize detected - ensure cursor is visible
182+ const buffer = this . terminal . buffer . active ;
183+ const cursorY = buffer . cursorY ;
184+ const cursorViewportPos = buffer . baseY + cursorY ;
185+ const viewportTop = buffer . viewportY ;
186+ const viewportBottom = viewportTop + this . terminal . rows - 1 ;
187+
188+ if (
189+ cursorViewportPos <= viewportTop + 1 ||
190+ cursorViewportPos >= viewportBottom - 1
191+ ) {
192+ const targetScroll = Math . max (
193+ 0 ,
194+ Math . min (
195+ buffer . length - this . terminal . rows ,
196+ cursorViewportPos - Math . floor ( this . terminal . rows * 0.25 ) ,
197+ ) ,
198+ ) ;
199+ this . terminal . scrollToLine ( targetScroll ) ;
200+ }
201+ } else {
202+ // Regular resize - preserve scroll position
203+ this . preserveViewportPosition ( lastKnownScrollPosition ) ;
204+ }
175205
176206 // Update stored dimensions
177207 originalRows = size . rows ;
@@ -437,8 +467,9 @@ export default class TerminalComponent {
437467 height: 100%;
438468 position: relative;
439469 background: ${ this . options . theme . background } ;
440- border-radius: 4px;
441470 overflow: hidden;
471+ padding: 0.25rem;
472+ box-sizing: border-box;
442473 ` ;
443474
444475 return this . container ;
@@ -455,6 +486,9 @@ export default class TerminalComponent {
455486
456487 this . container = container ;
457488
489+ // Apply terminal background color to container to match theme
490+ this . container . style . background = this . options . theme . background ;
491+
458492 try {
459493 try {
460494 this . terminal . loadAddon ( this . webglAddon ) ;
@@ -535,13 +569,16 @@ export default class TerminalComponent {
535569 rows : this . terminal . rows ,
536570 } ;
537571
538- const response = await fetch ( "http://localhost:8767/terminals" , {
539- method : "POST" ,
540- headers : {
541- "Content-Type" : "application/json" ,
572+ const response = await fetch (
573+ `http://localhost:${ this . options . port } /terminals` ,
574+ {
575+ method : "POST" ,
576+ headers : {
577+ "Content-Type" : "application/json" ,
578+ } ,
579+ body : JSON . stringify ( requestBody ) ,
542580 } ,
543- body : JSON . stringify ( requestBody ) ,
544- } ) ;
581+ ) ;
545582
546583 if ( ! response . ok ) {
547584 throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
@@ -573,7 +610,7 @@ export default class TerminalComponent {
573610
574611 this . pid = pid ;
575612
576- const wsUrl = `ws://localhost:8767 /terminals/${ pid } ` ;
613+ const wsUrl = `ws://localhost:${ this . options . port } /terminals/${ pid } ` ;
577614
578615 this . websocket = new WebSocket ( wsUrl ) ;
579616
@@ -627,13 +664,16 @@ export default class TerminalComponent {
627664 if ( ! this . pid || ! this . serverMode ) return ;
628665
629666 try {
630- await fetch ( `http://localhost:8767/terminals/${ this . pid } /resize` , {
631- method : "POST" ,
632- headers : {
633- "Content-Type" : "application/json" ,
667+ await fetch (
668+ `http://localhost:${ this . options . port } /terminals/${ this . pid } /resize` ,
669+ {
670+ method : "POST" ,
671+ headers : {
672+ "Content-Type" : "application/json" ,
673+ } ,
674+ body : JSON . stringify ( { cols, rows } ) ,
634675 } ,
635- body : JSON . stringify ( { cols, rows } ) ,
636- } ) ;
676+ ) ;
637677 } catch ( error ) {
638678 console . error ( "Failed to resize terminal:" , error ) ;
639679 }
@@ -653,7 +693,18 @@ export default class TerminalComponent {
653693 * @param {string } data - Data to write
654694 */
655695 write ( data ) {
656- this . terminal . write ( data ) ;
696+ if (
697+ this . serverMode &&
698+ this . isConnected &&
699+ this . websocket &&
700+ this . websocket . readyState === WebSocket . OPEN
701+ ) {
702+ // Send data through WebSocket instead of direct write
703+ this . websocket . send ( data ) ;
704+ } else {
705+ // For local mode or disconnected terminals, write directly
706+ this . terminal . write ( data ) ;
707+ }
657708 }
658709
659710 /**
@@ -675,6 +726,32 @@ export default class TerminalComponent {
675726 * Focus terminal
676727 */
677728 focus ( ) {
729+ // Ensure cursor is visible before focusing to prevent half-visibility
730+ if ( this . terminal . buffer && this . terminal . buffer . active ) {
731+ const buffer = this . terminal . buffer . active ;
732+ const cursorY = buffer . cursorY ;
733+ const cursorViewportPos = buffer . baseY + cursorY ;
734+ const viewportTop = buffer . viewportY ;
735+ const viewportBottom = viewportTop + this . terminal . rows - 1 ;
736+
737+ // Check if cursor is fully visible (with margin to prevent half-visibility)
738+ const isCursorFullyVisible =
739+ cursorViewportPos >= viewportTop + 1 &&
740+ cursorViewportPos <= viewportBottom - 2 ;
741+
742+ // If cursor is not fully visible, scroll to make it properly visible
743+ if ( ! isCursorFullyVisible && buffer . length > this . terminal . rows ) {
744+ const targetScroll = Math . max (
745+ 0 ,
746+ Math . min (
747+ buffer . length - this . terminal . rows ,
748+ cursorViewportPos - Math . floor ( this . terminal . rows * 0.25 ) ,
749+ ) ,
750+ ) ;
751+ this . terminal . scrollToLine ( targetScroll ) ;
752+ }
753+ }
754+
678755 this . terminal . focus ( ) ;
679756 }
680757
@@ -896,9 +973,12 @@ export default class TerminalComponent {
896973
897974 if ( this . pid && this . serverMode ) {
898975 try {
899- await fetch ( `http://localhost:8767/terminals/${ this . pid } /terminate` , {
900- method : "POST" ,
901- } ) ;
976+ await fetch (
977+ `http://localhost:${ this . options . port } /terminals/${ this . pid } /terminate` ,
978+ {
979+ method : "POST" ,
980+ } ,
981+ ) ;
902982 } catch ( error ) {
903983 console . error ( "Failed to terminate terminal:" , error ) ;
904984 }
0 commit comments