From 115d4e4627fbb3c67997304d56ee4fd62909e7f0 Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Wed, 1 Jul 2026 12:05:44 -0300 Subject: [PATCH 1/6] Update to use Palette --- Silkstring/UI/Palette.cs | 5 +++ Silkstring/UI/Panels/AliasEditPanel.cs | 2 +- Silkstring/UI/Panels/AliasSelectPanel.cs | 4 +-- Silkstring/Windows/ChangelogWindow.cs | 5 ++- Silkstring/Windows/HelpWindow.cs | 45 ++++++++++++------------ Silkstring/Windows/VariablesWindow.cs | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Silkstring/UI/Palette.cs b/Silkstring/UI/Palette.cs index 8879bb4..2f6f05a 100644 --- a/Silkstring/UI/Palette.cs +++ b/Silkstring/UI/Palette.cs @@ -4,5 +4,10 @@ namespace Silkstring.UI; public static class Palette { + public static readonly Vector4 Heading = new(0.7f, 0.5f, 1.0f, 1.0f); + public static readonly Vector4 Folder = new(0.7f, 0.5f, 1.0f, 1.0f); + public static readonly Vector4 Error = new(1.0f, 0.4f, 0.4f, 1.0f); + public static readonly Vector4 Success = new(0.4f, 1.0f, 0.4f, 1.0f); + public static readonly Vector4 VariableToken = new(0.4f, 0.8f, 1.0f, 1.0f); } diff --git a/Silkstring/UI/Panels/AliasEditPanel.cs b/Silkstring/UI/Panels/AliasEditPanel.cs index c8cbbc5..d38bbc3 100644 --- a/Silkstring/UI/Panels/AliasEditPanel.cs +++ b/Silkstring/UI/Panels/AliasEditPanel.cs @@ -47,7 +47,7 @@ public void Draw() ImGui.Separator(); if (_blockError != null) { - ImGui.TextColored(new Vector4(1f, 0.4f, 0.4f, 1f), _blockError); + ImGui.TextColored(Palette.Error, _blockError); ImGui.Spacing(); } DrawCommandList(alias); diff --git a/Silkstring/UI/Panels/AliasSelectPanel.cs b/Silkstring/UI/Panels/AliasSelectPanel.cs index 639e61d..4d40221 100644 --- a/Silkstring/UI/Panels/AliasSelectPanel.cs +++ b/Silkstring/UI/Panels/AliasSelectPanel.cs @@ -24,8 +24,6 @@ public class AliasSelectPanel private const string DragDropType = "ALIAS"; - private static readonly Vector4 FolderColor = new(0.7f, 0.5f, 1.0f, 1.0f); - public AliasSelectPanel(Configuration configuration, MainWindow mainWindow) { _configuration = configuration; @@ -86,7 +84,7 @@ private void DrawFolders() } else { - ImGui.PushStyleColor(ImGuiCol.Text, FolderColor); + ImGui.PushStyleColor(ImGuiCol.Text, Palette.Folder); open = ImGui.TreeNodeEx($"{folder.Name}###{folder.UniqueId}folder", ImGuiTreeNodeFlags.SpanAvailWidth); ImGui.PopStyleColor(); diff --git a/Silkstring/Windows/ChangelogWindow.cs b/Silkstring/Windows/ChangelogWindow.cs index 5a8daf0..613f48d 100644 --- a/Silkstring/Windows/ChangelogWindow.cs +++ b/Silkstring/Windows/ChangelogWindow.cs @@ -5,13 +5,12 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Windowing; using Silkstring.Services; +using Silkstring.UI; namespace Silkstring.Windows; public class ChangelogWindow : Window, IDisposable { - private static readonly Vector4 HeadingColor = new(0.7f, 0.5f, 1.0f, 1.0f); - private readonly IReadOnlyList _sections; private readonly string[] _versions; private int _selected; @@ -63,7 +62,7 @@ private static void DrawBody(string body) else if (line.StartsWith("### ")) { ImGui.Spacing(); - ImGui.TextColored(HeadingColor, line[4..]); + ImGui.TextColored(Palette.Heading, line[4..]); ImGui.Separator(); } else if (line.StartsWith(" - ")) diff --git a/Silkstring/Windows/HelpWindow.cs b/Silkstring/Windows/HelpWindow.cs index d30fb0b..e35199e 100644 --- a/Silkstring/Windows/HelpWindow.cs +++ b/Silkstring/Windows/HelpWindow.cs @@ -21,8 +21,7 @@ private enum Tab } private Tab _selectedTab = Tab.Commands; - - private static readonly Vector4 HeadingColor = new(0.7f, 0.5f, 1.0f, 1.0f); + private string _testerInput = string.Empty; private readonly CommandResolver _resolver; @@ -78,7 +77,7 @@ public override void Draw() private void DrawCommandTester() { - ImGui.TextColored(HeadingColor, "Command Tester"); + ImGui.TextColored(Palette.Heading, "Command Tester"); ImGui.Spacing(); ImGui.SetNextItemWidth(-1); ImGui.InputTextWithHint("###testerInput", "Enter a command e.g. /say Hello {character}!", ref _testerInput, 200); @@ -94,19 +93,19 @@ private void DrawCommandTester() else if (resolved == _testerInput) ImGui.TextDisabled(resolved); else - ImGui.TextColored(new Vector4(0.4f, 1f, 0.4f, 1f), resolved); + ImGui.TextColored(Palette.Success, resolved); } private void DrawCommandsHelp() { - ImGui.TextColored(HeadingColor, "What is an Alias?"); + ImGui.TextColored(Palette.Heading, "What is an Alias?"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("An alias lets you create a custom chat command that fires one or more FFXIV commands in sequence. " + "Type your trigger in the chat box just like any other command and Silkstring will intercept it and execute your defined command list."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Triggers"); + ImGui.TextColored(Palette.Heading, "Triggers"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("A trigger is the command you type in chat to activate the alias. Triggers must start with a forward slash when used in chat, " + @@ -115,7 +114,7 @@ private void DrawCommandsHelp() ImGui.BulletText("Triggers cannot contain spaces."); ImGui.BulletText("Triggers should not conflict with built-in FFXIV or Dalamud commands."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Multiple Triggers"); + ImGui.TextColored(Palette.Heading, "Multiple Triggers"); ImGui.Spacing(); ImGui.TextWrapped("You can assign multiple triggers to a single alias by separating them with a pipe character:"); ImGui.Spacing(); @@ -126,7 +125,7 @@ private void DrawCommandsHelp() ImGui.TextWrapped("Any of these typed in chat will fire the same alias."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Commands"); + ImGui.TextColored(Palette.Heading, "Commands"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Commands are the actions Silkstring runs when your alias is triggered. Each command must start with a slash, exactly as you would type it into the chat box."); @@ -142,7 +141,7 @@ private void DrawCommandsHelp() ImGui.Unindent(); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Chat Messages"); + ImGui.TextColored(Palette.Heading, "Chat Messages"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Any line that does not start with a slash is sent as a chat message to whatever channel you currently have active."); @@ -156,7 +155,7 @@ private void DrawCommandsHelp() ImGui.Unindent(); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Variables"); + ImGui.TextColored(Palette.Heading, "Variables"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Variables let you insert dynamic values into your commands at execution time using curly brace syntax:"); @@ -169,19 +168,19 @@ private void DrawCommandsHelp() "See the Variables tab for a full list of supported variables."); ImGui.TextWrapped("You can also define your own variables, see the Variables tab."); - ImGui.TextColored(HeadingColor, "Parameters"); + ImGui.TextColored(Palette.Heading, "Parameters"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Aliases can take arguments typed after the trigger, inserted with numbered braces like {0}. See the Parameters tab for the full syntax."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Conditionals"); + ImGui.TextColored(Palette.Heading, "Conditionals"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Run commands only when a condition is true with :if / :else / :endif blocks, and pause with :wait. See the Conditionals tab."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Macros"); + ImGui.TextColored(Palette.Heading, "Macros"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Silkstring aliases are intentionally disabled when called from within FFXIV macros. " + @@ -189,7 +188,7 @@ private void DrawCommandsHelp() "Aliases must be typed directly into the chat box to function."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Cycles & Recursion"); + ImGui.TextColored(Palette.Heading, "Cycles & Recursion"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("A cycle occurs when an alias triggers itself either directly or through a chain of other aliases:"); @@ -207,7 +206,7 @@ private void DrawCommandsHelp() private void DrawVariablesHelp() { - ImGui.TextColored(HeadingColor, "What are Variables?"); + ImGui.TextColored(Palette.Heading, "What are Variables?"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Variables let you insert dynamic values into your commands at execution time. " + @@ -223,7 +222,7 @@ private void DrawVariablesHelp() "it is left as-is in the command string rather than being replaced with an empty value."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Your Own Variables"); + ImGui.TextColored(Palette.Heading, "Your Own Variables"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Besides the built-in variables below, you can define your own. Open the Variables window with /silkstring variables, give it a name and a value, then use it anywhere with {name}."); @@ -238,7 +237,7 @@ private void DrawVariablesHelp() ImGui.TextWrapped("A :set only works on a variable you have already created. The alias editor warns you if it names one that does not exist."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Available Variables"); + ImGui.TextColored(Palette.Heading, "Available Variables"); ImGui.Separator(); ImGui.Spacing(); @@ -250,7 +249,7 @@ private void DrawVariablesHelp() private void DrawVariableCategory(string category, IEnumerable variables) { - ImGui.TextColored(HeadingColor, category); + ImGui.TextColored(Palette.Heading, category); if (ImGui.BeginTable($"###varTable_{category}", 3, ImGuiTableFlags.BordersInnerH | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersOuter)) { ImGui.TableSetupColumn("Variable", ImGuiTableColumnFlags.WidthFixed, 120); @@ -277,7 +276,7 @@ private void DrawVariableRow(string variable, string description, string current private void DrawParametersHelp() { - ImGui.TextColored(HeadingColor, "What are Parameters?"); + ImGui.TextColored(Palette.Heading, "What are Parameters?"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Parameters let an alias take arguments. Anything you type after the trigger becomes a numbered argument, starting at zero, that you insert into command lines with curly braces."); @@ -293,7 +292,7 @@ private void DrawParametersHelp() ImGui.TextWrapped("If you reference an argument that was not supplied, it is left as written (for example {3} stays {3})."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Parameter Tokens"); + ImGui.TextColored(Palette.Heading, "Parameter Tokens"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Ranges work like C# ranges: the end is exclusive."); @@ -326,7 +325,7 @@ private void DrawParameterRow(string token, string meaning) private void DrawConditionalsHelp() { - ImGui.TextColored(HeadingColor, "What are Conditionals?"); + ImGui.TextColored(Palette.Heading, "What are Conditionals?"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Conditionals let an alias run some commands only when a condition is true. They use block syntax: everything between :if and :endif runs only when the condition holds."); @@ -345,7 +344,7 @@ private void DrawConditionalsHelp() ImGui.BulletText("The :if, :else, and :endif lines are never sent to chat."); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Conditions"); + ImGui.TextColored(Palette.Heading, "Conditions"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("A condition either compares two values, or checks a true/false variable on its own. Comparisons can be combined with and (&&) and or (||)."); @@ -365,7 +364,7 @@ private void DrawConditionalsHelp() ImGui.Unindent(); ImGui.Spacing(); - ImGui.TextColored(HeadingColor, "Waits"); + ImGui.TextColored(Palette.Heading, "Waits"); ImGui.Separator(); ImGui.Spacing(); ImGui.TextWrapped("Pause between lines with :wait, followed by a number of seconds. Decimals work, and the duration can come from a variable or parameter. Waits are capped at 60 seconds, and a :wait inside a condition only pauses when that branch runs. Like the other control lines, it is never sent to chat."); diff --git a/Silkstring/Windows/VariablesWindow.cs b/Silkstring/Windows/VariablesWindow.cs index b8c18e3..a59da56 100644 --- a/Silkstring/Windows/VariablesWindow.cs +++ b/Silkstring/Windows/VariablesWindow.cs @@ -58,7 +58,7 @@ private void DrawAddRow() } } ImGuiUtil.Tooltip("Add Variable"); - if (_addError != null) ImGui.TextColored(new Vector4(1f, 0.4f, 0.4f, 1f), _addError); + if (_addError != null) ImGui.TextColored(Palette.Error, _addError); } private void DrawList() From 0256e739c10b957f79eb9922ee54df3e627266a3 Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:57:13 -0300 Subject: [PATCH 2/6] Add config for theme --- Silkstring/Configuration.cs | 2 ++ Silkstring/Models/ThemeColors.cs | 17 ++++++++++++ Silkstring/Plugin.cs | 3 +++ Silkstring/UI/Palette.cs | 29 +++++++++++++++++---- Silkstring/Windows/ConfigWindow.cs | 42 ++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 Silkstring/Models/ThemeColors.cs diff --git a/Silkstring/Configuration.cs b/Silkstring/Configuration.cs index 0fccfe8..3efc3dc 100644 --- a/Silkstring/Configuration.cs +++ b/Silkstring/Configuration.cs @@ -24,9 +24,11 @@ public int CommandDelay public const int CurrentVersion = 2; public string? LastSeenVersion { get; set; } public int Version { get; set; } = CurrentVersion; + public List Folders = new(); public List Aliases = new(); public List UserVariables = new(); + public ThemeColors Theme = new(); public bool MultilineCommands { get; set; } public void Save() diff --git a/Silkstring/Models/ThemeColors.cs b/Silkstring/Models/ThemeColors.cs new file mode 100644 index 0000000..9542521 --- /dev/null +++ b/Silkstring/Models/ThemeColors.cs @@ -0,0 +1,17 @@ +using System.Numerics; + +namespace Silkstring.Models; + +public class ThemeColors +{ + public Vector4 Heading = new(0.7f, 0.5f, 1.0f, 1.0f); + public Vector4 Folder = new(0.7f, 0.5f, 1.0f, 1.0f); + public Vector4 Error = new(1.0f, 0.4f, 0.4f, 1.0f); + public Vector4 Success = new(0.4f, 1.0f, 0.4f, 1.0f); + public Vector4 VariableToken = new(0.4f, 0.8f, 1.0f, 1.0f); + public Vector4 ParameterToken = new(1.0f, 0.6f, 0.3f, 1.0f); + public Vector4 ControlKeyword = new(0.85f, 0.5f, 0.8f, 1.0f); + public Vector4 Command = new(0.9f, 0.7f, 0.3f, 1.0f); + public Vector4 Operator = new(0.6f, 0.7f, 0.8f, 1.0f); + public Vector4 ChatText = new(0.9f, 0.9f, 0.9f, 1.0f); +} diff --git a/Silkstring/Plugin.cs b/Silkstring/Plugin.cs index 7abf7ac..350d445 100644 --- a/Silkstring/Plugin.cs +++ b/Silkstring/Plugin.cs @@ -11,6 +11,7 @@ using ECommons; using Silkstring.Services; using Silkstring.Services.Variables; +using Silkstring.UI; using Silkstring.Windows; namespace Silkstring; @@ -45,6 +46,7 @@ public sealed class Plugin : IDalamudPlugin public Plugin() { Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); + Palette.Apply(Configuration.Theme); var migration = ConfigMigrator.Migrate(Configuration, PluginInterface); if (migration != null) @@ -140,6 +142,7 @@ private void OnCommand(string command, string args) case "help": ToggleHelpUi(); break; case "changelog": ToggleChangelogUi(); break; case "variables": ToggleVariablesUi(); break; + case "edit": ToggleConfigUi(); break; default: MainWindow.Toggle(); break; } } diff --git a/Silkstring/UI/Palette.cs b/Silkstring/UI/Palette.cs index 2f6f05a..e0600ae 100644 --- a/Silkstring/UI/Palette.cs +++ b/Silkstring/UI/Palette.cs @@ -1,13 +1,32 @@ using System.Numerics; +using Silkstring.Models; namespace Silkstring.UI; public static class Palette { - public static readonly Vector4 Heading = new(0.7f, 0.5f, 1.0f, 1.0f); - public static readonly Vector4 Folder = new(0.7f, 0.5f, 1.0f, 1.0f); - public static readonly Vector4 Error = new(1.0f, 0.4f, 0.4f, 1.0f); - public static readonly Vector4 Success = new(0.4f, 1.0f, 0.4f, 1.0f); + public static Vector4 Heading; + public static Vector4 Folder; + public static Vector4 Error; + public static Vector4 Success; + public static Vector4 VariableToken; + public static Vector4 ParameterToken; + public static Vector4 ControlKeyword; + public static Vector4 Command; + public static Vector4 Operator; + public static Vector4 ChatText; - public static readonly Vector4 VariableToken = new(0.4f, 0.8f, 1.0f, 1.0f); + public static void Apply(ThemeColors t) + { + Heading = t.Heading; + Folder = t.Folder; + Error = t.Error; + Success = t.Success; + VariableToken = t.VariableToken; + ParameterToken = t.ParameterToken; + ControlKeyword = t.ControlKeyword; + Command = t.Command; + Operator = t.Operator; + ChatText = t.ChatText; + } } diff --git a/Silkstring/Windows/ConfigWindow.cs b/Silkstring/Windows/ConfigWindow.cs index 427c628..c9ba4f7 100644 --- a/Silkstring/Windows/ConfigWindow.cs +++ b/Silkstring/Windows/ConfigWindow.cs @@ -1,13 +1,23 @@ using System; using Dalamud.Interface.Windowing; using System.Numerics; +using System.Reflection; +using System.Text.RegularExpressions; using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Components; +using Silkstring.Models; +using Silkstring.UI; namespace Silkstring.Windows; + public class ConfigWindow : Window, IDisposable { private readonly Configuration configuration; + private static readonly FieldInfo[] ThemeFields = typeof(ThemeColors).GetFields(); + private static readonly ThemeColors Defaults = new(); + private static string Prettify(string name) => Regex.Replace(name, "(\\B[A-Z])", " $1"); public ConfigWindow(Plugin plugin) : base("Silkstring Settings###Config") { @@ -50,6 +60,38 @@ public override void Draw() configuration.Save(); } + if (ImGui.CollapsingHeader("Colors")) + { + void Sync() { Palette.Apply(configuration.Theme); configuration.MarkDirty(); } + + foreach (var field in ThemeFields) + { + if (ImGuiComponents.IconButton($"reset{field.Name}", FontAwesomeIcon.Undo)) + { + field.SetValue(configuration.Theme, field.GetValue(Defaults)); + Sync(); + } + ImGuiUtil.Tooltip("Reset to default"); + ImGui.SameLine(); + + var value = (Vector4)field.GetValue(configuration.Theme)!; + if (ImGui.ColorEdit4($"{Prettify(field.Name)}##{field.Name}", ref value, ImGuiColorEditFlags.NoInputs)) + { + field.SetValue(configuration.Theme, value); + Sync(); + } + } + + if (ImGui.Button("Reset colors")) + { + configuration.Theme = new ThemeColors(); + Palette.Apply(configuration.Theme); + configuration.Save(); + + } + + } + var availableHeight = ImGui.GetContentRegionAvail().Y; var buttonHeight = ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y + ImGui.GetStyle().WindowPadding.Y * 2 + 4; ImGui.SetCursorPosY(ImGui.GetCursorPosY() + availableHeight - buttonHeight); From 1d924d274cdcc7d1dcf2ddde05ccfc86b060b622 Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:19:29 -0300 Subject: [PATCH 3/6] Include DalamudTextEdit --- .gitmodules | 3 +++ Silkstring.sln | 43 +++++++++++++++++++++++++++++++---- Silkstring/Silkstring.csproj | 4 ++++ Silkstring/packages.lock.json | 3 +++ extern/DalamudTextEdit | 1 + 5 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 .gitmodules create mode 160000 extern/DalamudTextEdit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..07cc53d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extern/DalamudTextEdit"] + path = extern/DalamudTextEdit + url = https://github.com/devoreofox/DalamudTextEdit.git diff --git a/Silkstring.sln b/Silkstring.sln index abca2b9..efa4443 100644 --- a/Silkstring.sln +++ b/Silkstring.sln @@ -7,28 +7,63 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silkstring", "Silkstring\Si EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{BC8C19B7-F609-4B27-A05B-03D50E7E46BB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "extern", "extern", "{8C8C186C-83DC-ECBC-707A-D920EEBF6757}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DalamudTextEdit", "extern\DalamudTextEdit\DalamudTextEdit.csproj", "{B36EF61A-B235-4249-925B-FC6C0DB568EA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 Release|x64 = Release|x64 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64 {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x86.ActiveCfg = Debug|Any CPU + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x86.Build.0 = Debug|Any CPU {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64 {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Debug|x64.ActiveCfg = Debug|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Debug|x64.Build.0 = Debug|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Release|x64.ActiveCfg = Release|x64 - {4FEC9558-EB25-419F-B86E-51B8CFDA32B7}.Release|x64.Build.0 = Release|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|Any CPU.Build.0 = Release|Any CPU + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x86.ActiveCfg = Release|Any CPU + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x86.Build.0 = Release|Any CPU {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Debug|x64.ActiveCfg = Debug|Any CPU {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Debug|x64.Build.0 = Debug|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Debug|x86.Build.0 = Debug|Any CPU {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Release|x64.ActiveCfg = Release|Any CPU {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Release|x64.Build.0 = Release|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Release|Any CPU.Build.0 = Release|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Release|x86.ActiveCfg = Release|Any CPU + {BC8C19B7-F609-4B27-A05B-03D50E7E46BB}.Release|x86.Build.0 = Release|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Debug|x64.ActiveCfg = Debug|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Debug|x64.Build.0 = Debug|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Debug|x86.ActiveCfg = Debug|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Debug|x86.Build.0 = Debug|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Release|x64.ActiveCfg = Release|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Release|x64.Build.0 = Release|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Release|Any CPU.Build.0 = Release|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Release|x86.ActiveCfg = Release|Any CPU + {B36EF61A-B235-4249-925B-FC6C0DB568EA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B36EF61A-B235-4249-925B-FC6C0DB568EA} = {8C8C186C-83DC-ECBC-707A-D920EEBF6757} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} EndGlobalSection diff --git a/Silkstring/Silkstring.csproj b/Silkstring/Silkstring.csproj index 8bc1ab1..f06fbab 100644 --- a/Silkstring/Silkstring.csproj +++ b/Silkstring/Silkstring.csproj @@ -22,6 +22,10 @@ + + + + diff --git a/Silkstring/packages.lock.json b/Silkstring/packages.lock.json index b4c31dc..5c4cf0d 100644 --- a/Silkstring/packages.lock.json +++ b/Silkstring/packages.lock.json @@ -19,6 +19,9 @@ "requested": "[3.2.0.18, )", "resolved": "3.2.0.18", "contentHash": "esPIjfuveuw05c4PI7gqpRcifaUaUZ9sf7JnN90CBM1Ah2emxTBrKQl6A+ghHobwQOOe+yflN03TJnv32NEkVw==" + }, + "dalamudtextedit": { + "type": "Project" } } } diff --git a/extern/DalamudTextEdit b/extern/DalamudTextEdit new file mode 160000 index 0000000..b41c8b3 --- /dev/null +++ b/extern/DalamudTextEdit @@ -0,0 +1 @@ +Subproject commit b41c8b3692e809be5a6fb1a20415493db905e14e From b47f2eeb5336fdced0b8de25e242a0c34b370e4f Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Wed, 1 Jul 2026 20:09:06 -0300 Subject: [PATCH 4/6] Hook in token recognition and rework colors --- Silkstring/Configuration.cs | 2 + Silkstring/Models/ThemeColors.cs | 12 +- Silkstring/UI/Palette.cs | 28 ++--- Silkstring/UI/Panels/AliasEditPanel.cs | 44 ++++--- Silkstring/UI/SilkstringHighlighter.cs | 152 +++++++++++++++++++++++++ Silkstring/Windows/ConfigWindow.cs | 7 ++ Silkstring/Windows/HelpWindow.cs | 2 +- extern/DalamudTextEdit | 2 +- 8 files changed, 204 insertions(+), 45 deletions(-) create mode 100644 Silkstring/UI/SilkstringHighlighter.cs diff --git a/Silkstring/Configuration.cs b/Silkstring/Configuration.cs index 3efc3dc..cdc8332 100644 --- a/Silkstring/Configuration.cs +++ b/Silkstring/Configuration.cs @@ -28,7 +28,9 @@ public int CommandDelay public List Folders = new(); public List Aliases = new(); public List UserVariables = new(); + public ThemeColors Theme = new(); + public bool ShowLineNumbers = true; public bool MultilineCommands { get; set; } public void Save() diff --git a/Silkstring/Models/ThemeColors.cs b/Silkstring/Models/ThemeColors.cs index 9542521..162e2c2 100644 --- a/Silkstring/Models/ThemeColors.cs +++ b/Silkstring/Models/ThemeColors.cs @@ -8,10 +8,10 @@ public class ThemeColors public Vector4 Folder = new(0.7f, 0.5f, 1.0f, 1.0f); public Vector4 Error = new(1.0f, 0.4f, 0.4f, 1.0f); public Vector4 Success = new(0.4f, 1.0f, 0.4f, 1.0f); - public Vector4 VariableToken = new(0.4f, 0.8f, 1.0f, 1.0f); - public Vector4 ParameterToken = new(1.0f, 0.6f, 0.3f, 1.0f); - public Vector4 ControlKeyword = new(0.85f, 0.5f, 0.8f, 1.0f); - public Vector4 Command = new(0.9f, 0.7f, 0.3f, 1.0f); - public Vector4 Operator = new(0.6f, 0.7f, 0.8f, 1.0f); - public Vector4 ChatText = new(0.9f, 0.9f, 0.9f, 1.0f); + public Vector4 Variable = new(0.9f, 0.8f, 0.4f, 1.0f); + public Vector4 Parameter = new(1.0f, 0.6f, 0.3f, 1.0f); + public Vector4 Keyword = new(0.4f, 0.8f, 1.0f, 1.0f); + public Vector4 String = new(0.6f, 0.8f, 0.5f, 1.0f); + public Vector4 Command = new(0.7f, 0.5f, 1.0f, 1.0f); + public Vector4 Text = new(0.9f, 0.9f, 0.9f, 1.0f); } diff --git a/Silkstring/UI/Palette.cs b/Silkstring/UI/Palette.cs index e0600ae..9dee9f2 100644 --- a/Silkstring/UI/Palette.cs +++ b/Silkstring/UI/Palette.cs @@ -5,28 +5,28 @@ namespace Silkstring.UI; public static class Palette { + public static Vector4 Variable; + public static Vector4 Parameter; + public static Vector4 Keyword; + public static Vector4 String; + public static Vector4 Command; + public static Vector4 Text; + public static Vector4 Error; public static Vector4 Heading; public static Vector4 Folder; - public static Vector4 Error; public static Vector4 Success; - public static Vector4 VariableToken; - public static Vector4 ParameterToken; - public static Vector4 ControlKeyword; - public static Vector4 Command; - public static Vector4 Operator; - public static Vector4 ChatText; public static void Apply(ThemeColors t) { + Variable = t.Variable; + Parameter = t.Parameter; + Keyword = t.Keyword; + String = t.String; + Command = t.Command; + Text = t.Text; + Error = t.Error; Heading = t.Heading; Folder = t.Folder; - Error = t.Error; Success = t.Success; - VariableToken = t.VariableToken; - ParameterToken = t.ParameterToken; - ControlKeyword = t.ControlKeyword; - Command = t.Command; - Operator = t.Operator; - ChatText = t.ChatText; } } diff --git a/Silkstring/UI/Panels/AliasEditPanel.cs b/Silkstring/UI/Panels/AliasEditPanel.cs index d38bbc3..e8de8cc 100644 --- a/Silkstring/UI/Panels/AliasEditPanel.cs +++ b/Silkstring/UI/Panels/AliasEditPanel.cs @@ -5,6 +5,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Components; +using ImGuiColorTextEditNet; using Silkstring.Models; using Silkstring.Services; using Silkstring.Windows; @@ -19,18 +20,23 @@ public class AliasEditPanel private List? _detectedCycle; private string? _blockError; - private string _multilineBuffer = string.Empty; - private int _multilineAliasId = -1; + private readonly TextEditor _editor; + private int _editorAliasId = -1; public AliasEditPanel(Configuration configuration, MainWindow mainWindow) { + _configuration = configuration; + _editor = new TextEditor + { + SyntaxHighlighter = new SilkstringHighlighter(() => new HashSet(_configuration.UserVariables.Select(v => v.Name), StringComparer.OrdinalIgnoreCase)) + }; + _editor.Renderer.ColorizeEveryFrame = true; mainWindow.SelectionChanged += (alias, _) => { _selectedAlias = alias; if (alias != null) RefreshCycleCheck(); else { _detectedCycle = null; _blockError = null; } }; - _configuration = configuration; } public void Draw() @@ -95,21 +101,20 @@ private void DrawCommandList(AliasEntry alias) private void DrawMultilineView(AliasEntry alias) { - SyncMultilineBuffer(alias); + if (_editorAliasId != alias.UniqueId) + { + _editor.AllText = string.Join("\n", alias.Output.Select(c => c.Command)); + _editorAliasId = alias.UniqueId; + } - if (ImGui.InputTextMultiline($"###multiline{alias.UniqueId}", ref _multilineBuffer, 5000, new Vector2(-1, ImGui.GetContentRegionAvail().Y))) + _editor.Renderer.ShowLineNumbers = _configuration.ShowLineNumbers; + SilkstringHighlighter.ApplyPalette(_editor); + + if (_editor.Render("###aliasEditor", new Vector2(-1, ImGui.GetContentRegionAvail().Y))) { - if (ImGui.IsKeyPressed(ImGuiKey.Escape)) - { - _multilineAliasId = -1; - } - - else - { - ApplyMultiline(alias, _multilineBuffer); - _configuration.MarkDirty(); - RefreshCycleCheck(); - } + ApplyMultiline(alias, _editor.AllText); + _configuration.MarkDirty(); + RefreshCycleCheck(); } } @@ -158,13 +163,6 @@ private void RefreshCycleCheck() _blockError = AliasValidator.ValidateBlocks(_selectedAlias) ?? AliasValidator.ValidateSets(_selectedAlias, defined) ?? AliasValidator.ValidateWaits(_selectedAlias); } - private void SyncMultilineBuffer(AliasEntry alias) - { - if (_multilineAliasId == alias.UniqueId) return; - _multilineBuffer = string.Join("\n", alias.Output.Select(c => c.Command)); - _multilineAliasId = alias.UniqueId; - } - private static void ApplyMultiline(AliasEntry alias, string text) { var lines = text.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); diff --git a/Silkstring/UI/SilkstringHighlighter.cs b/Silkstring/UI/SilkstringHighlighter.cs new file mode 100644 index 0000000..5972388 --- /dev/null +++ b/Silkstring/UI/SilkstringHighlighter.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text.RegularExpressions; +using Dalamud.Bindings.ImGui; +using ImGuiColorTextEditNet; +using ImGuiColorTextEditNet.Syntax; +using Silkstring.Services.Conditions; + +namespace Silkstring.UI; + +public sealed class SilkstringHighlighter : ISyntaxHighlighter +{ + private const PaletteIndex Error = PaletteIndex.CharLiteral; + + private static readonly object Empty = new(); + private static readonly Regex TokenRegex = new(@"\{(\d+\.\.\d+|\.\.\d+|\d+\.\.|\w+|\*)\}", RegexOptions.Compiled); + private static readonly Regex StringRegex = new("\"[^\"]*\"?", RegexOptions.Compiled); + + private readonly Func> _definedVariables; + + public SilkstringHighlighter(Func> definedVariables) => _definedVariables = definedVariables; + + public bool AutoIndentation => false; + public int MaxLinesPerFrame => 1000; + public string? GetTooltip(string id) => null; + + public object Colorize(Span line, object? state) + { + var chars = new char[line.Length]; + for (var i = 0; i < line.Length; i++) + { + chars[i] = line[i].Char; + line[i] = new Glyph(line[i].Char, PaletteIndex.Default); + } + var text = new string(chars); + + var (kind, expression) = BlockInterpreter.Classify(text); + var exprStart = text.Length - expression.Length; + + switch (kind) + { + case BlockKind.If: + Paint(line, 0, exprStart, PaletteIndex.Keyword); + if (TryParseCondition(expression)) PaintContent(line, text, exprStart); + else Paint(line, exprStart, text.Length, Error); + break; + + case BlockKind.Else: + case BlockKind.EndIf: + Paint(line, 0, exprStart, PaletteIndex.Keyword); + break; + + case BlockKind.Set: + Paint(line, 0, exprStart, PaletteIndex.Keyword); + var (name, _) = BlockInterpreter.ParseSet(expression); + if (name.Length == 0 || !_definedVariables().Contains(name)) + Paint(line, exprStart, exprStart + Math.Max(name.Length, 1), Error); + PaintContent(line, text, exprStart + name.Length); + break; + + case BlockKind.Wait: + Paint(line, 0, exprStart, PaletteIndex.Keyword); + if (!expression.Contains('{') && !BlockInterpreter.TryParseDuration(expression.Trim(), out _)) + Paint(line, exprStart, text.Length, Error); + else PaintContent(line, text, exprStart); + break; + + default: + if (text.Length > 1 && text[0] == ':' && char.IsLetter(text[1])) + { + var kw = text.IndexOf(' '); + if (kw < 0) kw = text.Length; + Paint(line, 0, kw, Error); + PaintContent(line, text, kw); + } + else + { + if (text.StartsWith('/')) + { + var end = text.IndexOf(' '); + Paint(line, 0, end < 0 ? text.Length : end, PaletteIndex.KnownIdentifier); + } + PaintContent(line, text, 0); + } + break; + } + + return Empty; + } + + private static bool TryParseCondition(string expression) + { + try { new Parser(Tokenizer.Tokenize(expression)).Parse(); return true; } + catch (ConditionException) { return false; } + } + + private static void PaintContent(Span line, string text, int from) + { + if (from >= text.Length) return; + foreach (Match m in StringRegex.Matches(text, from)) + Paint(line, m.Index, m.Index + m.Length, PaletteIndex.String); + PaintTokens(line, text, from); + PaintMalformedBraces(line, from); + } + + private static void PaintMalformedBraces(Span line, int from) + { + for (var i = from; i < line.Length; i++) + { + if (line[i].Char != '{' || line[i].ColorIndex != PaletteIndex.Default) continue; + var end = i + 1; + while (end < line.Length && line[end].Char != '}') end++; + if (end < line.Length) end++; + Paint(line, i, end, Error); + i = end - 1; + } + } + + private static void PaintTokens(Span line, string text, int from) + { + if (from >= text.Length) return; + foreach (Match m in TokenRegex.Matches(text, from)) + { + var color = IsParameter(m.Groups[1].Value) ? PaletteIndex.Number : PaletteIndex.Identifier; + Paint(line, m.Index, m.Index + m.Length, color); + } + } + + private static void Paint(Span line, int start, int end, PaletteIndex color) + { + for (var i = start; i < end && i < line.Length; i++) + line[i] = new Glyph(line[i].Char, color); + } + + private static bool IsParameter(string token) => token == "*" || token.Contains("..") || token.All(char.IsDigit); + + public static void ApplyPalette(TextEditor editor) + { + var r = editor.Renderer; + r.SetColor(PaletteIndex.Default, U32(Palette.Text)); + r.SetColor(PaletteIndex.Keyword, U32(Palette.Keyword)); + r.SetColor(PaletteIndex.KnownIdentifier, U32(Palette.Command)); + r.SetColor(PaletteIndex.Identifier, U32(Palette.Variable)); + r.SetColor(PaletteIndex.Number, U32(Palette.Parameter)); + r.SetColor(PaletteIndex.String, U32(Palette.String)); + r.SetColor(PaletteIndex.CharLiteral, U32(Palette.Error)); + } + + private static uint U32(Vector4 c) => ImGui.ColorConvertFloat4ToU32(c); +} diff --git a/Silkstring/Windows/ConfigWindow.cs b/Silkstring/Windows/ConfigWindow.cs index c9ba4f7..8eb9578 100644 --- a/Silkstring/Windows/ConfigWindow.cs +++ b/Silkstring/Windows/ConfigWindow.cs @@ -60,6 +60,13 @@ public override void Draw() configuration.Save(); } + var showLineNumbers = configuration.ShowLineNumbers; + if (ImGui.Checkbox("Line numbers in the editor", ref showLineNumbers)) + { + configuration.ShowLineNumbers = showLineNumbers; + configuration.Save(); + } + if (ImGui.CollapsingHeader("Colors")) { void Sync() { Palette.Apply(configuration.Theme); configuration.MarkDirty(); } diff --git a/Silkstring/Windows/HelpWindow.cs b/Silkstring/Windows/HelpWindow.cs index e35199e..d4f2085 100644 --- a/Silkstring/Windows/HelpWindow.cs +++ b/Silkstring/Windows/HelpWindow.cs @@ -266,7 +266,7 @@ private void DrawVariableRow(string variable, string description, string current { ImGui.TableNextRow(); ImGui.TableNextColumn(); - ImGui.TextColored(Palette.VariableToken, variable); + ImGui.TextColored(Palette.Variable, variable); ImGui.TableNextColumn(); ImGui.TextWrapped(description); diff --git a/extern/DalamudTextEdit b/extern/DalamudTextEdit index b41c8b3..f341119 160000 --- a/extern/DalamudTextEdit +++ b/extern/DalamudTextEdit @@ -1 +1 @@ -Subproject commit b41c8b3692e809be5a6fb1a20415493db905e14e +Subproject commit f341119fc9c0c4fe2e42e34b96424c236559da02 From cd2748f2e70281296f73829562569d5694395e25 Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Wed, 1 Jul 2026 20:25:40 -0300 Subject: [PATCH 5/6] Customize line numbers --- Silkstring/Models/ThemeColors.cs | 1 + Silkstring/UI/Palette.cs | 2 ++ Silkstring/UI/SilkstringHighlighter.cs | 1 + 3 files changed, 4 insertions(+) diff --git a/Silkstring/Models/ThemeColors.cs b/Silkstring/Models/ThemeColors.cs index 162e2c2..82ec42d 100644 --- a/Silkstring/Models/ThemeColors.cs +++ b/Silkstring/Models/ThemeColors.cs @@ -6,6 +6,7 @@ public class ThemeColors { public Vector4 Heading = new(0.7f, 0.5f, 1.0f, 1.0f); public Vector4 Folder = new(0.7f, 0.5f, 1.0f, 1.0f); + public Vector4 LineNumber = new(0.5f, 0.5f, 0.5f, 1.0f); public Vector4 Error = new(1.0f, 0.4f, 0.4f, 1.0f); public Vector4 Success = new(0.4f, 1.0f, 0.4f, 1.0f); public Vector4 Variable = new(0.9f, 0.8f, 0.4f, 1.0f); diff --git a/Silkstring/UI/Palette.cs b/Silkstring/UI/Palette.cs index 9dee9f2..a1e90de 100644 --- a/Silkstring/UI/Palette.cs +++ b/Silkstring/UI/Palette.cs @@ -15,6 +15,7 @@ public static class Palette public static Vector4 Heading; public static Vector4 Folder; public static Vector4 Success; + public static Vector4 LineNumber; public static void Apply(ThemeColors t) { @@ -28,5 +29,6 @@ public static void Apply(ThemeColors t) Heading = t.Heading; Folder = t.Folder; Success = t.Success; + LineNumber = t.LineNumber; } } diff --git a/Silkstring/UI/SilkstringHighlighter.cs b/Silkstring/UI/SilkstringHighlighter.cs index 5972388..f4bdde4 100644 --- a/Silkstring/UI/SilkstringHighlighter.cs +++ b/Silkstring/UI/SilkstringHighlighter.cs @@ -146,6 +146,7 @@ public static void ApplyPalette(TextEditor editor) r.SetColor(PaletteIndex.Number, U32(Palette.Parameter)); r.SetColor(PaletteIndex.String, U32(Palette.String)); r.SetColor(PaletteIndex.CharLiteral, U32(Palette.Error)); + r.SetColor(PaletteIndex.LineNumber, U32(Palette.LineNumber)); } private static uint U32(Vector4 c) => ImGui.ColorConvertFloat4ToU32(c); From 96e93cfa5d376aeaef3541032d607b517bfe58fa Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Thu, 2 Jul 2026 03:13:25 -0300 Subject: [PATCH 6/6] Documentation update for syntax --- .github/workflows/release.yml | 3 +++ CHANGELOG.md | 6 ++++++ README.md | 5 +++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 154176b..cf10c47 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,6 +16,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Extract version from tag id: version shell: bash @@ -58,6 +60,7 @@ jobs: "$output/Silkstring.dll", "$output/Silkstring.json", "$output/ECommons.dll", + "$output/DalamudTextEdit.dll", "$output/Silkstring.deps.json", "$output/images", "$output/Silkstring" diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b3f94..08e62e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.5.0.0 - 2026-07-02 +### Added +- Syntax highlighting in the multiline editor: commands, keywords (`:if`, `:set`, `:wait`), variables, parameters, and quoted text are each given their own color as you type, and anything malformed is shown in red (a bad `:wait` time, an unfinished `:if`, a `:set` for a variable you have not created, a mistyped keyword, or an unclosed `{`) +- Line numbers in the multiline editor, with a setting to turn them off +- A Colors section in the settings to recolor the editor and interface, updating live as you change them + ## v1.4.1.0 - 2026-07-01 ### Fixed - Removed TBD and dated changelog (oops) diff --git a/README.md b/README.md index 412281f..1beabd9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ A Dalamud plugin for FFXIV that lets you define custom command aliases. Each ali - Filter aliases by name, and import, export, or clone them - Enable or disable an alias without deleting it - Built-in help window with a live command tester +- Syntax highlighting in the multiline editor, with customizable colors - Cycle detection warns you if aliases would trigger each other in a loop ## Installation @@ -174,11 +175,11 @@ Create a folder with the **New Folder** button, then drag aliases into or out of ### Multiline entry -By default each line of an alias is its own row. You can switch to a single multiline text box in the settings, with one line per row, which is handy for pasting or editing longer aliases. +By default each line of an alias is its own row. You can switch to a single multiline editor in the settings, which is handy for pasting or editing longer aliases. The editor highlights your syntax as you type: commands, keywords, variables, parameters, and quoted text each get their own color, and anything malformed (a bad `:wait`, an unfinished `:if`, an unknown `:set` name, a mistyped keyword, or an unclosed `{`) is shown in red. It also shows line numbers, which you can turn off in the settings. ### Settings -Open settings with the cog icon in the Silkstring title bar, or the cog next to Silkstring in `/xlplugins`. You can set the delay between lines in milliseconds (0 to 1000, default 100), and toggle multiline command entry. +Open settings with the cog icon in the Silkstring title bar, or the cog next to Silkstring in `/xlplugins`. You can set the delay between lines in milliseconds (0 to 1000, default 100), toggle multiline command entry, toggle line numbers in the editor, and open the Colors section to recolor the editor and interface to your taste. ## Notes