File size: 2,460 Bytes
8272517
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// SpatialShellTerminal.cs — the terminal panel: a command line inside VR.
//
// A TextMeshPro input field + output log. Typing a command and submitting it
// sends the text to the backend shell and prints the returned output. This is
// the "terminal" element of the spatial OS.
//
// Setup: attach to a GameObject with a TMP_InputField (input) and a TMP_Text
// (output) as children, and a reference to the XrosClient. Wire the input
// field's OnSubmit event to Submit(), or call Submit() from your own handler.

using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;

public class SpatialShellTerminal : MonoBehaviour
{
    public XrosClient client;
    public TMP_InputField input;
    public TMP_Text output;

    [Tooltip("Maximum number of output lines kept in the log.")]
    public int maxLines = 200;

    private readonly List<string> history = new List<string>();
    private int historyIndex = -1;

    private void OnEnable()
    {
        if (client != null) client.OnMessage += HandleMessage;
    }

    private void OnDisable()
    {
        if (client != null) client.OnMessage -= HandleMessage;
    }

    private void HandleMessage(JObject msg)
    {
        // Only the terminal cares about "output" (command results).
        if (msg["op"]?.ToString() == "output")
        {
            Append(msg["text"]?.ToString() ?? "");
        }
    }

    public void Submit()
    {
        if (string.IsNullOrWhiteSpace(input.text)) return;
        string line = input.text.Trim();
        history.Add(line);
        historyIndex = history.Count;
        Append("> " + line);
        input.text = "";
        input.ActivateInputField();
        client?.SendCommand(line);
    }

    public void ScrollHistory(int direction)
    {
        if (history.Count == 0) return;
        historyIndex = Mathf.Clamp(historyIndex + direction, 0, history.Count);
        input.text = historyIndex < history.Count ? history[historyIndex] : "";
        input.caretPosition = input.text.Length;
    }

    private void Append(string line)
    {
        output.text += line + "\n";
        // Trim old lines to keep the log bounded.
        var lines = output.text.Split('\n');
        if (lines.Length > maxLines)
        {
            var kept = new string[maxLines];
            System.Array.Copy(lines, lines.Length - maxLines, kept, 0, maxLines);
            output.text = string.Join("\n", kept);
        }
    }
}