Add plugin error notifications, per-plugin event invocation wrappers

This commit is contained in:
goaaats 2025-05-01 20:47:03 +02:00
parent 1913a4cd2c
commit ddf0a97c83
11 changed files with 358 additions and 85 deletions

View file

@ -308,8 +308,14 @@ internal class DalamudInterface : IInternalDisposableService
/// <summary>
/// Opens the <see cref="ConsoleWindow"/>.
/// </summary>
public void OpenLogWindow()
/// <param name="textFilter">The filter to set, if not null.</param>
public void OpenLogWindow(string? textFilter = "")
{
if (textFilter != null)
{
this.consoleWindow.TextFilter = textFilter;
}
this.consoleWindow.IsOpen = true;
this.consoleWindow.BringToFront();
}

View file

@ -41,9 +41,9 @@ internal class ConsoleWindow : Window, IDisposable
// Fields below should be touched only from the main thread.
private readonly RollingList<LogEntry> logText;
private readonly RollingList<LogEntry> filteredLogEntries;
private readonly List<PluginFilterEntry> pluginFilters = new();
private readonly DalamudConfiguration configuration;
private int newRolledLines;
@ -87,14 +87,14 @@ internal class ConsoleWindow : Window, IDisposable
: base("Dalamud Console", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)
{
this.configuration = configuration;
this.autoScroll = configuration.LogAutoScroll;
this.autoOpen = configuration.LogOpenAtStartup;
Service<Framework>.GetAsync().ContinueWith(r => r.Result.Update += this.FrameworkOnUpdate);
var cm = Service<ConsoleManager>.Get();
cm.AddCommand("clear", "Clear the console log", () =>
cm.AddCommand("clear", "Clear the console log", () =>
{
this.QueueClear();
return true;
@ -123,6 +123,19 @@ internal class ConsoleWindow : Window, IDisposable
/// <summary>Gets the queue where log entries that are not processed yet are stored.</summary>
public static ConcurrentQueue<(string Line, LogEvent LogEvent)> NewLogEntries { get; } = new();
/// <summary>
/// Gets or sets the current text filter.
/// </summary>
public string TextFilter
{
get => this.textFilter;
set
{
this.textFilter = value;
this.RecompileLogFilter();
}
}
/// <inheritdoc/>
public override void OnOpen()
{
@ -578,7 +591,7 @@ internal class ConsoleWindow : Window, IDisposable
inputWidth = ImGui.GetWindowWidth() - (ImGui.GetStyle().WindowPadding.X * 2);
if (!breakInputLines)
inputWidth = (inputWidth - ImGui.GetStyle().ItemSpacing.X) / 2;
inputWidth = (inputWidth - ImGui.GetStyle().ItemSpacing.X) / 2;
}
else
{
@ -622,24 +635,29 @@ internal class ConsoleWindow : Window, IDisposable
ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.AutoSelectAll)
|| ImGui.IsItemDeactivatedAfterEdit())
{
this.compiledLogFilter = null;
this.exceptionLogFilter = null;
try
{
this.compiledLogFilter = new(this.textFilter, RegexOptions.IgnoreCase);
this.QueueRefilter();
}
catch (Exception e)
{
this.exceptionLogFilter = e;
}
foreach (var log in this.logText)
log.HighlightMatches = null;
this.RecompileLogFilter();
}
}
private void RecompileLogFilter()
{
this.compiledLogFilter = null;
this.exceptionLogFilter = null;
try
{
this.compiledLogFilter = new(this.textFilter, RegexOptions.IgnoreCase);
this.QueueRefilter();
}
catch (Exception e)
{
this.exceptionLogFilter = e;
}
foreach (var log in this.logText)
log.HighlightMatches = null;
}
private void DrawSettingsPopup()
{
if (ImGui.Checkbox("Open at startup", ref this.autoOpen))
@ -799,15 +817,15 @@ internal class ConsoleWindow : Window, IDisposable
{
if (string.IsNullOrEmpty(this.commandText))
return;
this.historyPos = -1;
if (this.commandText != this.configuration.LogCommandHistory.LastOrDefault())
this.configuration.LogCommandHistory.Add(this.commandText);
if (this.configuration.LogCommandHistory.Count > HistorySize)
this.configuration.LogCommandHistory.RemoveAt(0);
this.configuration.QueueSave();
this.lastCmdSuccess = Service<ConsoleManager>.Get().ProcessCommand(this.commandText);
@ -832,7 +850,7 @@ internal class ConsoleWindow : Window, IDisposable
this.completionZipText = null;
this.completionTabIdx = 0;
break;
case ImGuiInputTextFlags.CallbackCompletion:
var textBytes = new byte[data->BufTextLen];
Marshal.Copy((IntPtr)data->Buf, textBytes, 0, data->BufTextLen);
@ -843,11 +861,11 @@ internal class ConsoleWindow : Window, IDisposable
// We can't do any completion for parameters at the moment since it just calls into CommandHandler
if (words.Length > 1)
return 0;
var wordToComplete = words[0];
if (wordToComplete.IsNullOrWhitespace())
return 0;
if (this.completionZipText is not null)
wordToComplete = this.completionZipText;
@ -878,7 +896,7 @@ internal class ConsoleWindow : Window, IDisposable
toComplete = candidates.ElementAt(this.completionTabIdx);
this.completionTabIdx = (this.completionTabIdx + 1) % candidates.Count();
}
if (toComplete != null)
{
ptr.DeleteChars(0, ptr.BufTextLen);

View file

@ -3569,6 +3569,24 @@ internal class PluginInstallerWindow : Window, IDisposable
{
ImGui.SetTooltip(Locs.PluginButtonToolTip_AutomaticReloading);
}
// Error Notifications
ImGui.PushStyleColor(ImGuiCol.Button, plugin.NotifyForErrors ? greenColor : redColor);
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, plugin.NotifyForErrors ? greenColor : redColor);
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Bolt))
{
plugin.NotifyForErrors ^= true;
configuration.QueueSave();
}
ImGui.PopStyleColor(2);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip(Locs.PluginButtonToolTip_NotifyForErrors);
}
}
}
@ -4239,6 +4257,8 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string PluginButtonToolTip_AutomaticReloading => Loc.Localize("InstallerAutomaticReloading", "Automatic reloading");
public static string PluginButtonToolTip_NotifyForErrors => Loc.Localize("InstallerNotifyForErrors", "Show Dalamud notifications when this plugin is creating errors");
public static string PluginButtonToolTip_DeletePlugin => Loc.Localize("InstallerDeletePlugin ", "Delete plugin");
public static string PluginButtonToolTip_DeletePluginRestricted => Loc.Localize("InstallerDeletePluginRestricted", "Cannot delete right now - please restart the game.");