chore: housekeeping — linter & formatter setup

Add .prettierrc.json, .markdownlint.json, .yamllint.yaml, .gitattributes
Run CSharpier, Prettier and markdownlint across the entire codebase.
No logic changes — formatting, using order and line endings only.
This commit is contained in:
2026-05-10 13:01:00 +02:00
parent cd01fa63a1
commit 699d4ede1d
141 changed files with 8833 additions and 5733 deletions
+70 -28
View File
@@ -7,7 +7,6 @@ using Lumina.Excel;
using Lumina.Text.Payloads;
using Lumina.Text.ReadOnly;
using Pidgin;
using static Pidgin.Parser;
using static Pidgin.Parser<char>;
@@ -26,14 +25,18 @@ internal static class AutoTranslate
private static Parser<char, (string name, Maybe<IEnumerable<ISelectorPart>> selector)> Parser()
{
var sheetName = Any
.AtLeastOnceUntil(Lookahead(Char('[').IgnoreResult().Or(End)))
var sheetName = Any.AtLeastOnceUntil(Lookahead(Char('[').IgnoreResult().Or(End)))
.Select(string.Concat)
.Labelled("sheetName");
var numPair = Map(ISelectorPart (first, second) =>
new IndexRange(uint.Parse(string.Concat(first)), uint.Parse(string.Concat(second))),
var numPair = Map(
ISelectorPart (first, second) =>
new IndexRange(
uint.Parse(string.Concat(first)),
uint.Parse(string.Concat(second))
),
Digit.AtLeastOnce().Before(Char('-')),
Digit.AtLeastOnce())
Digit.AtLeastOnce()
)
.Labelled("numPair");
var singleRow = Digit
.AtLeastOnce()
@@ -43,14 +46,11 @@ internal static class AutoTranslate
.Then(Digit.AtLeastOnce())
.Select(string.Concat)
.Select(ISelectorPart (num) => new ColumnSpecifier(uint.Parse(num)));
var noun = String("noun")
.Select(ISelectorPart (_) => new NounMarker());
var noun = String("noun").Select(ISelectorPart (_) => new NounMarker());
var selectorItems = OneOf(Try(numPair), singleRow, column, noun)
.Separated(Char(','))
.Labelled("selectorItems");
var selector = selectorItems
.Between(Char('['), Char(']'))
.Labelled("selector");
var selector = selectorItems.Between(Char('['), Char(']')).Labelled("selector");
return Map((name, sel) => (name, sel), sheetName, selector.Optional());
}
@@ -90,7 +90,16 @@ internal static class AutoTranslate
var list = new List<AutoTranslateEntry>();
foreach (var row in Sheets.CompletionSheet)
{
var lookup = string.Concat(row.LookupTable.Select(p => p.Type == ReadOnlySePayloadType.Text ? Encoding.UTF8.GetString(p.Body.Span) : p.MacroCode == MacroCode.Num && p.TryGetExpression(out var num) && num.TryGetInt(out var val) ? val.ToString(CultureInfo.InvariantCulture) : ",,,unexpected macro code,,,"));
var lookup = string.Concat(
row.LookupTable.Select(p =>
p.Type == ReadOnlySePayloadType.Text ? Encoding.UTF8.GetString(p.Body.Span)
: p.MacroCode == MacroCode.Num
&& p.TryGetExpression(out var num)
&& num.TryGetInt(out var val)
? val.ToString(CultureInfo.InvariantCulture)
: ",,,unexpected macro code,,,"
)
);
try
{
if (lookup is not ("" or "@"))
@@ -114,7 +123,7 @@ internal static class AutoTranslate
case IndexRange range:
{
var start = (int)range.Start;
var end = (int)(range.End + 1);
var end = (int)(range.End + 1);
rows.Add(start..end);
break;
}
@@ -158,7 +167,14 @@ internal static class AutoTranslate
var rawName = rowParser.ReadStringColumn(col);
if (!rawName.IsEmpty)
{
list.Add(new AutoTranslateEntry(row.Group, (uint)i, rawName.ToString(), string.Empty));
list.Add(
new AutoTranslateEntry(
row.Group,
(uint)i,
rawName.ToString(),
string.Empty
)
);
if (shouldAdd)
ValidEntries.Add((row.Group, (uint)i));
@@ -172,7 +188,14 @@ internal static class AutoTranslate
if (row.Text.IsEmpty)
continue;
list.Add(new AutoTranslateEntry(row.Group, row.RowId, row.Text.ToString(), row.GroupTitle.ToString()));
list.Add(
new AutoTranslateEntry(
row.Group,
row.RowId,
row.Text.ToString(),
row.GroupTitle.ToString()
)
);
if (shouldAdd)
ValidEntries.Add((row.Group, row.RowId));
@@ -220,16 +243,16 @@ internal static class AutoTranslate
if (sort)
{
return wholeMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase)
.Concat(prefixMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase))
return wholeMatches
.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase)
.Concat(
prefixMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase)
)
.Concat(otherMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase))
.ToList();
}
return wholeMatches
.Concat(prefixMatches)
.Concat(otherMatches)
.ToList();
return wholeMatches.Concat(prefixMatches).Concat(otherMatches).ToList();
}
internal static void ReplaceWithPayload(ref byte[] bytes)
@@ -255,7 +278,11 @@ internal static class AutoTranslate
var tag = Encoding.UTF8.GetString(bytes[start..(i + 1)]);
var parts = tag[4..^1].Split(',', 2);
if (parts.Length == 2 && uint.TryParse(parts[0], out var group) && uint.TryParse(parts[1], out var key))
if (
parts.Length == 2
&& uint.TryParse(parts[0], out var group)
&& uint.TryParse(parts[1], out var key)
)
{
bool isValid;
lock (EntriesLock)
@@ -267,7 +294,13 @@ internal static class AutoTranslate
bytes = new byte[oldBytes.Length + lengthDiff];
Array.Copy(oldBytes, bytes, start);
Array.Copy(payload, 0, bytes, start, payload.Length);
Array.Copy(oldBytes, i + 1, bytes, start + payload.Length, oldBytes.Length - (i + 1));
Array.Copy(
oldBytes,
i + 1,
bytes,
start + payload.Length,
oldBytes.Length - (i + 1)
);
i += lengthDiff;
}
@@ -278,7 +311,10 @@ internal static class AutoTranslate
// Pure managed comparison via Span avoids the msvcrt.dll P/Invoke,
// which is fragile under Wine and triggered an extra managed-to-
// unmanaged copy per check.
if (i + search.Length < bytes.Length && bytes.AsSpan(i, search.Length).SequenceEqual(search))
if (
i + search.Length < bytes.Length
&& bytes.AsSpan(i, search.Length).SequenceEqual(search)
)
start = i;
}
}
@@ -309,7 +345,11 @@ internal static class AutoTranslate
var tag = Encoding.UTF8.GetString(bytes[..(i + 1)]);
var parts = tag[4..^1].Split(',', 2);
if (parts.Length == 2 && uint.TryParse(parts[0], out var group) && uint.TryParse(parts[1], out var key))
if (
parts.Length == 2
&& uint.TryParse(parts[0], out var group)
&& uint.TryParse(parts[1], out var key)
)
{
bool isValid;
lock (EntriesLock)
@@ -317,7 +357,9 @@ internal static class AutoTranslate
if (!isValid)
return false;
var evaluated = Plugin.Evaluator.Evaluate(new ReadOnlySeString(CreateFixedTranslation(group, key))).ToString();
var evaluated = Plugin
.Evaluator.Evaluate(new ReadOnlySeString(CreateFixedTranslation(group, key)))
.ToString();
if (!evaluated.StartsWith('/'))
return false;
@@ -332,8 +374,8 @@ internal static class AutoTranslate
private static byte[] CreateFixedTranslation(uint group, uint key)
{
using var rssb = new RentedSeStringBuilder();
return rssb.Builder
.BeginMacro(MacroCode.Fixed)
return rssb
.Builder.BeginMacro(MacroCode.Fixed)
.AppendUIntExpression(group - 1)
.AppendUIntExpression(key)
.EndMacro()
+57 -25
View File
@@ -1,9 +1,8 @@
using HellionChat.Code;
using System.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using System.Text;
using HellionChat.Code;
using Lumina.Text.Payloads;
using PayloadType = Dalamud.Game.Text.SeStringHandling.PayloadType;
namespace HellionChat.Util;
@@ -248,7 +247,11 @@ internal static class ChunkUtil
// return chunks;
// }
internal static IEnumerable<Chunk> ToChunks(SeString msg, ChunkSource source, ChatType? defaultColour)
internal static IEnumerable<Chunk> ToChunks(
SeString msg,
ChunkSource source,
ChatType? defaultColour
)
{
var chunks = new List<Chunk>();
@@ -259,13 +262,15 @@ internal static class ChunkUtil
void Append(string text)
{
chunks.Add(new TextChunk(source, link, text)
{
FallbackColour = defaultColour,
Foreground = foreground.Count > 0 ? foreground.Peek() : null,
Glow = glow.Count > 0 ? glow.Peek() : null,
Italic = italic,
});
chunks.Add(
new TextChunk(source, link, text)
{
FallbackColour = defaultColour,
Foreground = foreground.Count > 0 ? foreground.Peek() : null,
Glow = glow.Count > 0 ? glow.Peek() : null,
Italic = italic,
}
);
}
foreach (var payload in msg.Payloads)
@@ -273,18 +278,18 @@ internal static class ChunkUtil
switch (payload.Type)
{
case PayloadType.EmphasisItalic:
var newStatus = ((EmphasisItalicPayload) payload).IsEnabled;
var newStatus = ((EmphasisItalicPayload)payload).IsEnabled;
italic = newStatus;
break;
case PayloadType.UIForeground:
var foregroundPayload = (UIForegroundPayload) payload;
var foregroundPayload = (UIForegroundPayload)payload;
if (foregroundPayload.IsEnabled)
foreground.Push(foregroundPayload.UIColor.Value.Dark);
else if (foreground.Count > 0)
foreground.Pop();
break;
case PayloadType.UIGlow:
var glowPayload = (UIGlowPayload) payload;
var glowPayload = (UIGlowPayload)payload;
if (glowPayload.IsEnabled)
glow.Push(glowPayload.UIColor.Value.Light);
else if (glow.Count > 0)
@@ -292,12 +297,12 @@ internal static class ChunkUtil
break;
case PayloadType.AutoTranslateText:
chunks.Add(new IconChunk(source, payload, BitmapFontIcon.AutoTranslateBegin));
var autoText = ((AutoTranslatePayload) payload).Text;
var autoText = ((AutoTranslatePayload)payload).Text;
Append(autoText.Substring(2, autoText.Length - 4));
chunks.Add(new IconChunk(source, link, BitmapFontIcon.AutoTranslateEnd));
break;
case PayloadType.Icon:
chunks.Add(new IconChunk(source, link, ((IconPayload) payload).Icon));
chunks.Add(new IconChunk(source, link, ((IconPayload)payload).Icon));
break;
case PayloadType.MapLink:
case PayloadType.Quest:
@@ -311,7 +316,7 @@ internal static class ChunkUtil
link = payload;
break;
case PayloadType.Unknown:
var rawPayload = (RawPayload) payload;
var rawPayload = (RawPayload)payload;
var colorPayload = ColorPayload.From(rawPayload.Data);
if (colorPayload != null)
{
@@ -333,20 +338,36 @@ internal static class ChunkUtil
{
glow.Pop();
}
else if (rawPayload.Data.Length > 6 && rawPayload.Data[2] == 0x05 && rawPayload.Data[3] == 0xF6)
else if (
rawPayload.Data.Length > 6
&& rawPayload.Data[2] == 0x05
&& rawPayload.Data[3] == 0xF6
)
{
var (r, g, b) = (rawPayload.Data[4], rawPayload.Data[5], rawPayload.Data[6]);
var (r, g, b) = (
rawPayload.Data[4],
rawPayload.Data[5],
rawPayload.Data[6]
);
glow.Push(ColourUtil.ComponentsToRgba(r, g, b));
}
}
else if (rawPayload.Data.Length > 7 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x0A)
else if (
rawPayload.Data.Length > 7
&& rawPayload.Data[1] == 0x27
&& rawPayload.Data[3] == 0x0A
)
{
// pf payload
var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..]));
var id = GetInteger(reader);
link = new PartyFinderPayload(id);
}
else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x06)
else if (
rawPayload.Data.Length > 5
&& rawPayload.Data[1] == 0x27
&& rawPayload.Data[3] == 0x06
)
{
// achievement payload
var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..]));
@@ -452,18 +473,29 @@ internal static class ChunkUtil
return payload.World.RowId == senderWorld;
}
internal static readonly RawPayload PeriodicRecruitmentLink = new([0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]);
internal static readonly RawPayload PeriodicRecruitmentLink = new([
0x02,
0x27,
0x07,
0x08,
0x01,
0x01,
0x01,
0xFF,
0x01,
0x03,
]);
private static uint GetInteger(BinaryReader input)
{
var num1 = (uint) input.ReadByte();
var num1 = (uint)input.ReadByte();
if (num1 < 208U)
return num1 - 1U;
var num2 = (uint) ((int) num1 + 1 & 15);
var num2 = (uint)((int)num1 + 1 & 15);
var numArray = new byte[4];
for (var index = 3; index >= 0; --index)
numArray[index] = (num2 & 1 << index) == 0L ? (byte) 0 : input.ReadByte();
numArray[index] = (num2 & 1 << index) == 0L ? (byte)0 : input.ReadByte();
return BitConverter.ToUInt32(numArray, 0);
}
+39 -27
View File
@@ -3,12 +3,13 @@ using System.Numerics;
namespace HellionChat.Util;
internal static class ColourUtil {
internal static class ColourUtil
{
private static (byte r, byte g, byte b) RgbaToRgbComponents(uint rgba)
{
var r = (byte) ((rgba & 0xFF000000) >> 24);
var g = (byte) ((rgba & 0xFF0000) >> 16);
var b = (byte) ((rgba & 0xFF00) >> 8);
var r = (byte)((rgba & 0xFF000000) >> 24);
var g = (byte)((rgba & 0xFF0000) >> 16);
var b = (byte)((rgba & 0xFF00) >> 8);
return (r, g, b);
}
@@ -17,26 +18,28 @@ internal static class ColourUtil {
internal static Vector3 RgbaToVector3(uint rgba)
{
var (r, g, b) = RgbaToRgbComponents(rgba);
return new Vector3((float) r / 255, (float) g / 255, (float) b / 255);
return new Vector3((float)r / 255, (float)g / 255, (float)b / 255);
}
internal static uint Vector3ToRgba(Vector3 col)
{
return ComponentsToRgba(
(byte) Math.Round(col.X * 255),
(byte) Math.Round(col.Y * 255),
(byte) Math.Round(col.Z * 255)
(byte)Math.Round(col.X * 255),
(byte)Math.Round(col.Y * 255),
(byte)Math.Round(col.Z * 255)
);
}
internal static uint Vector4ToAbgr(Vector4 col)
{
return RgbaToAbgr(ComponentsToRgba(
(byte) Math.Round(col.X * 255),
(byte) Math.Round(col.Y * 255),
(byte) Math.Round(col.Z * 255),
(byte) Math.Round(col.W * 255)
));
return RgbaToAbgr(
ComponentsToRgba(
(byte)Math.Round(col.X * 255),
(byte)Math.Round(col.Y * 255),
(byte)Math.Round(col.Z * 255),
(byte)Math.Round(col.W * 255)
)
);
}
public static unsafe uint ArgbToRgba(uint x)
@@ -46,21 +49,21 @@ internal static class ColourUtil {
return x;
}
internal static uint ComponentsToRgba(byte red, byte green, byte blue, byte alpha = 0xFF)
=> alpha | (uint) (red << 24) | (uint) (green << 16) | (uint) (blue << 8);
internal static uint ComponentsToRgba(byte red, byte green, byte blue, byte alpha = 0xFF) =>
alpha | (uint)(red << 24) | (uint)(green << 16) | (uint)(blue << 8);
internal static uint AdjustBrightness(uint abgr, float factor)
{
var a = (byte) ((abgr & 0xFF000000) >> 24);
var b = (byte) ((abgr & 0x00FF0000) >> 16);
var g = (byte) ((abgr & 0x0000FF00) >> 8);
var r = (byte) (abgr & 0x000000FF);
var a = (byte)((abgr & 0xFF000000) >> 24);
var b = (byte)((abgr & 0x00FF0000) >> 16);
var g = (byte)((abgr & 0x0000FF00) >> 8);
var r = (byte)(abgr & 0x000000FF);
var nr = (byte) Math.Clamp(r * factor, 0f, 255f);
var ng = (byte) Math.Clamp(g * factor, 0f, 255f);
var nb = (byte) Math.Clamp(b * factor, 0f, 255f);
var nr = (byte)Math.Clamp(r * factor, 0f, 255f);
var ng = (byte)Math.Clamp(g * factor, 0f, 255f);
var nb = (byte)Math.Clamp(b * factor, 0f, 255f);
return ((uint) a << 24) | ((uint) nb << 16) | ((uint) ng << 8) | nr;
return ((uint)a << 24) | ((uint)nb << 16) | ((uint)ng << 8) | nr;
}
public static uint HexToRgba(string hex)
@@ -68,13 +71,22 @@ internal static class ColourUtil {
ArgumentNullException.ThrowIfNull(hex);
var s = hex.StartsWith('#') ? hex[1..] : hex;
if (s.Length != 6 && s.Length != 8)
throw new FormatException($"Hex colour must be 6 or 8 hex digits, got {s.Length}: '{hex}'");
throw new FormatException(
$"Hex colour must be 6 or 8 hex digits, got {s.Length}: '{hex}'"
);
if (!uint.TryParse(s, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out var value))
if (
!uint.TryParse(
s,
System.Globalization.NumberStyles.HexNumber,
System.Globalization.CultureInfo.InvariantCulture,
out var value
)
)
throw new FormatException($"Hex colour '{hex}' is not a valid hexadecimal value");
if (s.Length == 6)
value = (value << 8) | 0xFFu; // RRGGBB → RRGGBBFF
value = (value << 8) | 0xFFu; // RRGGBB → RRGGBBFF
return value;
}
+122 -24
View File
@@ -1,13 +1,13 @@
using System.Globalization;
using System.Numerics;
using HellionChat.Resources;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Utility;
using Dalamud.Bindings.ImGui;
using HellionChat.Resources;
namespace HellionChat.Util;
@@ -18,9 +18,46 @@ public static class DateWidget
private static readonly DateTime Sample = DateTime.UnixEpoch;
private static readonly Vector4 Transparent = new(1, 1, 1, 0);
private static readonly string[] DayNames = [Language.DateWidget_Day_Sun, Language.DateWidget_Day_Mon, Language.DateWidget_Day_Tue, Language.DateWidget_Day_Wed, Language.DateWidget_Day_Thu, Language.DateWidget_Day_Fri, Language.DateWidget_Day_Sat];
private static readonly string[] MonthNames = [Language.DateWidget_Month_January, Language.DateWidget_Month_February, Language.DateWidget_Month_March, Language.DateWidget_Month_April, Language.DateWidget_Month_May, Language.DateWidget_Month_June, Language.DateWidget_Month_July, Language.DateWidget_Month_August, Language.DateWidget_Month_September, Language.DateWidget_Month_October, Language.DateWidget_Month_November, Language.DateWidget_Month_December];
private static readonly int[] NumDaysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
private static readonly string[] DayNames =
[
Language.DateWidget_Day_Sun,
Language.DateWidget_Day_Mon,
Language.DateWidget_Day_Tue,
Language.DateWidget_Day_Wed,
Language.DateWidget_Day_Thu,
Language.DateWidget_Day_Fri,
Language.DateWidget_Day_Sat,
];
private static readonly string[] MonthNames =
[
Language.DateWidget_Month_January,
Language.DateWidget_Month_February,
Language.DateWidget_Month_March,
Language.DateWidget_Month_April,
Language.DateWidget_Month_May,
Language.DateWidget_Month_June,
Language.DateWidget_Month_July,
Language.DateWidget_Month_August,
Language.DateWidget_Month_September,
Language.DateWidget_Month_October,
Language.DateWidget_Month_November,
Language.DateWidget_Month_December,
];
private static readonly int[] NumDaysPerMonth =
[
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
];
private static float LongestMonthWidth;
private static readonly float[] MonthWidths = new float[12];
@@ -33,12 +70,14 @@ public static class DateWidget
if (minimal > currentMin)
{
currentMin = minimal;
Plugin.Notification.AddNotification(new Notification
{
Content = Language.DateWidget_InvalidDate.Format(minimal.ToShortDateString()),
Type = NotificationType.Warning,
Minimized = false,
});
Plugin.Notification.AddNotification(
new Notification
{
Content = Language.DateWidget_InvalidDate.Format(minimal.ToShortDateString()),
Type = NotificationType.Warning,
Minimized = false,
}
);
needsRefresh = true;
}
else if (currentMin > currentMax)
@@ -50,15 +89,41 @@ public static class DateWidget
return needsRefresh;
}
public static void DatePickerWithInput(string label, int id, ref string dateString, ref DateTime date, string format, bool sameLine = false, bool closeWhenMouseLeavesIt = true)
public static void DatePickerWithInput(
string label,
int id,
ref string dateString,
ref DateTime date,
string format,
bool sameLine = false,
bool closeWhenMouseLeavesIt = true
)
{
if (sameLine)
ImGui.SameLine();
ImGui.SetNextItemWidth(ImGui.CalcTextSize(Sample.ToString(format)).X + ImGui.GetStyle().ItemInnerSpacing.X * 2);
if (ImGui.InputTextWithHint($"##{label}Input", format.ToUpper(), ref dateString, 32, ImGuiInputTextFlags.CallbackCompletion))
ImGui.SetNextItemWidth(
ImGui.CalcTextSize(Sample.ToString(format)).X + ImGui.GetStyle().ItemInnerSpacing.X * 2
);
if (
ImGui.InputTextWithHint(
$"##{label}Input",
format.ToUpper(),
ref dateString,
32,
ImGuiInputTextFlags.CallbackCompletion
)
)
{
if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var tmp))
if (
DateTime.TryParseExact(
dateString,
format,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out var tmp
)
)
date = tmp;
}
@@ -72,7 +137,13 @@ public static class DateWidget
dateString = date.ToString(format);
}
private static bool DatePicker(string label, ref DateTime dateOut, bool closeWhenMouseLeavesIt, string leftArrow = "", string rightArrow = "")
private static bool DatePicker(
string label,
ref DateTime dateOut,
bool closeWhenMouseLeavesIt,
string leftArrow = "",
string rightArrow = ""
)
{
using var mono = ImRaii.PushFont(UiBuilder.MonoFont);
if (LongestMonthWidth == 0.0f)
@@ -96,12 +167,22 @@ public static class DateWidget
var labelSize = ImGui.CalcTextSize(label, true, 0);
var widthRequiredByCalendar = (2.0f * arrowLeftWidth) + (2.0f * arrowRightWidth) + LongestMonthWidth + ImGui.CalcTextSize("9999").X + (120.0f * ImGuiHelpers.GlobalScale);
var popupHeight = ((labelSize.Y + (2 * style.ItemSpacing.Y)) * HeightInItems) + (style.FramePadding.Y * 3);
var widthRequiredByCalendar =
(2.0f * arrowLeftWidth)
+ (2.0f * arrowRightWidth)
+ LongestMonthWidth
+ ImGui.CalcTextSize("9999").X
+ (120.0f * ImGuiHelpers.GlobalScale);
var popupHeight =
((labelSize.Y + (2 * style.ItemSpacing.Y)) * HeightInItems)
+ (style.FramePadding.Y * 3);
var valueChanged = false;
ImGui.SetNextWindowSize(new Vector2(widthRequiredByCalendar, widthRequiredByCalendar));
ImGui.SetNextWindowSizeConstraints(new Vector2(widthRequiredByCalendar, popupHeight + 40), new Vector2(widthRequiredByCalendar, popupHeight + 40));
ImGui.SetNextWindowSizeConstraints(
new Vector2(widthRequiredByCalendar, popupHeight + 40),
new Vector2(widthRequiredByCalendar, popupHeight + 40)
);
using var popupItem = ImRaii.ContextPopupItem(label, ImGuiPopupFlags.None);
if (!popupItem.Success)
@@ -156,7 +237,12 @@ public static class DateWidget
}
}
ImGui.SameLine(ImGui.GetWindowWidth() - yearPartWidth - style.WindowPadding.X - style.ItemSpacing.X * 4.0f);
ImGui.SameLine(
ImGui.GetWindowWidth()
- yearPartWidth
- style.WindowPadding.X
- style.ItemSpacing.X * 4.0f
);
using (ImRaii.PushId(1235))
{
@@ -189,7 +275,10 @@ public static class DateWidget
maxDayOfCurMonth = 29;
}
using var buttonHovered = ImRaii.PushColor(ImGuiCol.ButtonHovered, ImGuiColors.DalamudOrange);
using var buttonHovered = ImRaii.PushColor(
ImGuiCol.ButtonHovered,
ImGuiColors.DalamudOrange
);
using var buttonActive = ImRaii.PushColor(ImGuiCol.ButtonActive, ImGuiColors.DalamudYellow);
ImGui.Separator();
@@ -201,7 +290,11 @@ public static class DateWidget
{
using (ImRaii.Group())
{
using var textColor = ImRaii.PushColor(ImGuiCol.Text, CalculateTextColor(), dw == 0);
using var textColor = ImRaii.PushColor(
ImGuiCol.Text,
CalculateTextColor(),
dw == 0
);
ImGui.Text($"{(dw == 0 ? "" : " ")}{DayNames[dw]}");
if (dw == 0)
@@ -253,7 +346,12 @@ public static class DateWidget
size.X += 2.0f * distance;
size.Y += 2.0f * distance;
var mousePos = ImGui.GetIO().MousePos;
if (mousePos.X < pos.X || mousePos.Y < pos.Y || mousePos.X > pos.X + size.X || mousePos.Y > pos.Y + size.Y)
if (
mousePos.X < pos.X
|| mousePos.Y < pos.Y
|| mousePos.X > pos.X + size.X
|| mousePos.Y > pos.Y + size.Y
)
mustCloseCombo = true;
}
@@ -270,4 +368,4 @@ public static class DateWidget
var l = (textColor.X + textColor.Y + textColor.Z) * 0.33334f;
return new Vector4(l * 2.0f > 1 ? 1 : l * 2.0f, l * .5f, l * .5f, textColor.W);
}
}
}
+21 -9
View File
@@ -26,8 +26,11 @@ public class ColorPayload
case 0xE9:
var param = stream.ReadByte();
if (param == -1)
throw new ArgumentException("Encountered premature end of input (unexpected EOF).", nameof(stream));
var globalValue = (uint) GlobalParametersCache.GetValue(param - 2);
throw new ArgumentException(
"Encountered premature end of input (unexpected EOF).",
nameof(stream)
);
var globalValue = (uint)GlobalParametersCache.GetValue(param - 2);
payload.Enabled = true;
payload.UnshiftedColor = globalValue;
payload.Color = ColourUtil.ArgbToRgba(globalValue);
@@ -40,10 +43,16 @@ public class ColorPayload
return v switch
{
// ReSharper disable once LocalizableElement
-1 => throw new ArgumentException("Encountered premature end of input (unexpected EOF).", nameof(v)),
-1 => throw new ArgumentException(
"Encountered premature end of input (unexpected EOF).",
nameof(v)
),
// ReSharper disable once LocalizableElement
0 => throw new ArgumentException("Encountered premature end of input (unexpected null character).", nameof(v)),
_ => (uint)v << shift
0 => throw new ArgumentException(
"Encountered premature end of input (unexpected null character).",
nameof(v)
),
_ => (uint)v << shift,
};
}
@@ -54,9 +63,12 @@ public class ColorPayload
else
argbValue |= 0xff000000u;
if( (typeByte & 4) != 0 ) argbValue |= ShiftAndThrowIfZero( stream.ReadByte(), 16 );
if( (typeByte & 2) != 0 ) argbValue |= ShiftAndThrowIfZero( stream.ReadByte(), 8 );
if( (typeByte & 1) != 0 ) argbValue |= ShiftAndThrowIfZero( stream.ReadByte(), 0 );
if ((typeByte & 4) != 0)
argbValue |= ShiftAndThrowIfZero(stream.ReadByte(), 16);
if ((typeByte & 2) != 0)
argbValue |= ShiftAndThrowIfZero(stream.ReadByte(), 8);
if ((typeByte & 1) != 0)
argbValue |= ShiftAndThrowIfZero(stream.ReadByte(), 0);
payload.Enabled = true;
payload.Color = ColourUtil.ArgbToRgba(argbValue);
@@ -66,4 +78,4 @@ public class ColorPayload
return null;
}
}
}
}
+4 -2
View File
@@ -29,7 +29,9 @@ public static class GlobalParametersCache
public static unsafe void Refresh()
{
if (!ThreadSafety.IsMainThread)
throw new InvalidOperationException("GlobalParametersCache.Refresh must be called on the main thread.");
throw new InvalidOperationException(
"GlobalParametersCache.Refresh must be called on the main thread."
);
var rtm = RaptureTextModule.Instance();
if (rtm is null)
@@ -48,4 +50,4 @@ public static class GlobalParametersCache
Cache[(int)i] = 0;
}
}
}
}
+7 -5
View File
@@ -31,7 +31,8 @@ public readonly unsafe ref struct GfdFileView
private ref readonly GfdHeader Header => ref MemoryMarshal.AsRef<GfdHeader>(Span);
/// <summary>Gets the entries.</summary>
private ReadOnlySpan<GfdEntry> Entries => MemoryMarshal.Cast<byte, GfdEntry>(Span[sizeof(GfdHeader)..]);
private ReadOnlySpan<GfdEntry> Entries =>
MemoryMarshal.Cast<byte, GfdEntry>(Span[sizeof(GfdHeader)..]);
/// <summary>Attempts to get an entry.</summary>
/// <param name="iconId">The icon ID.</param>
@@ -153,8 +154,6 @@ public readonly unsafe ref struct GfdFileView
}
}
internal static class IconUtil
{
private static byte[]? GfdFile;
@@ -164,8 +163,11 @@ internal static class IconUtil
{
if (GfdFile is null)
{
var file = Plugin.DataManager.GetFile("common/font/gfdata.gfd")
?? throw new FileNotFoundException("Failed to load common/font/gfdata.gfd from the game data.");
var file =
Plugin.DataManager.GetFile("common/font/gfdata.gfd")
?? throw new FileNotFoundException(
"Failed to load common/font/gfdata.gfd from the game data."
);
GfdFile = file.Data;
}
return new GfdFileView(GfdFile);
+126 -28
View File
@@ -1,9 +1,7 @@
using System.Buffers;
using System.Numerics;
using System.Text;
using HellionChat.Code;
using HellionChat.GameFunctions.Types;
using HellionChat.Resources;
using Dalamud.Bindings.ImGui;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface;
@@ -13,7 +11,9 @@ using Dalamud.Interface.ImGuiFontChooserDialog;
using Dalamud.Interface.Style;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Bindings.ImGui;
using HellionChat.Code;
using HellionChat.GameFunctions.Types;
using HellionChat.Resources;
namespace HellionChat.Util;
@@ -30,7 +30,7 @@ internal static class ImGuiUtil
[
ImGuiMouseButton.Left,
ImGuiMouseButton.Middle,
ImGuiMouseButton.Right
ImGuiMouseButton.Right,
];
private static Payload? Hovered;
@@ -66,7 +66,13 @@ internal static class ImGuiUtil
// ever feeds in a degenerate input.
private const int MaxLineByteCount = 16 * 1024;
internal static void WrapText(string csText, Chunk chunk, PayloadHandler? handler, Vector4 defaultText, float lineWidth)
internal static void WrapText(
string csText,
Chunk chunk,
PayloadHandler? handler,
Vector4 defaultText,
float lineWidth
)
{
if (csText.Length == 0)
return;
@@ -111,7 +117,13 @@ internal static class ImGuiUtil
}
}
private static unsafe void WrapEncodedLine(ReadOnlySpan<byte> bytes, Chunk chunk, PayloadHandler? handler, Vector4 defaultText, float lineWidth)
private static unsafe void WrapEncodedLine(
ReadOnlySpan<byte> bytes,
Chunk chunk,
PayloadHandler? handler,
Vector4 defaultText,
float lineWidth
)
{
var byteCount = bytes.Length;
if (byteCount == 0)
@@ -187,13 +199,21 @@ internal static class ImGuiUtil
ImGuiHelpers.GlobalScale,
basePtr + start,
basePtr + end,
width);
width
);
if (result == null)
return -1;
return (int)(result - basePtr);
}
private static unsafe void DrawText(byte* basePtr, int start, int end, Chunk chunk, PayloadHandler? handler, Vector4 defaultText)
private static unsafe void DrawText(
byte* basePtr,
int start,
int end,
Chunk chunk,
PayloadHandler? handler,
Vector4 defaultText
)
{
var oldPos = ImGui.GetCursorScreenPos();
@@ -209,10 +229,14 @@ internal static class ImGuiUtil
{
defaultText.W = 0.25f;
var actualCol = ColourUtil.Vector4ToAbgr(defaultText);
ImGui.GetWindowDrawList().AddRectFilled(oldPos, oldPos + ImGui.GetItemRectSize(), actualCol);
ImGui
.GetWindowDrawList()
.AddRectFilled(oldPos, oldPos + ImGui.GetItemRectSize(), actualCol);
foreach (var (boundsStart, boundsSize) in PayloadBounds)
ImGui.GetWindowDrawList().AddRectFilled(boundsStart, boundsStart + boundsSize, actualCol);
ImGui
.GetWindowDrawList()
.AddRectFilled(boundsStart, boundsStart + boundsSize, actualCol);
PayloadBounds.Clear();
}
@@ -230,7 +254,12 @@ internal static class ImGuiUtil
return end;
}
internal static bool IconButton(FontAwesomeIcon icon, string? id = null, string? tooltip = null, int width = 0)
internal static bool IconButton(
FontAwesomeIcon icon,
string? id = null,
string? tooltip = null,
int width = 0
)
{
var label = icon.ToIconString();
if (id != null)
@@ -246,7 +275,10 @@ internal static class ImGuiUtil
ret = ImGui.Button(label, size);
}
if (!string.IsNullOrEmpty(tooltip) && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
if (
!string.IsNullOrEmpty(tooltip)
&& ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)
)
Tooltip(tooltip);
return ret;
@@ -264,7 +296,7 @@ internal static class ImGuiUtil
internal static void HelpText(string text)
{
using (ImRaii.TextWrapPos(0.0f))
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled]))
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int)ImGuiCol.TextDisabled]))
ImGui.TextUnformatted(text);
}
@@ -275,7 +307,7 @@ internal static class ImGuiUtil
internal static void HelpMarker(string description)
{
ImGui.SameLine();
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled]))
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int)ImGuiCol.TextDisabled]))
ImGui.TextUnformatted("(?)");
// AllowWhenDisabled — ohne das Flag liefert IsItemHovered bei
@@ -296,25 +328,48 @@ internal static class ImGuiUtil
var dalamudOrange = style.BuiltInColors?.DalamudOrange;
using (ImRaii.TextWrapPos(wrap ? 0.0f : ImGui.GetFontSize() * 35.0f))
using (ImRaii.PushColor(ImGuiCol.Text, dalamudOrange ?? Vector4.Zero, dalamudOrange != null))
using (
ImRaii.PushColor(ImGuiCol.Text, dalamudOrange ?? Vector4.Zero, dalamudOrange != null)
)
ImGui.TextUnformatted(text);
}
internal static ImRaii.ComboDisposable BeginComboVertical(string label, string previewValue, ImGuiComboFlags flags = ImGuiComboFlags.None)
internal static ImRaii.ComboDisposable BeginComboVertical(
string label,
string previewValue,
ImGuiComboFlags flags = ImGuiComboFlags.None
)
{
ImGui.TextUnformatted(label);
ImGui.SetNextItemWidth(-1);
return ImRaii.Combo($"##{label}", previewValue, flags);
}
internal static bool DragFloatVertical(string label, ref float value, float vSpeed = 1.0f, float vMin = float.MinValue, float vMax = float.MaxValue, string? format = null, ImGuiSliderFlags flags = ImGuiSliderFlags.None)
internal static bool DragFloatVertical(
string label,
ref float value,
float vSpeed = 1.0f,
float vMin = float.MinValue,
float vMax = float.MaxValue,
string? format = null,
ImGuiSliderFlags flags = ImGuiSliderFlags.None
)
{
ImGui.TextUnformatted(label);
ImGui.SetNextItemWidth(-1);
return ImGui.DragFloat($"##{label}", ref value, vSpeed, vMin, vMax, format, flags);
}
internal static bool DragFloatVertical(string label, string description, ref float value, float vSpeed = 1.0f, float vMin = float.MinValue, float vMax = float.MaxValue, string? format = null, ImGuiSliderFlags flags = ImGuiSliderFlags.None)
internal static bool DragFloatVertical(
string label,
string description,
ref float value,
float vSpeed = 1.0f,
float vMin = float.MinValue,
float vMax = float.MaxValue,
string? format = null,
ImGuiSliderFlags flags = ImGuiSliderFlags.None
)
{
ImGui.TextUnformatted(label);
ImGui.SetNextItemWidth(-1);
@@ -324,7 +379,14 @@ internal static class ImGuiUtil
return r;
}
internal static bool InputIntVertical(string label, string description, ref int value, int step = 1, int stepFast = 100, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None)
internal static bool InputIntVertical(
string label,
string description,
ref int value,
int step = 1,
int stepFast = 100,
ImGuiInputTextFlags flags = ImGuiInputTextFlags.None
)
{
ImGui.TextUnformatted(label);
ImGui.SetNextItemWidth(-1);
@@ -341,7 +403,14 @@ internal static class ImGuiUtil
ImGui.TextUnformatted(tooltip);
}
public static SingleFontChooserDialog? FontChooser(string label, SingleFontSpec font, bool checkbox, ref bool checkboxValue, Predicate<IFontFamilyId>? exclusion = null, string? preview = null)
public static SingleFontChooserDialog? FontChooser(
string label,
SingleFontSpec font,
bool checkbox,
ref bool checkboxValue,
Predicate<IFontFamilyId>? exclusion = null,
string? preview = null
)
{
using var id = ImRaii.PushId(label);
@@ -360,7 +429,7 @@ internal static class ImGuiUtil
if (!ImGui.Button($"{buttonText}##{label}"))
return null;
var chooser = SingleFontChooserDialog.CreateAuto((UiBuilder) Plugin.Interface.UiBuilder);
var chooser = SingleFontChooserDialog.CreateAuto((UiBuilder)Plugin.Interface.UiBuilder);
chooser.SelectedFont = font;
if (exclusion is not null)
chooser.FontFamilyExcludeFilter = exclusion;
@@ -445,7 +514,19 @@ internal static class ImGuiUtil
foreach (var vk in Enum.GetValues<VirtualKey>())
{
if (vk is VirtualKey.NO_KEY or VirtualKey.CONTROL or VirtualKey.LCONTROL or VirtualKey.RCONTROL or VirtualKey.SHIFT or VirtualKey.LSHIFT or VirtualKey.RSHIFT or VirtualKey.MENU or VirtualKey.LMENU or VirtualKey.RMENU)
if (
vk
is VirtualKey.NO_KEY
or VirtualKey.CONTROL
or VirtualKey.LCONTROL
or VirtualKey.RCONTROL
or VirtualKey.SHIFT
or VirtualKey.LSHIFT
or VirtualKey.RSHIFT
or VirtualKey.MENU
or VirtualKey.LMENU
or VirtualKey.RMENU
)
continue;
if (!vk.TryToImGui(out var imKey) || !ImGui.IsKeyPressed(imKey))
@@ -466,7 +547,15 @@ internal static class ImGuiUtil
}
}
public static void DrawArrows(ref int selected, int min, int max, float spacing, int id = 0, string? tooltipLeft = null, string? tooltipRight = null)
public static void DrawArrows(
ref int selected,
int min,
int max,
float spacing,
int id = 0,
string? tooltipLeft = null,
string? tooltipRight = null
)
{
// Prevents changing values from triggering EndDisable
var isMin = selected == min;
@@ -486,7 +575,7 @@ internal static class ImGuiUtil
using (ImRaii.Disabled(isMax))
{
if (IconButton(FontAwesomeIcon.ArrowRight, id+1.ToString()))
if (IconButton(FontAwesomeIcon.ArrowRight, id + 1.ToString()))
selected++;
}
@@ -503,7 +592,9 @@ internal static class ImGuiUtil
public static void CenterText(string text, float indent = 0.0f)
{
indent *= ImGuiHelpers.GlobalScale;
ImGui.SameLine(((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X) * 0.5f) + indent);
ImGui.SameLine(
((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X) * 0.5f) + indent
);
ImGui.TextUnformatted(text);
}
@@ -624,7 +715,10 @@ internal static class ImGuiUtil
return result != 0 || key == VirtualKey.NO_KEY;
}
public static void ChannelSelector(string headerText, Dictionary<ChatType, (ChatSource Source, ChatSource Target)> chatCodes)
public static void ChannelSelector(
string headerText,
Dictionary<ChatType, (ChatSource Source, ChatSource Target)> chatCodes
)
{
var spacing = 3.0f * ImGuiHelpers.GlobalScale;
@@ -710,7 +804,11 @@ internal static class ImGuiUtil
}
}
public static void ExtraChatSelector(string headerText, ref bool all, HashSet<Guid> extraChatChannels)
public static void ExtraChatSelector(
string headerText,
ref bool all,
HashSet<Guid> extraChatChannels
)
{
if (Plugin.ExtraChat.ChannelNames.Count <= 0)
return;
+8 -6
View File
@@ -25,10 +25,10 @@ public static class MathUtil
SizeY = Y + Height;
}
public Rectangle(Vector2 pos, Vector2 size) : this((int) pos.X, (int) pos.Y, (int) size.X, (int) size.Y) { }
public Rectangle(Vector2 pos, Vector2 size)
: this((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y) { }
public override string ToString()
=> $"X: {X} Y: {Y} Width: {Width} Height: {Height}";
public override string ToString() => $"X: {X} Y: {Y} Width: {Width} Height: {Height}";
}
/// <summary>
@@ -43,7 +43,9 @@ public static class MathUtil
// overlap on both axes. The previous nested ValueInRange approach
// used strict inequalities at both ends, which dropped identical
// rectangles and shared-edge cases as false negatives.
return a.X < b.X + b.Width && a.X + a.Width > b.X &&
a.Y < b.Y + b.Height && a.Y + a.Height > b.Y;
return a.X < b.X + b.Width
&& a.X + a.Width > b.X
&& a.Y < b.Y + b.Height
&& a.Y + a.Height > b.Y;
}
}
}
+14 -6
View File
@@ -15,25 +15,33 @@ public static class MemoryUtil
if (address == nint.Zero)
throw new ArgumentException("Memory address cannot be zero.", nameof(address));
if (length <= 0)
throw new ArgumentOutOfRangeException(nameof(length), length, "Length must be positive.");
throw new ArgumentOutOfRangeException(
nameof(length),
length,
"Length must be positive."
);
if (length > MaxDumpLength)
throw new ArgumentOutOfRangeException(nameof(length), length, $"Length exceeds the {MaxDumpLength}-byte safety cap.");
throw new ArgumentOutOfRangeException(
nameof(length),
length,
$"Length exceeds the {MaxDumpLength}-byte safety cap."
);
var ptr = (byte*)address;
var str = new StringBuilder("\n");
for(var i = 0; i < length; i++)
for (var i = 0; i < length; i++)
{
str.Append($"{ptr![i]:X02}");
if (i == 0)
continue;
if ((i+1) % 16 == 0)
if ((i + 1) % 16 == 0)
str.Append('\n');
else if ((i+1) % 4 == 0)
else if ((i + 1) % 4 == 0)
str.Append(' ');
}
Plugin.Log.Information(str.ToString());
}
}
}
+4 -5
View File
@@ -4,7 +4,7 @@ namespace HellionChat.Util;
internal class PartyFinderPayload : Payload
{
public override PayloadType Type => (PayloadType) 0x50;
public override PayloadType Type => (PayloadType)0x50;
internal uint Id { get; }
@@ -26,7 +26,7 @@ internal class PartyFinderPayload : Payload
internal class AchievementPayload : Payload
{
public override PayloadType Type => (PayloadType) 0x51;
public override PayloadType Type => (PayloadType)0x51;
internal uint Id { get; }
@@ -46,10 +46,9 @@ internal class AchievementPayload : Payload
}
}
internal class UriPayload(Uri uri) : Payload
{
public override PayloadType Type => (PayloadType) 0x52;
public override PayloadType Type => (PayloadType)0x52;
public Uri Uri { get; } = uri;
@@ -92,7 +91,7 @@ internal class UriPayload(Uri uri) : Payload
internal class EmotePayload : Payload
{
public override PayloadType Type => (PayloadType) 0x53;
public override PayloadType Type => (PayloadType)0x53;
public string Code = string.Empty;
+47 -13
View File
@@ -1,7 +1,7 @@
using System.Numerics;
using Dalamud.Interface.Utility;
using System.Collections;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using System.Collections;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
namespace HellionChat.Util;
@@ -15,7 +15,6 @@ public static class SearchSelector
private static string PrevSearchId = null!;
private static Type PrevSearchType = null!;
public record SelectorOptions
{
public Func<string, string> FormatRow { get; init; } = row => row.ToString();
@@ -25,14 +24,18 @@ public static class SearchSelector
public Vector2? Size { get; init; } = null;
}
public record SelectorPopupOptions: SelectorOptions
public record SelectorPopupOptions : SelectorOptions
{
public ImGuiPopupFlags PopupFlags { get; init; } = ImGuiPopupFlags.None;
public bool CloseOnSelection { get; init; } = false;
public Func<string, bool> IsSelected { get; init; } = _ => false;
}
private static void SearchInput(string id, IEnumerable<string> filteredSheet, Func<string, string, bool> searchPredicate)
private static void SearchInput(
string id,
IEnumerable<string> filteredSheet,
Func<string, string, bool> searchPredicate
)
{
if (ImGui.IsWindowAppearing() && ImGui.IsWindowFocused() && !ImGui.IsAnyItemActive())
{
@@ -51,13 +54,28 @@ public static class SearchSelector
ImGui.SetKeyboardFocusHere(0);
}
if (ImGui.InputTextWithHint("##ExcelSheetSearch", "Search", ref SheetSearchText, 128, ImGuiInputTextFlags.AutoSelectAll))
if (
ImGui.InputTextWithHint(
"##ExcelSheetSearch",
"Search",
ref SheetSearchText,
128,
ImGuiInputTextFlags.AutoSelectAll
)
)
FilteredSearchSheet = null;
FilteredSearchSheet ??= filteredSheet.Where(s => searchPredicate(s, SheetSearchText)).ToArray();
FilteredSearchSheet ??= filteredSheet
.Where(s => searchPredicate(s, SheetSearchText))
.ToArray();
}
public static bool SelectorPopup(string id, out string selected, SelectorPopupOptions? options = null, bool close = false)
public static bool SelectorPopup(
string id,
out string selected,
SelectorPopupOptions? options = null,
bool close = false
)
{
options ??= new SelectorPopupOptions();
var sheet = options.FilteredSheet;
@@ -71,14 +89,26 @@ public static class SearchSelector
if (!popup.Success)
return false;
SearchInput(id, sheet, options.SearchPredicate ?? ((row, s) => options.FormatRow(row).Contains(s, StringComparison.CurrentCultureIgnoreCase)));
SearchInput(
id,
sheet,
options.SearchPredicate
?? (
(row, s) =>
options
.FormatRow(row)
.Contains(s, StringComparison.CurrentCultureIgnoreCase)
)
);
using var child = ImRaii.Child("SearchList", Vector2.Zero, true);
if (!child.Success)
return false;
var ret = false;
var drawSelectable = options.DrawSelectable ?? ((row, selected) => ImGui.Selectable(options.FormatRow(row), selected));
var drawSelectable =
options.DrawSelectable
?? ((row, selected) => ImGui.Selectable(options.FormatRow(row), selected));
using (var clipper = new ListClipper(FilteredSearchSheet!.Length))
{
foreach (var i in clipper.Rows)
@@ -139,7 +169,10 @@ public unsafe class ListClipper : IEnumerable<(int, int)>, IDisposable
{
get
{
var cols = (ItemRemainder == 0 || CurrentRows != DisplayEnd || CurrentRow != DisplayEnd - 1) ? CurrentColumns : ItemRemainder;
var cols =
(ItemRemainder == 0 || CurrentRows != DisplayEnd || CurrentRow != DisplayEnd - 1)
? CurrentColumns
: ItemRemainder;
for (var j = 0; j < cols; j++)
yield return j;
}
@@ -155,7 +188,8 @@ public unsafe class ListClipper : IEnumerable<(int, int)>, IDisposable
Clipper.Begin(CurrentRows, itemHeight);
}
public IEnumerator<(int, int)> GetEnumerator() => (from i in Rows from j in Columns select (i, j)).GetEnumerator();
public IEnumerator<(int, int)> GetEnumerator() =>
(from i in Rows from j in Columns select (i, j)).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+2 -1
View File
@@ -28,7 +28,8 @@ internal static class StringUtil
// "0.#" keeps the rounded fractional digit (1.5 GB stays "1.5GB"); "N0"
// would truncate it back to integer. InvariantCulture pins the decimal
// separator to '.' so a German locale doesn't render "1,5GB".
return (Math.Sign(byteCount) * num).ToString("0.#", CultureInfo.InvariantCulture) + suf[place];
return (Math.Sign(byteCount) * num).ToString("0.#", CultureInfo.InvariantCulture)
+ suf[place];
}
// Returns the text unchanged when it already fits the width budget,
+137 -125
View File
@@ -20,149 +20,161 @@ public static class TabsUtil
// events (loot, crafting, gathering, NPC dialogue, PF pings) move to
// the System tab where they belong — keeps the General view focused
// on actual conversation in the immediate surroundings.
public static Tab VanillaGeneral => new()
{
Name = Language.Tabs_Presets_General,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab VanillaGeneral =>
new()
{
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Yell] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Shout] = (ChatSourceExt.All, ChatSourceExt.All),
}
};
Name = Language.Tabs_Presets_General,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Yell] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Shout] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
public static Tab VanillaEvent => new()
{
Name = Language.Tabs_Presets_Event,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)> { [ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All), },
};
public static Tab VanillaTellExclusive => new()
{
Name = Language.Tabs_Presets_Tell,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab VanillaEvent =>
new()
{
[ChatType.TellIncoming] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.TellOutgoing] = (ChatSourceExt.All, ChatSourceExt.All),
},
Channel = InputChannel.Tell,
AllSenderMessages = true,
};
Name = Language.Tabs_Presets_Event,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
public static Tab VanillaTellExclusive =>
new()
{
Name = Language.Tabs_Presets_Tell,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.TellIncoming] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.TellOutgoing] = (ChatSourceExt.All, ChatSourceExt.All),
},
Channel = InputChannel.Tell,
AllSenderMessages = true,
};
// Hellion default-tab presets used by the v10 wipe migration. Names are
// kept in HellionStrings (EN+DE) instead of Language.* so the upstream
// resource files stay untouched. Channel selections cover the channels
// a typical Eorzea raider uses without forcing the user to hand-tick
// each box on first start.
public static Tab HellionFreeCompany => new()
{
Name = HellionStrings.Tabs_Presets_FreeCompany,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab HellionFreeCompany =>
new()
{
[ChatType.FreeCompany] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
},
Channel = InputChannel.FreeCompany,
};
Name = HellionStrings.Tabs_Presets_FreeCompany,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.FreeCompany] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
},
Channel = InputChannel.FreeCompany,
};
public static Tab HellionParty => new()
{
Name = HellionStrings.Tabs_Presets_Party,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab HellionParty =>
new()
{
[ChatType.Party] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossParty] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Alliance] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeam] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
},
// No automatic input-channel switch; the Gruppe tab is a read
// surface that pulls in Party, CrossParty, Alliance and PvpTeam
// together. Auto-routing /party into this tab would surprise the
// user when they actually wanted /alliance or /pvpteam.
};
Name = HellionStrings.Tabs_Presets_Party,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.Party] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossParty] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Alliance] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeam] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
},
// No automatic input-channel switch; the Gruppe tab is a read
// surface that pulls in Party, CrossParty, Alliance and PvpTeam
// together. Auto-routing /party into this tab would surprise the
// user when they actually wanted /alliance or /pvpteam.
};
public static Tab HellionBeginner => new()
{
Name = HellionStrings.Tabs_Presets_Beginner,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab HellionBeginner =>
new()
{
[ChatType.NoviceNetwork] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
},
Channel = InputChannel.NoviceNetwork,
};
Name = HellionStrings.Tabs_Presets_Beginner,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.NoviceNetwork] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
},
Channel = InputChannel.NoviceNetwork,
};
public static Tab HellionSystem => new()
{
Name = HellionStrings.Tabs_Presets_System,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab HellionSystem =>
new()
{
// Plain system noise
[ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Notice] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.GatheringSystem] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.BattleSystem] = (ChatSourceExt.All, ChatSourceExt.All),
// Login / logout / announcement noise
[ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PeriodicRecruitmentNotification] = (ChatSourceExt.All, ChatSourceExt.All),
// Gameplay-event streams (moved out of General in v1.0.0)
[ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Crafting] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Gathering] = (ChatSourceExt.All, ChatSourceExt.All),
// Misc
[ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Sign] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.GlamourNotifications] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
Name = HellionStrings.Tabs_Presets_System,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
// Plain system noise
[ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Notice] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.GatheringSystem] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.BattleSystem] = (ChatSourceExt.All, ChatSourceExt.All),
// Login / logout / announcement noise
[ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.PeriodicRecruitmentNotification] = (ChatSourceExt.All, ChatSourceExt.All),
// Gameplay-event streams (moved out of General in v1.0.0)
[ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Crafting] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Gathering] = (ChatSourceExt.All, ChatSourceExt.All),
// Misc
[ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Sign] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.GlamourNotifications] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
public static Tab HellionLinkshell => new()
{
Name = HellionStrings.Tabs_Presets_Linkshell,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
public static Tab HellionLinkshell =>
new()
{
[ChatType.Linkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
Name = HellionStrings.Tabs_Presets_Linkshell,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.Linkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.CrossLinkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
public static Dictionary<ChatType, (ChatSource, ChatSource)> MostlyPlayer => new()
{
public static Dictionary<ChatType, (ChatSource, ChatSource)> MostlyPlayer =>
new()
{
// Special
[ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All),
@@ -208,5 +220,5 @@ public static class TabsUtil
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All),
[ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All),
};
};
}
+10 -8
View File
@@ -19,12 +19,13 @@ public static class Tokenizer
UrlString,
StringValue,
Leftover,
SequenceTerminator
SequenceTerminator,
}
public class Token(TokenType tokenType, string value)
{
public Token(TokenType tokenType) : this(tokenType, string.Empty) { }
public Token(TokenType tokenType)
: this(tokenType, string.Empty) { }
public TokenType TokenType { get; } = tokenType;
public string Value { get; } = value;
@@ -49,7 +50,7 @@ public static class Tokenizer
new TokenDefinition(TokenType.OpenParenthesis, "\\(", 1),
new TokenDefinition(TokenType.UrlString, UrlRegex, 1),
new TokenDefinition(TokenType.StringValue, "\\p{IsBasicLatin}", 2),
new TokenDefinition(TokenType.Leftover, ".", 3)
new TokenDefinition(TokenType.Leftover, ".", 3),
];
}
@@ -57,7 +58,8 @@ public static class Tokenizer
{
var tokenMatches = FindTokenMatches(lqlText);
var groupedByIndex = tokenMatches.GroupBy(x => x.StartIndex)
var groupedByIndex = tokenMatches
.GroupBy(x => x.StartIndex)
.OrderBy(x => x.Key)
.ToList();
@@ -97,7 +99,7 @@ public static class Tokenizer
{
Type = returnsToken;
Precedence = precedence;
Regex = new Regex(regexPattern, RegexOptions.IgnoreCase|RegexOptions.Compiled);
Regex = new Regex(regexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
public TokenDefinition(TokenType returnsToken, Regex regex, int precedence)
@@ -110,7 +112,7 @@ public static class Tokenizer
public IEnumerable<TokenMatch> FindMatches(string inputString)
{
var matches = Regex.Matches(inputString);
for(var i = 0; i < matches.Count; i++)
for (var i = 0; i < matches.Count; i++)
{
yield return new TokenMatch
{
@@ -118,7 +120,7 @@ public static class Tokenizer
EndIndex = matches[i].Index + matches[i].Length,
TokenType = Type,
Value = matches[i].Value,
Precedence = Precedence
Precedence = Precedence,
};
}
}
@@ -149,4 +151,4 @@ public static class Tokenizer
@"(?<URL>((https?:\/\/|www\.)[a-z0-9-]+(\.[a-z0-9-]+)*|([a-z0-9-]+(\.[a-z0-9-]+)*\.(com|net|org|co|io|app)))(:[\d]{1,5})?(\/[^\s]*)?)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
);
}
}
+11 -4
View File
@@ -1,5 +1,5 @@
using HellionChat.Resources;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification;
using HellionChat.Resources;
namespace HellionChat.Util;
@@ -7,7 +7,14 @@ public static class WrapperUtil
{
public static void AddNotification(string content, NotificationType type, bool minimized = true)
{
Plugin.Notification.AddNotification(new Notification { Content = content, Type = type, Minimized = minimized });
Plugin.Notification.AddNotification(
new Notification
{
Content = content,
Type = type,
Minimized = minimized,
}
);
}
public static void TryOpenUri(Uri uri)
@@ -23,4 +30,4 @@ public static class WrapperUtil
AddNotification(Language.Context_OpenInBrowserError, NotificationType.Error);
}
}
}
}