Added console panel with device and host console, logs and domain console.

This commit is contained in:
RedNicStone committed 2026-11-09 21:15:57 +01:00
1 parent 6038b816b7
commit b98ed82619
17 files changed
+551 -22

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
@tool
extends VBoxContainer
signal command_submitted(command: String)
signal focus_requested
@export var session_id := "rov"
@export var tab_label := "ROV"
@export var shortcut: Key = KEY_F5
@export var prompt := "rov $"
@export var read_only := false
@export var introduction := "ROV shell disconnected."
@export var max_scrollback_characters := 128000
var connected := false
var _buffer := ""
var _history: Array[String] = []
var _history_index := 0
var _draft := ""
@onready var output: RichTextLabel = $Output
@onready var command_input: LineEdit = $Input/Command
@onready var filter_input: LineEdit = $Filter/Text
func _ready() -> void:
$Input.visible = not read_only
$Filter.visible = read_only
$Input/Prompt.text = prompt
_buffer = introduction + "\n"
output.text = _buffer
if Engine.is_editor_hint():
return
command_input.text_submitted.connect(submit_command)
command_input.gui_input.connect(_history_input)
filter_input.text_changed.connect(func(_text: String) -> void: _render_output())
$Status/Clear.pressed.connect(clear_output)
$Status/Follow.toggled.connect(func(enabled: bool) -> void:
output.scroll_following = enabled
if enabled: output.scroll_to_line(maxi(output.get_line_count() - 1, 0))
)
for control in [output, command_input, filter_input, $Status/Clear, $Status/Follow]:
control.gui_input.connect(func(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
focus_requested.emit()
)
func preferred_input() -> Control:
return filter_input if read_only else command_input
func set_connection(value: bool, message: String = "") -> void:
connected = value
$Status/Connection.text = message if not message.is_empty() else ("Connected" if value else "Not connected")
func submit_command(command: String) -> bool:
if read_only or command.strip_edges().is_empty():
return false
if _history.is_empty() or _history.back() != command:
_history.append(command)
if _history.size() > 200: _history.pop_front()
_history_index = _history.size()
_draft = ""
append_output(prompt + " " + command + "\n")
command_input.clear()
command_submitted.emit(command)
return true
func append_output(text: String) -> void:
_buffer += text
var truncated := _buffer.length() > max_scrollback_characters
if truncated:
_buffer = _buffer.right(max_scrollback_characters)
var newline := _buffer.find("\n")
if newline >= 0 and newline < _buffer.length() - 1:
_buffer = _buffer.substr(newline + 1)
if truncated or (read_only and not filter_input.text.is_empty()):
_render_output()
else:
output.add_text(text)
func clear_output() -> void:
_buffer = ""
output.clear()
func _render_output() -> void:
var scroll := output.get_v_scroll_bar().value
if read_only and not filter_input.text.is_empty():
var matches := PackedStringArray()
for line in _buffer.split("\n"):
if line.to_lower().contains(filter_input.text.to_lower()):
matches.append(line)
output.text = "\n".join(matches)
else:
output.text = _buffer
if not $Status/Follow.button_pressed:
output.get_v_scroll_bar().set_deferred("value", scroll)
func _history_input(event: InputEvent) -> void:
if not event is InputEventKey or not event.pressed or event.ctrl_pressed or event.alt_pressed or event.meta_pressed:
return
if event.keycode not in [KEY_UP, KEY_DOWN] or _history.is_empty():
return
if _history_index == _history.size():
_draft = command_input.text
_history_index = clampi(_history_index + (-1 if event.keycode == KEY_UP else 1), 0, _history.size())
command_input.text = _draft if _history_index == _history.size() else _history[_history_index]
command_input.caret_column = command_input.text.length()
command_input.accept_event()