Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Extract version from tag
id: version
shell: bash
Expand Down Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "extern/DalamudTextEdit"]
path = extern/DalamudTextEdit
url = https://github.com/devoreofox/DalamudTextEdit.git
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
43 changes: 39 additions & 4 deletions Silkstring.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Silkstring/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ public int CommandDelay
public const int CurrentVersion = 2;
public string? LastSeenVersion { get; set; }
public int Version { get; set; } = CurrentVersion;

public List<AliasFolder> Folders = new();
public List<AliasEntry> Aliases = new();
public List<UserVariable> UserVariables = new();

public ThemeColors Theme = new();
public bool ShowLineNumbers = true;
public bool MultilineCommands { get; set; }

public void Save()
Expand Down
18 changes: 18 additions & 0 deletions Silkstring/Models/ThemeColors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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 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);
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);
}
3 changes: 3 additions & 0 deletions Silkstring/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using ECommons;
using Silkstring.Services;
using Silkstring.Services.Variables;
using Silkstring.UI;
using Silkstring.Windows;

namespace Silkstring;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
}
Expand Down
4 changes: 4 additions & 0 deletions Silkstring/Silkstring.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<PackageReference Include="ECommons" Version="3.2.0.18" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\extern\DalamudTextEdit\DalamudTextEdit.csproj" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Tests" />
</ItemGroup>
Expand Down
28 changes: 27 additions & 1 deletion Silkstring/UI/Palette.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
using System.Numerics;
using Silkstring.Models;

namespace Silkstring.UI;

public static class Palette
{
public static readonly Vector4 VariableToken = new(0.4f, 0.8f, 1.0f, 1.0f);
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 Success;
public static Vector4 LineNumber;

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;
Success = t.Success;
LineNumber = t.LineNumber;
}
}
46 changes: 22 additions & 24 deletions Silkstring/UI/Panels/AliasEditPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -19,18 +20,23 @@ public class AliasEditPanel
private List<string>? _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<string>(_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()
Expand All @@ -47,7 +53,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);
Expand Down Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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);
Expand Down
4 changes: 1 addition & 3 deletions Silkstring/UI/Panels/AliasSelectPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
Loading
Loading