140 lines
4.1 KiB
C#
140 lines
4.1 KiB
C#
using Godot;
|
|
using System;
|
|
using Godot.Collections;
|
|
|
|
[Tool]
|
|
public partial class TerminalTextEdit : TextEdit
|
|
{
|
|
private Dictionary _psProcess = new Dictionary();
|
|
private FileAccess _psOutputPipe;
|
|
private FileAccess _psInputPipe;
|
|
|
|
// Track historical boundaries so users can't delete past output
|
|
private int _protectedLine = 0;
|
|
private int _protectedColumn = 0;
|
|
private bool _isUpdatingText = false;
|
|
|
|
public override void _Ready()
|
|
{
|
|
// Initial setup
|
|
Text = "ReEdit Terminal - 0.1.3\nWindows PowerShell\nCopyright (C) Microsoft Corporation. All rights reserved.\n\nTry the new cross-platform PowerShell https://aka.ms/pscore6\n\n";
|
|
_protectedLine = GetLineCount() - 1;
|
|
_protectedColumn = GetLine(_protectedLine).Length;
|
|
|
|
// Force caret to the active prompt area
|
|
SetCaretLine(_protectedLine);
|
|
SetCaretColumn(_protectedColumn);
|
|
|
|
TextChanged += OnTextChanged;
|
|
StartPowerShell();
|
|
}
|
|
|
|
private void StartPowerShell()
|
|
{
|
|
var args = new string[] {
|
|
"-NoExit",
|
|
"-NoProfile",
|
|
"-Command",
|
|
"$OutputEncoding = [System.Text.Encoding]::UTF8"
|
|
};
|
|
|
|
_psProcess = OS.ExecuteWithPipe("powershell.exe", args);
|
|
|
|
if (_psProcess.Count == 0)
|
|
{
|
|
AppendSystemText("\n[Error: Failed to initialize PowerShell process.]\n");
|
|
return;
|
|
}
|
|
|
|
_psOutputPipe = (FileAccess)_psProcess["stdio"];
|
|
_psInputPipe = (FileAccess)_psProcess["stdio"];
|
|
}
|
|
|
|
public override void _GuiInput(InputEvent @event)
|
|
{
|
|
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
|
|
{
|
|
if (keyEvent.Keycode == Key.Backspace)
|
|
{
|
|
if (GetCaretLine() < _protectedLine ||
|
|
(GetCaretLine() == _protectedLine && GetCaretColumn() <= _protectedColumn))
|
|
{
|
|
AcceptEvent(); // Kill the input event before it acts
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (keyEvent.Keycode == Key.Enter || keyEvent.Keycode == Key.KpEnter)
|
|
{
|
|
string activeLine = GetLine(GetCaretLine());
|
|
string command = activeLine.Substring(_protectedColumn).Trim();
|
|
|
|
if (!string.IsNullOrWhiteSpace(command) && _psInputPipe != null)
|
|
{
|
|
_psInputPipe.StoreLine(command);
|
|
}
|
|
|
|
_isUpdatingText = true;
|
|
InsertTextAtCaret("\n");
|
|
_protectedLine = GetLineCount() - 1;
|
|
_protectedColumn = 0;
|
|
_isUpdatingText = false;
|
|
|
|
AcceptEvent();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnTextChanged()
|
|
{
|
|
if (_isUpdatingText) return;
|
|
|
|
if (GetCaretLine() < _protectedLine ||
|
|
(GetCaretLine() == _protectedLine && GetCaretColumn() < _protectedColumn))
|
|
{
|
|
_isUpdatingText = true;
|
|
SetCaretLine(_protectedLine);
|
|
SetCaretColumn(GetLine(_protectedLine).Length);
|
|
_isUpdatingText = false;
|
|
}
|
|
}
|
|
|
|
public override void _Process(double delta)
|
|
{
|
|
if (_psOutputPipe != null && _psOutputPipe.GetLength() > 0)
|
|
{
|
|
string newText = _psOutputPipe.GetAsText();
|
|
if (!string.IsNullOrEmpty(newText))
|
|
{
|
|
AppendSystemText(newText);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AppendSystemText(string incoming)
|
|
{
|
|
_isUpdatingText = true;
|
|
|
|
int oldCaretLine = GetCaretLine();
|
|
int oldCaretCol = GetCaretColumn();
|
|
SetCaretLine(GetLineCount() - 1);
|
|
SetCaretColumn(GetLine(GetLineCount() - 1).Length);
|
|
InsertTextAtCaret(incoming);
|
|
_protectedLine = GetLineCount() - 1;
|
|
_protectedColumn = GetLine(_protectedLine).Length;
|
|
SetCaretLine(_protectedLine);
|
|
SetCaretColumn(_protectedColumn);
|
|
|
|
_isUpdatingText = false;
|
|
}
|
|
|
|
public override void _ExitTree()
|
|
{
|
|
if (_psProcess.Count > 0 && _psProcess.ContainsKey("pid"))
|
|
{
|
|
int pid = (int)_psProcess["pid"];
|
|
OS.Kill(pid);
|
|
}
|
|
}
|
|
}
|