11import React , { useEffect , useMemo , useRef , useState } from 'react' ;
2- import { ITerminalOptions , Terminal } from 'xterm' ;
2+ import { Terminal , ITerminalOptions } from 'xterm' ;
33import { FitAddon } from 'xterm-addon-fit' ;
44import { SearchAddon } from 'xterm-addon-search' ;
55import { SearchBarAddon } from 'xterm-addon-search-bar' ;
66import { WebLinksAddon } from 'xterm-addon-web-links' ;
7+ import { ScrollDownHelperAddon } from '@/plugins/XtermScrollDownHelperAddon' ;
78import SpinnerOverlay from '@/components/elements/SpinnerOverlay' ;
89import { ServerContext } from '@/state/server' ;
910import styled from 'styled-components/macro' ;
@@ -72,12 +73,13 @@ export default () => {
7273 const searchAddon = new SearchAddon ( ) ;
7374 const searchBar = new SearchBarAddon ( { searchAddon } ) ;
7475 const webLinksAddon = new WebLinksAddon ( ) ;
76+ const scrollDownHelperAddon = new ScrollDownHelperAddon ( ) ;
7577 const { connected, instance } = ServerContext . useStoreState ( state => state . socket ) ;
76- const [ canSendCommands ] = usePermissions ( [ 'control.console' ] ) ;
78+ const [ canSendCommands ] = usePermissions ( [ 'control.console' ] ) ;
7779 const serverId = ServerContext . useStoreState ( state => state . server . data ! . id ) ;
7880 const isTransferring = ServerContext . useStoreState ( state => state . server . data ! . isTransferring ) ;
79- const [ history , setHistory ] = usePersistedState < string [ ] > ( `${ serverId } :command_history` , [ ] ) ;
80- const [ historyIndex , setHistoryIndex ] = useState ( - 1 ) ;
81+ const [ history , setHistory ] = usePersistedState < string [ ] > ( `${ serverId } :command_history` , [ ] ) ;
82+ const [ historyIndex , setHistoryIndex ] = useState ( - 1 ) ;
8183
8284 const handleConsoleOutput = ( line : string , prelude = false ) => terminal . writeln (
8385 ( prelude ? TERMINAL_PRELUDE : '' ) + line . replace ( / (?: \r \n | \r | \n ) $ / im, '' ) + '\u001b[0m' ,
@@ -125,7 +127,7 @@ export default () => {
125127
126128 const command = e . currentTarget . value ;
127129 if ( e . key === 'Enter' && command . length > 0 ) {
128- setHistory ( prevHistory => [ command , ...prevHistory ! ] . slice ( 0 , 32 ) ) ;
130+ setHistory ( prevHistory => [ command , ...prevHistory ! ] . slice ( 0 , 32 ) ) ;
129131 setHistoryIndex ( - 1 ) ;
130132
131133 instance && instance . send ( 'send command' , command ) ;
@@ -139,6 +141,7 @@ export default () => {
139141 terminal . loadAddon ( searchAddon ) ;
140142 terminal . loadAddon ( searchBar ) ;
141143 terminal . loadAddon ( webLinksAddon ) ;
144+ terminal . loadAddon ( scrollDownHelperAddon ) ;
142145
143146 terminal . open ( ref . current ) ;
144147 fitAddon . fit ( ) ;
@@ -158,7 +161,7 @@ export default () => {
158161 return true ;
159162 } ) ;
160163 }
161- } , [ terminal , connected ] ) ;
164+ } , [ terminal , connected ] ) ;
162165
163166 useEventListener ( 'resize' , debounce ( ( ) => {
164167 if ( terminal . element ) {
@@ -196,33 +199,33 @@ export default () => {
196199 } ) ;
197200 }
198201 } ;
199- } , [ connected , instance ] ) ;
202+ } , [ connected , instance ] ) ;
200203
201204 return (
202205 < div css = { tw `text-xs font-mono relative` } >
203- < SpinnerOverlay visible = { ! connected } size = { 'large' } />
206+ < SpinnerOverlay visible = { ! connected } size = { 'large' } />
204207 < div
205208 css = { [
206209 tw `rounded-t p-2 bg-black w-full` ,
207210 ! canSendCommands && tw `rounded-b` ,
208211 ] }
209212 style = { { minHeight : '16rem' } }
210213 >
211- < TerminalDiv id = { 'terminal' } ref = { ref } />
214+ < TerminalDiv id = { 'terminal' } ref = { ref } />
212215 </ div >
213216 { canSendCommands &&
214- < div css = { tw `rounded-b bg-neutral-900 text-neutral-100 flex items-baseline` } >
215- < div css = { tw `flex-shrink-0 p-2 font-bold` } > $</ div >
216- < div css = { tw `w-full` } >
217- < CommandInput
218- type = { 'text' }
219- placeholder = { 'Type a command...' }
220- aria-label = { 'Console command input.' }
221- disabled = { ! instance || ! connected }
222- onKeyDown = { handleCommandKeyDown }
223- />
217+ < div css = { tw `rounded-b bg-neutral-900 text-neutral-100 flex items-baseline` } >
218+ < div css = { tw `flex-shrink-0 p-2 font-bold` } > $</ div >
219+ < div css = { tw `w-full` } >
220+ < CommandInput
221+ type = { 'text' }
222+ placeholder = { 'Type a command...' }
223+ aria-label = { 'Console command input.' }
224+ disabled = { ! instance || ! connected }
225+ onKeyDown = { handleCommandKeyDown }
226+ />
227+ </ div >
224228 </ div >
225- </ div >
226229 }
227230 </ div >
228231 ) ;
0 commit comments