Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node tree access #84

Merged
merged 23 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5088010
Create SelectedNode scene
MASSHUU12 Dec 4, 2023
ca82d9f
Change signals name
MASSHUU12 Dec 4, 2023
eff4a65
Add UnknownMethod to LogHelper.cs
MASSHUU12 Dec 4, 2023
2467dd0
Add MethodCalled signal & CallMethod method
MASSHUU12 Dec 4, 2023
a6e8416
Add SelectedNode to Terminal
MASSHUU12 Dec 4, 2023
a60996c
Update changelog
MASSHUU12 Dec 4, 2023
dfa7e6a
Get reference to the SelectedNode
MASSHUU12 Dec 5, 2023
33639ad
Display path to the current node before prompt
MASSHUU12 Dec 5, 2023
46ce3eb
Add Cn command to change selected node path
MASSHUU12 Dec 5, 2023
46d6ca0
Add Cn command to YAT
MASSHUU12 Dec 5, 2023
67ae021
Update docs
MASSHUU12 Dec 5, 2023
0694339
First search for node in CurrentNode's children before looking in the…
MASSHUU12 Dec 5, 2023
b17e3ad
Ls command supports scene tree
MASSHUU12 Dec 5, 2023
038a749
Add option to print info about currently selected node in whereami co…
MASSHUU12 Dec 6, 2023
8381205
Add method call on selected node to input component
MASSHUU12 Dec 6, 2023
8298d97
Add SplitClean method to TextHelper.cs
MASSHUU12 Dec 6, 2023
fe9aecc
Do not continue when input starts with $
MASSHUU12 Dec 6, 2023
4697693
Add option to list methods of current node
MASSHUU12 Dec 6, 2023
2613925
Add called methods to the history
MASSHUU12 Dec 6, 2023
8114721
Display arguments & their types
MASSHUU12 Dec 6, 2023
3de36e5
Run methods on a selected node
MASSHUU12 Dec 6, 2023
0c79e85
Add documentation for calling methods on nodes
MASSHUU12 Dec 6, 2023
1c70b7a
Update changelog
MASSHUU12 Dec 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- SelectedNode scene.
- UnknownMethod method for LogHelper.
- CurrentNodeChanged signal.
- CurrentNodeChangeFailed signal.
- MethodCalled signal.
- Cn command.
- Support for scene tree for Ls command.
- -s option for Whereami command for printing info about currently selected node.
- -m option for Whereami command for printing the methods of the selected node.
- SplitClean method to TextHelper.
- Ability to run methods on a selected node (experimental).

### Changed

- Ls command is no longer threaded.

## [1.12.0-beta 2023-12-04]

### Added
Expand Down
1 change: 1 addition & 0 deletions addons/yat/docs/BUILTIN_COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@
| ping | N/A | Sends ICMP (Internet Control Message Protocol) echo request to the server. |
| ip | N/A | Displays your private IP addresses. |
| ls | N/A | Lists the contents of the current directory. |
| cn | N/A | Changes the selected node to the specified node path. |
30 changes: 30 additions & 0 deletions addons/yat/docs/CALLING_METHODS_ON_NODES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<div align="center">
<h3>Calling methods on nodes</h1>
<p>Here you will find information on how to call methods on selected nodes,
how to select them and many more.</p>
</div>

### Calling methods on nodes

> [!NOTE]
> Please keep in mind that this feature is still in development.
>
> Many things may not work as expected.
>
> Method chaining is not yet working as it should. At the moment, the chained methods will be run one at a time on the selected node, not on the returned data.

The terminal in `YAT` can operate in two modes: by default, the terminal treats any input as `commands` and tries to parse them.

The second mode allows you to run `methods` on the currently selected `node`, this mode is triggered by giving a `$` character at the beginning of the input data.

To run a method, you just need to specify the whole name, in the case of methods built in Godot, the names are written in `snake_case`.

### Changing selected node

To change the selected node, use the `cn` command.

### Checking available methods

To see what methods are available for a particular node, use the `ls` command with the `-m` option.

If you want to check the methods for the currently selected node, use `ls . -m`.
1 change: 1 addition & 0 deletions addons/yat/src/YAT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public override void _Ready()

AddCommand(new Ls(this));
AddCommand(new Ip(this));
AddCommand(new Cn(this));
AddCommand(new Cls(this));
AddCommand(new Man(this));
AddCommand(new Set(this));
Expand Down
28 changes: 28 additions & 0 deletions addons/yat/src/commands/builtin/Cn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using YAT.Attributes;
using YAT.Enums;
using YAT.Interfaces;

namespace YAT.Commands
{
[Command(
"cn",
"Changes the selected node to the specified node path.",
"[b]Usage[/b]: cn [i]node_path[/i]"
)]
[Argument("node_path", "string", "The node path of the new selected node.")]
public partial class Cn : ICommand
{
public YAT Yat { get; set; }

public Cn(YAT Yat) => this.Yat = Yat;

public CommandResult Execute(Dictionary<string, object> cArgs, params string[] args)
{
var path = cArgs["node_path"] as string;
var result = Yat.Terminal.SelectedNode.ChangeSelectedNode(path);

return result ? CommandResult.Success : CommandResult.Failure;
}
}
}
95 changes: 83 additions & 12 deletions addons/yat/src/commands/builtin/Ls.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Godot;
using YAT.Attributes;
using YAT.Enums;
Expand All @@ -13,23 +13,98 @@
namespace YAT.Commands
{
[Command("ls", "Lists the contents of the current directory.", "[b]Usage[/b]: ls")]
[Threaded]
[Argument("path", "string", "The path to list the contents of.")]
[Option("-n", null, "Displays the children of the current node.", false)]
[Option("-m", null, "Lists the methods of the current node.", false)]
public sealed class Ls : ICommand
{
public YAT Yat { get; set; }
public Ls(YAT Yat) => this.Yat = Yat;

private CancellationToken _ct;

public CommandResult Execute(Dictionary<string, object> cArgs, CancellationToken ct, params string[] args)
public CommandResult Execute(Dictionary<string, object> cArgs, params string[] args)
{
string path = (string)cArgs["path"];
path = ProjectSettings.GlobalizePath(path);
bool n = (bool)cArgs["-n"];
bool m = (bool)cArgs["-m"];

if (n) return PrintNodeChildren(path);
if (m) return PrintNodeMethods(path);
return PrintDirectoryContents(ProjectSettings.GlobalizePath(path));
}

private CommandResult PrintNodeMethods(string path)
{
Node node = path != "."
? Yat.Terminal.SelectedNode.GetNodeOrNull(path)
: Yat.Terminal.SelectedNode;

if (!GodotObject.IsInstanceValid(node))
{
Yat.Terminal.Print($"Node '{path}' does not exist.", PrintType.Error);
return CommandResult.Failure;
}

var methods = node.GetMethodList().GetEnumerator();

_ct = ct;
StringBuilder sb = new();

return PrintDirectoryContents(path);
while (methods.MoveNext())
{
string name = methods.Current.TryGetValue("name", out var value)
? (string)value
: string.Empty;

string[] arguments = methods.Current.TryGetValue("args", out value)
? value.AsGodotArray<Godot.Collections.Dictionary<string, Variant>>()
.Select(arg => $"[u]{arg["name"]}[/u]: {((Variant.Type)(int)arg["type"]).ToString()}").ToArray()
: Array.Empty<string>();

int returns = methods.Current.TryGetValue("return", out value)
? value.AsGodotDictionary<string, int>()["type"]
: 0;

sb.Append($"[b]{name}[/b]");
sb.Append($"({string.Join(", ", arguments)}) -> ");
sb.Append(((Variant.Type)returns).ToString());
sb.AppendLine();
}

Yat.Terminal.Print(sb.ToString());

return CommandResult.Success;
}

private CommandResult PrintNodeChildren(string path)
{
Node node = path != "."
? Yat.Terminal.SelectedNode.GetNodeOrNull(path)
: Yat.Terminal.SelectedNode;

if (!GodotObject.IsInstanceValid(node))
{
Yat.Terminal.Print($"Node '{path}' does not exist.", PrintType.Error);
return CommandResult.Failure;
}

var children = node.GetChildren();

if (children == null || children.Count == 0)
{
Yat.Terminal.Print($"Node '{path}' has no children.", PrintType.Warning);
return CommandResult.Success;
}

StringBuilder sb = new();

foreach (Node child in children)
{
sb.Append($"[{child.Name}] ({child.GetType().Name}) - {child.GetPath()}");
sb.AppendLine();
}

Yat.Terminal.Print(sb.ToString());

return CommandResult.Success;
}

private CommandResult PrintDirectoryContents(string path)
Expand Down Expand Up @@ -86,8 +161,6 @@ private void AppendDetails(StringBuilder sb, FileSystemInfo[] infos)
// Get the maximum length of the file size and last write time strings.
foreach (FileSystemInfo info in infos)
{
if (_ct.IsCancellationRequested) return;

maxLastWriteTimeLength = Math.Max(
maxLastWriteTimeLength,
info.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss").Length
Expand All @@ -103,8 +176,6 @@ private void AppendDetails(StringBuilder sb, FileSystemInfo[] infos)
// Append the details of each FileSystemInfo object to the StringBuilder.
foreach (FileSystemInfo info in infos)
{
if (_ct.IsCancellationRequested) return;

var fileSizeString = NumericHelper.FileSizeToString(
info is FileInfo
? ((FileInfo)info).Length
Expand Down
4 changes: 4 additions & 0 deletions addons/yat/src/commands/builtin/Whereami.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace YAT.Commands
{
[Command("whereami", "Prints the current scene name and path.", "[b]Usage[/b]: whereami", "wai")]
[Option("-l", null, "Prints the full path to the scene file.", false)]
[Option("-s", null, "Prints info about currently selected node.", false)]
public partial class Whereami : ICommand
{
public YAT Yat { get; set; }
Expand All @@ -17,6 +18,9 @@ public CommandResult Execute(Dictionary<string, object> cArgs, params string[] a
{
var scene = Yat.GetTree().CurrentScene;
var longForm = (bool)cArgs["-l"];
var s = (bool)cArgs["-s"];

scene = s ? Yat.Terminal.SelectedNode.CurrentNode : scene;

Yat.Terminal.Print(
scene.GetPath() +
Expand Down
11 changes: 11 additions & 0 deletions addons/yat/src/helpers/LogHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ public static void MissingValue(string command, string option)
PrintMessage(message, Terminal.PrintType.Error);
}

public static void UnknownMethod(string sceneName, string method)
{
var message = string.Format(
"{0} does not have a method named {1}.",
sceneName,
method
);

PrintMessage(message, Terminal.PrintType.Error);
}

public static void Error(string message) => PrintMessage(message, Terminal.PrintType.Error);
}
}
23 changes: 18 additions & 5 deletions addons/yat/src/helpers/TextHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ public static string MakeBold(string text)
/// <returns>An array of sanitized strings.</returns>
public static string[] SanitizeText(string text)
{
return text.Split(' ', System.StringSplitOptions.TrimEntries |
System.StringSplitOptions.RemoveEmptyEntries)
.Select(token => token.Trim())
.Where(token => !string.IsNullOrEmpty(token))
.ToArray();
return SplitClean(text, " ");
}

/// <summary>
Expand Down Expand Up @@ -131,5 +127,22 @@ public static bool EndsWith(string text, params char[] value)
{
return value.Any(text.EndsWith);
}

/// <summary>
/// Splits the given text using the specified separator,
/// trims each token, removes empty tokens,
/// and returns an array of the resulting tokens.
/// </summary>
/// <param name="text">The text to split.</param>
/// <param name="separator">The separator used to split the text.</param>
/// <returns>An array of the resulting tokens.</returns>
public static string[] SplitClean(string text, string separator)
{
return text.Split(separator, System.StringSplitOptions.TrimEntries |
System.StringSplitOptions.RemoveEmptyEntries)
.Select(token => token.Trim())
.Where(token => !string.IsNullOrEmpty(token))
.ToArray();
}
}
}
13 changes: 12 additions & 1 deletion addons/yat/src/scenes/overlay/components/terminal/Terminal.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Godot;
using YAT.Scenes.Overlay.Components.Terminal.Components.SelectedNode;

namespace YAT.Scenes.Overlay.Components.Terminal
{
public partial class Terminal : YatWindow.YatWindow
{
public Input Input { get; private set; }
public TerminalContext Context { get; private set; }
public SelectedNode SelectedNode { get; private set; }

/// <summary>
/// The type of message to print in the YatTerminal.
Expand Down Expand Up @@ -43,6 +45,9 @@ public override void _Ready()
_yat = GetNode<YAT>("/root/YAT");
_yat.OptionsChanged += UpdateOptions;

SelectedNode = GetNode<SelectedNode>("%SelectedNode");
SelectedNode.CurrentNodeChanged += OnCurrentNodeChanged;

Context = GetNode<TerminalContext>("%TerminalContext");

_commandManager = _yat.GetNode<CommandManager>("CommandManager");
Expand All @@ -57,6 +62,7 @@ public override void _Ready()

CloseRequested += () => _yat.ToggleOverlay();

OnCurrentNodeChanged(SelectedNode.CurrentNode);
UpdateOptions(_yat.Options);
}

Expand Down Expand Up @@ -121,12 +127,17 @@ public override void _Input(InputEvent @event)

private void UpdateOptions(YatOptions options)
{
_promptLabel.Text = options.Prompt;
OnCurrentNodeChanged(SelectedNode.CurrentNode);
_promptLabel.Visible = options.ShowPrompt;
Size = new((int)options.DefaultWidth, (int)options.DefaultHeight);
Output.ScrollFollowing = options.AutoScroll;
}

private void OnCurrentNodeChanged(Node node)
{
_promptLabel.Text = $"{node.GetPath()} {_yat.Options.Prompt}";
}

/// <summary>
/// Prints the specified text to the terminal with the specified print type.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
[gd_scene load_steps=7 format=3 uid="uid://dsyqv187j7w76"]
[gd_scene load_steps=8 format=3 uid="uid://dsyqv187j7w76"]

[ext_resource type="PackedScene" uid="uid://o1hlj04h0rri" path="res://addons/yat/src/scenes/overlay/components/yat_window/YatWindow.tscn" id="2_0wq7x"]
[ext_resource type="Theme" uid="uid://bbo6sgir4ilud" path="res://addons/yat/src/scenes/overlay/components/terminal/theme/yat_terminal_theme.tres" id="2_8e34l"]
[ext_resource type="Script" path="res://addons/yat/src/scenes/overlay/components/terminal/Terminal.cs" id="2_17k82"]
[ext_resource type="Script" path="res://addons/yat/src/scenes/overlay/components/terminal/components/input/Input.cs" id="3_vlo1w"]
[ext_resource type="PackedScene" uid="uid://dnjobwvlxce2m" path="res://addons/yat/src/scenes/overlay/components/terminal/components/autocompletion/Autocompletion.tscn" id="4_qug7a"]
[ext_resource type="PackedScene" uid="uid://byapbl7njd52y" path="res://addons/yat/src/scenes/overlay/components/terminal/components/terminal_context/TerminalContext.tscn" id="6_letxx"]
[ext_resource type="PackedScene" uid="uid://dmmf70stqcfgm" path="res://addons/yat/src/scenes/overlay/components/terminal/components/selected_node/SelectedNode.tscn" id="7_r2rl8"]

[node name="Terminal" instance=ExtResource("2_0wq7x")]
title = "YAT"
Expand Down Expand Up @@ -56,3 +57,6 @@ script = ExtResource("3_vlo1w")
unique_name_in_owner = true
title = "Context menu"
visible = false

[node name="SelectedNode" parent="." index="1" instance=ExtResource("7_r2rl8")]
unique_name_in_owner = true
Loading