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

Custom context menu #64

Merged
merged 45 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
6869311
Add ContextMenu scene to the project
MASSHUU12 Nov 26, 2023
3802afc
Update context menu theme
MASSHUU12 Nov 26, 2023
508d568
Add yat_context_menu input event keybinding
MASSHUU12 Nov 26, 2023
21f9ef0
Update changelog
MASSHUU12 Nov 26, 2023
959214a
Add ContextMenu class and scene
MASSHUU12 Nov 26, 2023
cf3e2b7
Update ContextMenu.tscn and
MASSHUU12 Nov 26, 2023
babc7cf
Handle yat_context_menu in ContextMenu
MASSHUU12 Nov 26, 2023
db4835d
Add TerminalContext component
MASSHUU12 Nov 26, 2023
2c4bd4e
Add terminal context menu
MASSHUU12 Nov 26, 2023
e42c866
Add TerminalContext class to
MASSHUU12 Nov 27, 2023
d859e7e
Add ContextSubmenu class and scene
MASSHUU12 Nov 27, 2023
b2c0eba
Add hover theme for context menu
MASSHUU12 Nov 27, 2023
780b07b
Fix reference to CommandManager
MASSHUU12 Nov 27, 2023
134e8cf
Update changelog
MASSHUU12 Nov 27, 2023
b03f720
Add quick command functionality to TerminalContext
MASSHUU12 Nov 27, 2023
9c86d88
Update ContextMenu and Terminal settings
MASSHUU12 Nov 27, 2023
f59dede
Add QuickCommands class and resource
MASSHUU12 Nov 27, 2023
8437c24
Update TerminalContext with QuickCommands resource
MASSHUU12 Nov 27, 2023
7ed1396
Make TerminalContext public in Terminal class
MASSHUU12 Nov 27, 2023
356f96a
Hide by default
MASSHUU12 Nov 27, 2023
da07f57
Add QuickCommandsContext class and scene
MASSHUU12 Nov 27, 2023
05ad590
Move quick commands logic to QuickCommandsContext
MASSHUU12 Nov 27, 2023
0531b8b
Update terminal scene
MASSHUU12 Nov 27, 2023
5082ba5
Fixed a bug that incorrectly recognized sentences consisting of a sin…
MASSHUU12 Nov 27, 2023
ee4b004
Add EndsWith text helper method
MASSHUU12 Nov 27, 2023
6f662d4
Add QuickCommands class
MASSHUU12 Nov 27, 2023
06672ae
Add QuickCommands command
MASSHUU12 Nov 27, 2023
199dec1
Update USAGE.md
MASSHUU12 Nov 27, 2023
4df3e90
Update changelog
MASSHUU12 Nov 27, 2023
b7bf148
Handle tokens with length < 2
MASSHUU12 Nov 27, 2023
875d37d
Implement quickcommands command
MASSHUU12 Nov 27, 2023
7f0dba2
Update QuickCommands resource ID in TerminalContext.tscn and QuickCom…
MASSHUU12 Nov 27, 2023
b3334ff
Update docs
MASSHUU12 Nov 27, 2023
beb239c
Update changelog
MASSHUU12 Nov 27, 2023
53309b5
Add StartsWith method to TextHelper
MASSHUU12 Nov 28, 2023
9c58bc4
Add support for sentences in options
MASSHUU12 Nov 28, 2023
ad11b65
Split only by first =
MASSHUU12 Nov 28, 2023
1350dc1
Update changelog
MASSHUU12 Nov 28, 2023
4f33424
Correctly treat one-word options
MASSHUU12 Nov 28, 2023
60d16c7
Reworked qc command
MASSHUU12 Nov 28, 2023
f5566bf
Create terminal documentation
MASSHUU12 Nov 28, 2023
8bb4529
Add StorageHelper class
MASSHUU12 Nov 28, 2023
76d2dca
Add type hint for loading resource
MASSHUU12 Nov 28, 2023
2b799c6
Load & save Quick Commands from disk
MASSHUU12 Nov 28, 2023
03ec8a9
Update docs
MASSHUU12 Nov 28, 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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,28 @@ All notable changes to this project will be documented in this file.

- Cat command.
- Cowsay command.
- QuickCommands command.
- TextHelper.ConcatenateSentence method.
- yat_context_menu input event keybinding.
- Generic context menu.
- Generic context submenu.
- Context menu for terminal.
- Quick Commands for terminal.
- StartsWith & EndsWith text helper method.
- Support for sentences in options.
- Terminal documentation.
- StorageHelper class.

### Changed

- Godot.NET.Sdk version to 4.2.0-rc.2.
- The terminal now distinguishes between sentences wrapped in " or ' and treats them as a whole.
- Renamed keybindings for example scenes.

### Fixed

- The CommandManager variable in YAT was empty, instead of storing a reference to Command Manager.
- Providing an '=' character in an option resulted in incorrect parsing of the option.

## [1.9.0-beta 2023-11-23]

Expand Down
35 changes: 18 additions & 17 deletions addons/yat/docs/BUILTIN_COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@

> More information about each command can be found in their manuals.

| Command | Alias | Description |
| -------- | ------ | -------------------------------------------------------------------------------- |
| cls | clear | Clears the console. |
| man | N/A | Displays the manual for a command. |
| quit | N/A | Quits the game. |
| echo | N/A | Displays the given text. |
| restart | reboot | Restarts the level. |
| options | N/A | Creates the options window. |
| pause | N/A | Toggles the game pause state. |
| whereami | wai | Prints the current scene name and path. |
| list | ls | List all available commands. |
| view | N/A | Changes the rendering mode of the viewport. |
| set | N/A | Sets a variable to a value. Does nothing by default, requires adding extensions. |
| watch | N/A | Runs user-defined (not threaded) commands at regular intervals. |
| history | hist | Manages the command history of the current session. |
| cat | N/A | Prints content of a file. |
| cowsay | N/A | Make a cow say something. |
| Command | Alias | Description |
| ------------- | ------ | -------------------------------------------------------------------------------- |
| cls | clear | Clears the console. |
| man | N/A | Displays the manual for a command. |
| quit | N/A | Quits the game. |
| echo | N/A | Displays the given text. |
| restart | reboot | Restarts the level. |
| options | N/A | Creates the options window. |
| pause | N/A | Toggles the game pause state. |
| whereami | wai | Prints the current scene name and path. |
| list | ls | List all available commands. |
| view | N/A | Changes the rendering mode of the viewport. |
| set | N/A | Sets a variable to a value. Does nothing by default, requires adding extensions. |
| watch | N/A | Runs user-defined (not threaded) commands at regular intervals. |
| history | hist | Manages the command history of the current session. |
| cat | N/A | Prints content of a file. |
| cowsay | N/A | Make a cow say something. |
| quickcommands | qc | Manages Quick Commands. |
31 changes: 31 additions & 0 deletions addons/yat/docs/TERMINAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div align="center">
<h3>Terminal</h1>
<p>Here you will find information on the operation of the terminal.</p>
</div>

## Terminal

### Aborting the command

Interrupting a command is possible only if it runs on a separate thread (and if its work does not end in a fraction of a second).

To terminate the command you must use the keybinding `yat_terminal_interrupt`.

> Remember that sending an interrupt signal does not necessarily mean that the operation of the command will immediately end.

### Context menu

YAT uses the keybinding `yat_context_menu` to launch the context menu, so if you haven't created one, you need to do so to use the context menu.

#### Quick Commands

> Quick Commands are saved in user://yat_qc.tres

The terminal's context menu allows you to run Quick Commands.
These are user-defined command prompts, and you can manage them via the `qc` command.

Example of adding a command to Quick Commands:

```bash
$ qc add -name="Red Hello" -command="echo [color=red]Hello[/color]"
```
2 changes: 2 additions & 0 deletions addons/yat/docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ To use this extension, you need to create these keybindings in your project.
- `yat_terminal_history_previous` - Displays the previous command from history.
- `yat_terminal_interrupt` - Used to stop command working on separate thread.
- `yat_terminal_autocompletion` - Used to scroll through suggestions from autocompletion.
- `yat_context_menu` - Allows to call the context menu.

### Example

Expand All @@ -26,6 +27,7 @@ To use this extension, you need to create these keybindings in your project.

- yat_toggle: `~`
- yat_terminal_interrupt: `Ctrl + C`
- yat_context_menu: `Right Mouse Button`
- yat_terminal_history_next: `Arrow Down`
- yat_terminal_history_previous: `Arrow Up`

Expand Down
3 changes: 3 additions & 0 deletions addons/yat/src/YAT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ public override void _Ready()

Overlay = GD.Load<PackedScene>("res://addons/yat/src/scenes/overlay/Overlay.tscn").Instantiate<Scenes.Overlay.Overlay>();
Overlay.Ready += OnOverlayReady;

OptionsManager = new(this, Options);
CommandManager = GetNode<CommandManager>("./CommandManager");

AddCommand(new Cls(this));
AddCommand(new Man(this));
Expand All @@ -77,6 +79,7 @@ public override void _Ready()
AddCommand(new Restart(this));
AddCommand(new History(this));
AddCommand(new Whereami(this));
AddCommand(new Commands.QuickCommands(this));
}

public override void _Input(InputEvent @event)
Expand Down
79 changes: 79 additions & 0 deletions addons/yat/src/commands/builtin/QuickCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using YAT.Attributes;
using YAT.Enums;
using YAT.Helpers;
using YAT.Interfaces;
using YAT.Scenes.Overlay.Components.Terminal;

namespace YAT.Commands
{
[Command("quickcommands", "Manages Quick Commands.", "[b]Usage[/b]: quickcommands [i]action[/i] [i]name[/i] [i]command[/i]", "qc")]
[Arguments("action:[add, remove, list]")]
[Options("-name=string", "-command=string")]
public sealed class QuickCommands : ICommand
{
public YAT Yat { get; set; }

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

public CommandResult Execute(System.Collections.Generic.Dictionary<string, object> cArgs, params string[] args)
{
string action = (string)cArgs["action"];
string name = cArgs.TryGetValue("-name", out object nameObj) ? (string)nameObj : null;
string command = cArgs.TryGetValue("-command", out object commandObj) ? (string)commandObj : null;

if (action != "list" && string.IsNullOrEmpty(name))
{
Yat.Terminal.Print("You need to provide a command name for this action.", Terminal.PrintType.Error);
return CommandResult.Failure;
}

switch (action)
{
case "add":
return AddQuickCommand(name, command);
case "remove":
return RemoveQuickCommand(name);
default:
foreach (var qc in Yat.Terminal.Context.QuickCommands.QuickCommands.Commands)
{
Yat.Terminal.Print($"[b]{qc.Key}[/b] - {TextHelper.EscapeBBCode(qc.Value)}");
}
break;
}

return CommandResult.Success;
}

private CommandResult AddQuickCommand(string name, string command)
{
if (string.IsNullOrEmpty(command))
{
Yat.Terminal.Print("You need to provide command for this action.", Terminal.PrintType.Error);
return CommandResult.Failure;
}

bool status = Yat.Terminal.Context.QuickCommands.AddQuickCommand(name, command);
string message;

if (status) message = $"Added quick command '{name}'.";
else message = $"Failed to add quick command '{name}'.";

Yat.Terminal.Print(message, status ? Terminal.PrintType.Success : Terminal.PrintType.Error);

return status ? CommandResult.Success : CommandResult.Failure;
}

private CommandResult RemoveQuickCommand(string name)
{
bool status = Yat.Terminal.Context.QuickCommands.RemoveQuickCommand(name);
string message;

if (status) message = $"Removed quick command '{name}'.";
else message = $"Failed to remove quick command '{name}'.";

Yat.Terminal.Print(message, status ? Terminal.PrintType.Success : Terminal.PrintType.Error);

return status ? CommandResult.Success : CommandResult.Failure;
}
}
}
2 changes: 1 addition & 1 deletion addons/yat/src/helpers/CommandHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private static bool ValidateCommandOptions(string name, Dictionary<string, objec
opts[optName] = null; // By default treat the option as not passed

var passedOpt = passedOpts.FirstOrDefault(o => o.StartsWith(optName))
?.Split('=', StringSplitOptions.TrimEntries |
?.Split('=', 2, StringSplitOptions.TrimEntries |
StringSplitOptions.RemoveEmptyEntries
);
string passedOptName = passedOpt?[0];
Expand Down
60 changes: 60 additions & 0 deletions addons/yat/src/helpers/StorageHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Godot;

namespace YAT.Helpers
{
/// <summary>
/// Helper class for saving and loading resources.<br/>
///
/// Supported path are:
/// <list type="unordered">
/// <item> user:// - The user:// path is a user-specific path that is different for each OS. </item>
/// <item> res:// - The res:// path is a read-only path that points to the project folder. </item>
/// <item> relative - Relative paths are relative to the current working directory. </item>
/// <item> absolute - Absolute paths are absolute paths on the filesystem. </item>
/// </list> <br/>
///
/// The actual directory paths for user:// are:
/// <list type="unordered">
/// <item> Windows: %APPDATA%\Godot\app_userdata\[project_name] </item>
/// <item> Linux: ~/.local/share/godot/app_userdata/[project_name] </item>
/// <item> macOS: ~/Library/Application Support/Godot/app_userdata/[project_name] </item>
/// </list>
///
/// See: https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html
/// </summary>
public static class StorageHelper
{
/// <summary>
/// Saves the specified resource to the given path.
/// </summary>
/// <param name="resource">The resource to save.</param>
/// <param name="path">The path to save the resource to.</param>
/// <param name="flags">Optional flags for saving the resource.</param>
/// <returns>True if the resource was saved successfully, false otherwise.</returns>
public static bool SaveResource(
Resource resource,
string path,
ResourceSaver.SaverFlags flags = ResourceSaver.SaverFlags.None
)
{
return ResourceSaver.Save(resource, path, flags) switch
{
Error.Ok => true,
_ => false,
};
}

/// <summary>
/// Loads a resource of the specified type from the given path.
/// </summary>
/// <typeparam name="T">The type of resource to load.</typeparam>
/// <param name="path">The path to load the resource from.</param>
/// <returns>The loaded resource, or null if the resource does not exist.</returns>
public static T LoadResource<T>(string path) where T : Resource
{
if (!ResourceLoader.Exists(path, nameof(T))) return null;

return ResourceLoader.Load<T>(path);
}
}
}
66 changes: 60 additions & 6 deletions addons/yat/src/helpers/TextHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,47 @@ public static string[] ConcatenateSentence(string[] strings)
{
List<string> modifiedStrings = new();

for (int i = 0; i < strings.Length; i++)
for (ushort i = 0; i < strings.Length; i++)
{
if (strings[i].IndexOfAny(new[] { '"', '\'' }) == 0)
string token = strings[i];
bool startsWith = StartsWith(token, '"', '\'');

// If the token starts and ends with quotation marks, remove them
if (startsWith && EndsWith(token, '"', '\''))
{
modifiedStrings.Add(token.Length > 1 ? token[1..^1] : token[1..]);
continue;
}

// Handle sentences in options (e.g. -name="John Doe")
if (StartsWith(token, '-') &&
(token.Contains('"') || token.Contains('\''))
&& !EndsWith(token, '"', '\'')
)
{
string sentence = token.Replace("\"", string.Empty).Replace("'", string.Empty);

// Concatenate the next strings until the end of the sentence is reached
while (!EndsWith(strings[i], '"', '\'') && i < strings.Length)
{
i++;
if (i >= strings.Length) break;

sentence += $" {strings[i]}";
}

sentence = i >= strings.Length ? sentence : sentence[..^1];
modifiedStrings.Add(sentence);
continue;
}

// If the token starts with a quotation mark, concatenate the next strings
if (startsWith)
{
string sentence = strings[i][1..];

while (!(strings[i].IndexOfAny(new[] { '"', '\'' }) == strings[i].Length - 1)
&& i < strings.Length
)
// Concatenate the next strings until the end of the sentence is reached
while (!EndsWith(strings[i], '"', '\'') && i < strings.Length)
{
i++;
if (i >= strings.Length) break;
Expand All @@ -72,10 +104,32 @@ public static string[] ConcatenateSentence(string[] strings)
sentence = i >= strings.Length ? sentence : sentence[..^1];
modifiedStrings.Add(sentence);
}
else modifiedStrings.Add(strings[i]);
else modifiedStrings.Add(token);
}

return modifiedStrings.ToArray();
}

/// <summary>
/// Determines whether the specified string starts with any of the specified characters.
/// </summary>
/// <param name="text">The string to check.</param>
/// <param name="value">The characters to compare.</param>
/// <returns><c>true</c> if the string starts with any of the specified characters; otherwise, <c>false</c>.</returns>
public static bool StartsWith(string text, params char[] value)
{
return value.Any(text.StartsWith);
}

/// <summary>
/// Determines whether the specified text ends with any of the specified characters.
/// </summary>
/// <param name="text">The text to check.</param>
/// <param name="value">The characters to compare against the end of the text.</param>
/// <returns><c>true</c> if the text ends with any of the specified characters; otherwise, <c>false</c>.</returns>
public static bool EndsWith(string text, params char[] value)
{
return value.Any(text.EndsWith);
}
}
}
Loading