2022-06-29 17:58:48 +02:00
# Derived from https://github.com/microsoft/node-pty/blob/main/src/terminal.ts
2021-07-02 19:27:34 +02:00
# Copyright (c) 2012-2015, Christopher Jeffrey (MIT License).
# Copyright (c) 2016, Daniel Imms (MIT License).
# Copyright (c) 2018, Microsoft Corporation (MIT License).
2022-06-29 17:58:48 +02:00
# Copyright (c) 2021-2022, Leroy Hopson (MIT License).
2021-07-02 19:27:34 +02:00
tool
2022-06-29 17:58:48 +02:00
extends Node
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
const _LibuvUtils := preload ( " ./nodes/pty/libuv_utils.gd " )
const _PTYNative := preload ( " ./nodes/pty/pty_native.gd " )
const _PTYUnix := preload ( " ./nodes/pty/unix/pty_unix.gd " )
const _Terminal := preload ( " ./terminal.gd " )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
const DEFAULT_NAME := " xterm-256color "
const DEFAULT_COLS := 80
const DEFAULT_ROWS := 24
const DEFAULT_ENV := { TERM = DEFAULT_NAME , COLORTERM = " truecolor " }
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# Any signal_number can be sent to the pty's process using the kill() function,
# these are just the signals with numbers specified in the POSIX standard.
const Signal = _PTYUnix . Signal
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
signal data_received ( data )
signal exited ( exit_code , signum )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
export ( NodePath ) var terminal_path := NodePath ( ) setget set_terminal_path
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
var _terminal : _Terminal = null setget _set_terminal
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# The column size in characters.
2022-08-12 00:24:54 +02:00
export ( int ) var cols : int = DEFAULT_COLS setget set_cols , get_cols
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# The row size in characters.
2022-08-12 00:24:54 +02:00
export ( int ) var rows : int = DEFAULT_ROWS setget set_rows , get_rows
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# Environment to be set for the child program.
export ( Dictionary ) var env := DEFAULT_ENV
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# If true the environment variables in the env Dictionary will be merged with
# the environment variables of the operating system (e.g. printenv), with the
# former taking precedence in the case of conflicts.
export ( bool ) var use_os_env := true
2021-07-02 19:27:34 +02:00
2022-08-12 00:24:54 +02:00
var _cols := DEFAULT_COLS
var _rows := DEFAULT_ROWS
2022-06-29 17:58:48 +02:00
var _pty_native : _PTYNative
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
func _init ( ) :
var os_name := OS . get_name ( )
match os_name :
" X11 " , " Server " , " OSX " :
_pty_native = _PTYUnix . new ( )
_ :
push_error ( " PTY is not support on current platform ( %s ). " % os_name )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
_pty_native . connect ( " data_received " , self , " _on_pty_native_data_received " )
_pty_native . connect ( " exited " , self , " _on_pty_native_exited " )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
add_child ( _pty_native )
2021-07-02 19:27:34 +02:00
2022-08-12 00:24:54 +02:00
func _ready ( ) :
if terminal_path and not _terminal :
set_terminal_path ( terminal_path )
2022-06-29 17:58:48 +02:00
func set_cols ( value : int ) :
2022-08-12 00:24:54 +02:00
resize ( value , _rows )
func get_cols ( ) - > int :
return _cols
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
func set_rows ( value : int ) :
2022-08-12 00:24:54 +02:00
resize ( _cols , value )
func get_rows ( ) - > int :
return _rows
2021-07-02 19:27:34 +02:00
2021-07-22 07:17:23 +02:00
2022-06-29 17:58:48 +02:00
func set_terminal_path ( value := NodePath ( ) ) :
terminal_path = value
_set_terminal ( get_node_or_null ( terminal_path ) )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
func _set_terminal ( value : _Terminal ) :
if _terminal == value :
return
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# Disconect the current terminal, if any.
if _terminal :
disconnect ( " data_received " , _terminal , " write " )
_terminal . disconnect ( " data_sent " , self , " write " )
_terminal . disconnect ( " size_changed " , self , " resizev " )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
_terminal = value
2021-07-03 15:54:34 +02:00
2022-06-29 17:58:48 +02:00
if not _terminal :
return
2021-07-03 15:54:34 +02:00
2022-06-29 17:58:48 +02:00
# Connect the new terminal.
2022-08-15 00:35:01 +02:00
resize ( _terminal . get_cols ( ) , _terminal . get_rows ( ) )
2022-06-29 17:58:48 +02:00
if not _terminal . is_connected ( " size_changed " , self , " resizev " ) :
_terminal . connect ( " size_changed " , self , " resizev " )
if not _terminal . is_connected ( " data_sent " , self , " write " ) :
_terminal . connect ( " data_sent " , self , " write " )
if not is_connected ( " data_received " , _terminal , " write " ) :
connect ( " data_received " , _terminal , " write " )
2021-07-22 07:17:23 +02:00
2022-06-29 17:58:48 +02:00
# Writes data to the socket.
# data: The data to write.
func write ( data ) - > void :
_pty_native . write ( data )
# Resizes the dimensions of the pty.
# cols: The number of columns.
# rows: The number of rows.
2022-08-12 00:24:54 +02:00
func resize ( cols = _cols , rows = _rows ) - > void :
if not _valid_size ( cols , rows ) :
push_error ( " Size of cols/rows must be a positive integer. " )
return
_cols = cols
_rows = rows
_pty_native . resize ( _cols , _rows )
2022-06-29 17:58:48 +02:00
# Same as resize() but takes a Vector2.
func resizev ( size : Vector2 ) - > void :
2022-08-12 00:24:54 +02:00
resize ( int ( size . x ) , int ( size . y ) )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
# Kill the pty.
# sigint: The signal to send. By default this is SIGHUP.
# This is not supported on Windows.
func kill ( signum : int = Signal . SIGHUP ) - > void :
_pty_native . kill ( signum )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
func _notification ( what : int ) :
match what :
NOTIFICATION_PARENTED :
var parent = get_parent ( )
if parent is _Terminal :
set_terminal_path ( get_path_to ( parent ) )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
func fork (
file : String = OS . get_environment ( " SHELL " ) ,
args : PoolStringArray = PoolStringArray ( ) ,
cwd = _LibuvUtils . get_cwd ( ) ,
2022-08-12 00:24:54 +02:00
cols : int = _cols ,
rows : int = _rows ,
2022-06-29 17:58:48 +02:00
uid : int = - 1 ,
gid : int = - 1 ,
utf8 = true
) - > int :
2022-08-12 00:24:54 +02:00
resize ( cols , rows ) # Ensures error message is printed if cols/rows are invalid.
if not _valid_size ( cols , rows ) :
return ERR_INVALID_PARAMETER
return _pty_native . fork ( file , args , cwd , _cols , _rows , uid , gid , utf8 )
2022-06-29 17:58:48 +02:00
func open ( cols : int = DEFAULT_COLS , rows : int = DEFAULT_ROWS ) - > Array :
return _pty_native . open ( cols , rows )
func get_master ( ) :
2022-08-19 10:20:04 +02:00
push_warning (
" The method get_master() is deprecated and will be removed in a future version. If you really need to get the underlying Pipe of the pty, then you can access '_pty_native._pipe', but this is not supported and may change at any time. "
)
2022-06-29 17:58:48 +02:00
return _pty_native . get_master ( )
func _on_pty_native_data_received ( data ) :
emit_signal ( " data_received " , data )
2021-07-02 19:27:34 +02:00
2022-06-29 17:58:48 +02:00
func _on_pty_native_exited ( exit_code : int , signum : int ) - > void :
emit_signal ( " exited " , exit_code , signum )
2022-08-12 00:24:54 +02:00
static func _valid_size ( cols : int , rows : int ) - > bool :
return cols > 0 and rows > 0 and cols != NAN and rows != NAN and cols != INF and rows != INF