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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## v1.6.2.0 - 2026-07-11
### Added
- Blank lines and indentation in the multiline editor are now kept when you save, so you can space out and indent longer aliases to make them easier to read
- Indented lines are now colored correctly in the editor

### Changed
- The alias editor now lists every problem with an alias at once, each with its line number, instead of stopping at the first one it finds
- Problems are now colored by how serious they are, so warnings stand out from errors
- A cycle warning (an alias that would trigger itself) now shows alongside the other problems, instead of only appearing when you hovered over the trigger box

## v1.6.1.0 - 2026-07-09
### Added
- Time variables: your aliases can now react to the clock. `{time}` shows your local time (like 3:45 PM), `{time24}` shows it in 24-hour form (15:45), and `{date}`, `{day}`, `{hour}`, and `{minute}` fill in the rest. `{daypart}` gives morning, afternoon, evening, or night, so a venue greeter can open with something like `Good {daypart}, welcome in!`
Expand Down
6 changes: 3 additions & 3 deletions Silkstring/Services/AliasValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static IEnumerable<Diagnostic> ValidateSets(AliasEntry alias, ISet<string
{
for (var i = 0; i < alias.Output.Count; i++)
{
var (kind, expression) = BlockInterpreter.Classify(alias.Output[i].Command);
var (kind, expression) = BlockInterpreter.Classify(alias.Output[i].Command.Trim());
if (kind != BlockKind.Set) continue;
var (name, _) = BlockInterpreter.ParseSet(expression);
if (string.IsNullOrEmpty(name)) { yield return new(":set needs a variable name", i); continue; }
Expand All @@ -70,7 +70,7 @@ public static IEnumerable<Diagnostic> ValidateWaits(AliasEntry alias)
{
for (var i = 0; i < alias.Output.Count; i++)
{
var (kind, expression) = BlockInterpreter.Classify(alias.Output[i].Command);
var (kind, expression) = BlockInterpreter.Classify(alias.Output[i].Command.Trim());
if (kind != BlockKind.Wait) continue;
var (value, _) = BlockInterpreter.ParseSet(expression);
if (string.IsNullOrEmpty(value)) { yield return new(":wait needs a duration", i); continue; }
Expand All @@ -83,7 +83,7 @@ public static IEnumerable<Diagnostic> ValidateUntils(AliasEntry alias, bool allo
{
for (var i = 0; i < alias.Output.Count; i++)
{
var (kind, expression) = BlockInterpreter.Classify(alias.Output[i].Command);
var (kind, expression) = BlockInterpreter.Classify(alias.Output[i].Command.Trim());
if (kind != BlockKind.Until) continue;
var (isUnsafe, condition) = BlockInterpreter.ParseUntil(expression);
if (string.IsNullOrWhiteSpace(condition)) { yield return new(":until needs a condition", i); continue; }
Expand Down
2 changes: 1 addition & 1 deletion Silkstring/UI/Panels/AliasEditPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private void RefreshDiagnostics()

private static void ApplyMultiline(AliasEntry alias, string text)
{
var lines = text.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var lines = text.Split('\n');

for (var i = 0; i < lines.Length; i++)
{
Expand Down
35 changes: 18 additions & 17 deletions Silkstring/UI/SilkstringHighlighter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,61 +37,62 @@ public object Colorize(Span<Glyph> line, object? state)
line[i] = new Glyph(line[i].Char, PaletteIndex.Default);
}
var text = new string(chars);
var indent = text.Length - text.TrimStart().Length;
var body = text.TrimStart();

var (kind, expression) = BlockInterpreter.Classify(text);
var exprStart = text.Length - expression.Length;

var (kind, expression) = BlockInterpreter.Classify(body);
var exprStart = indent + body.Length - expression.Length;
switch (kind)
{
case BlockKind.If:
Paint(line, 0, exprStart, PaletteIndex.Keyword);
Paint(line, indent, 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);
Paint(line, indent, exprStart, PaletteIndex.Keyword);
break;

case BlockKind.Set:
Paint(line, 0, exprStart, PaletteIndex.Keyword);
Paint(line, indent, 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);
Paint(line, indent, exprStart, PaletteIndex.Keyword);
if (!expression.Contains('{') && !BlockInterpreter.TryParseDuration(expression.Trim(), out _))
Paint(line, exprStart, text.Length, Error);
else PaintContent(line, text, exprStart);
break;

case BlockKind.Until:
Paint(line, 0, exprStart, PaletteIndex.Keyword);
Paint(line, indent, exprStart, PaletteIndex.Keyword);
var (_, untilCond) = BlockInterpreter.ParseUntil(expression);
if (TryParseCondition(untilCond)) PaintContent(line, text, exprStart);
else Paint(line, exprStart, text.Length, Error);
break;

default:
if (text.Length > 1 && text[0] == ':' && char.IsLetter(text[1]))
if (body.Length > 1 && body[0] == ':' && char.IsLetter(body[1]))
{
var kw = text.IndexOf(' ');
if (kw < 0) kw = text.Length;
Paint(line, 0, kw, Error);
PaintContent(line, text, kw);
var kw = body.IndexOf(' ');
if (kw < 0) kw = body.Length;
Paint(line, indent, indent + kw, Error);
PaintContent(line, text, indent + kw);
}
else
{
if (text.StartsWith('/'))
if (body.StartsWith('/'))
{
var end = text.IndexOf(' ');
Paint(line, 0, end < 0 ? text.Length : end, PaletteIndex.KnownIdentifier);
var end = body.IndexOf(' ');
Paint(line, indent, indent + (end < 0 ? body.Length : end), PaletteIndex.KnownIdentifier);
}
PaintContent(line, text, 0);
PaintContent(line, text, indent);
}
break;
}
Expand Down
Loading