mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-24 18:20:25 +01:00
41525959e1
This method was never officially documented and used only as a workaround for issue #53. It also returns an instance of the undocumented and scruffily implemented Pipe class that I would prefer to keep internal. Now that #53 has been fixed, this method can be removed from the unofficial public API, but deprecate it just in case. If someone was using it then it is still possible (although not supported) to access the `_pipe` property of `_pty_native`.
191 lines
5.2 KiB
GDScript
191 lines
5.2 KiB
GDScript
# Derived from https://github.com/microsoft/node-pty/blob/main/src/terminal.ts
|
|
# Copyright (c) 2012-2015, Christopher Jeffrey (MIT License).
|
|
# Copyright (c) 2016, Daniel Imms (MIT License).
|
|
# Copyright (c) 2018, Microsoft Corporation (MIT License).
|
|
# Copyright (c) 2021-2022, Leroy Hopson (MIT License).
|
|
tool
|
|
extends Node
|
|
|
|
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")
|
|
|
|
const DEFAULT_NAME := "xterm-256color"
|
|
const DEFAULT_COLS := 80
|
|
const DEFAULT_ROWS := 24
|
|
const DEFAULT_ENV := {TERM = DEFAULT_NAME, COLORTERM = "truecolor"}
|
|
|
|
# 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
|
|
|
|
signal data_received(data)
|
|
signal exited(exit_code, signum)
|
|
|
|
export(NodePath) var terminal_path := NodePath() setget set_terminal_path
|
|
|
|
var _terminal: _Terminal = null setget _set_terminal
|
|
|
|
# The column size in characters.
|
|
export(int) var cols: int = DEFAULT_COLS setget set_cols, get_cols
|
|
|
|
# The row size in characters.
|
|
export(int) var rows: int = DEFAULT_ROWS setget set_rows, get_rows
|
|
|
|
# Environment to be set for the child program.
|
|
export(Dictionary) var env := DEFAULT_ENV
|
|
|
|
# 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
|
|
|
|
var _cols := DEFAULT_COLS
|
|
var _rows := DEFAULT_ROWS
|
|
var _pty_native: _PTYNative
|
|
|
|
|
|
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)
|
|
|
|
_pty_native.connect("data_received", self, "_on_pty_native_data_received")
|
|
_pty_native.connect("exited", self, "_on_pty_native_exited")
|
|
|
|
add_child(_pty_native)
|
|
|
|
|
|
func _ready():
|
|
if terminal_path and not _terminal:
|
|
set_terminal_path(terminal_path)
|
|
|
|
|
|
func set_cols(value: int):
|
|
resize(value, _rows)
|
|
|
|
|
|
func get_cols() -> int:
|
|
return _cols
|
|
|
|
|
|
func set_rows(value: int):
|
|
resize(_cols, value)
|
|
|
|
|
|
func get_rows() -> int:
|
|
return _rows
|
|
|
|
|
|
func set_terminal_path(value := NodePath()):
|
|
terminal_path = value
|
|
_set_terminal(get_node_or_null(terminal_path))
|
|
|
|
|
|
func _set_terminal(value: _Terminal):
|
|
if _terminal == value:
|
|
return
|
|
|
|
# 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")
|
|
|
|
_terminal = value
|
|
|
|
if not _terminal:
|
|
return
|
|
|
|
# Connect the new terminal.
|
|
resize(_terminal.get_cols(), _terminal.get_rows())
|
|
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")
|
|
|
|
|
|
# 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.
|
|
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)
|
|
|
|
|
|
# Same as resize() but takes a Vector2.
|
|
func resizev(size: Vector2) -> void:
|
|
resize(int(size.x), int(size.y))
|
|
|
|
|
|
# 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)
|
|
|
|
|
|
func _notification(what: int):
|
|
match what:
|
|
NOTIFICATION_PARENTED:
|
|
var parent = get_parent()
|
|
if parent is _Terminal:
|
|
set_terminal_path(get_path_to(parent))
|
|
|
|
|
|
func fork(
|
|
file: String = OS.get_environment("SHELL"),
|
|
args: PoolStringArray = PoolStringArray(),
|
|
cwd = _LibuvUtils.get_cwd(),
|
|
cols: int = _cols,
|
|
rows: int = _rows,
|
|
uid: int = -1,
|
|
gid: int = -1,
|
|
utf8 = true
|
|
) -> int:
|
|
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)
|
|
|
|
|
|
func open(cols: int = DEFAULT_COLS, rows: int = DEFAULT_ROWS) -> Array:
|
|
return _pty_native.open(cols, rows)
|
|
|
|
|
|
func get_master():
|
|
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."
|
|
)
|
|
return _pty_native.get_master()
|
|
|
|
|
|
func _on_pty_native_data_received(data):
|
|
emit_signal("data_received", data)
|
|
|
|
|
|
func _on_pty_native_exited(exit_code: int, signum: int) -> void:
|
|
emit_signal("exited", exit_code, signum)
|
|
|
|
|
|
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
|