1690 Commits
Author SHA1 Message Date
renovate-bot 7ef1337ea0 chore(deps): update minor and patch updates (nuget)
Security / scan (pull_request) Successful in 20s
Build / Build (Release) (pull_request) Successful in 26s
2026-06-03 06:06:55 +00:00
JonKazama-Hellion a13713752e Merge pull request 'chore(deps): update actions/setup-dotnet digest to 9a946fd' (#19) from renovate/actions-setup-dotnet-digest into main
Security / scan (push) Successful in 21s
Build / Build (Release) (push) Successful in 27s
Reviewed-on: #19
2026-06-03 06:06:11 +00:00
renovate-bot a9f42e32c5 chore(deps): update actions/setup-dotnet digest to 9a946fd
Security / scan (pull_request) Successful in 29s
Build / Build (Release) (pull_request) Successful in 45s
2026-06-01 00:32:04 +00:00
JonKazama-Hellion e372afc8ac Merge restoration block 2 (settings without UI) into v1.8.x track 2026-05-31 00:48:58 +02:00
JonKazama-Hellion b0bee25770 feat(input): warn and hold before sending plugin-only symbols 2026-05-31 00:45:31 +02:00
JonKazama-Hellion 92f1736ea9 feat(settings): add world suffix and name format combos to the chat tab 2026-05-31 00:36:09 +02:00
JonKazama-Hellion 83b1708d5d feat(messages): render sender names through the name-aware path 2026-05-31 00:31:48 +02:00
JonKazama-Hellion 8fcb10cf51 chore(release): bump manifest to 1.8.3 for restoration block 2 2026-05-31 00:11:29 +02:00
JonKazama-Hellion 71cf6234b5 Merge restoration block 1 (dead settings) into v1.8.x track 2026-05-30 19:08:15 +02:00
JonKazama-Hellion 78d56f0e3e fix(channels): restore auto-tell limit range to 50 and relocate enable toggle 2026-05-30 19:04:32 +02:00
JonKazama-Hellion ca00f528d6 feat(config): drop dead SidebarTabView and migrate false to top tabs (schema v23) 2026-05-30 18:55:26 +02:00
JonKazama-Hellion a7a5aee982 feat(sidebar): wire configurable expanded width through a single source 2026-05-30 18:22:38 +02:00
JonKazama-Hellion caacb87a6a feat(window): wire move/resize flags and consolidate the duplicate toggle 2026-05-30 17:54:15 +02:00
JonKazama-Hellion 336f722eef feat(window): wire inactive opacity to main window focus state 2026-05-30 16:57:59 +02:00
JonKazama-Hellion 7792b327dc chore(release): bump manifest to 1.8.2 for restoration block 1 2026-05-30 16:17:06 +02:00
JonKazama-Hellion 6581943bf1 Merge restoration block 0 (verification truth) into v1.8.x track 2026-05-30 08:56:00 +02:00
JonKazama-Hellion c84891e75d docs(selftest): add binding render-path selftest standard 2026-05-30 08:43:06 +02:00
JonKazama-Hellion 6af9e05664 test(selftest): add PayloadHandler and ChunkRenderer ctor smoke steps 2026-05-30 08:40:51 +02:00
JonKazama-Hellion ea549ebcd0 test(selftest): remove dead ConfigMigrationV21 step superseded by V22 2026-05-30 08:23:29 +02:00
JonKazama-Hellion d33c25e77a chore(release): bump manifest to 1.8.1 for restoration block 0 2026-05-30 08:18:16 +02:00
JonKazama-Hellion ad892cbcb6 feat(layout): add top-tabs layout mode and shared channel resolver 2026-05-29 14:06:41 +02:00
JonKazama-Hellion a9e70ce2af fix(popout): guard against mid-frame unbind when closing from the header 2026-05-29 13:29:29 +02:00
JonKazama-Hellion db47708264 feat(popout): wire pool + window render + sidebar pop-out routing 2026-05-29 12:49:21 +02:00
JonKazama-Hellion e786257cb3 feat(config): add MainWindowLayoutMode + v22 migration; scaffold popout pool 2026-05-29 11:56:18 +02:00
JonKazama-Hellion b221a6e418 feat(input-bar): wire auto-translate tab picker + payload-replace on send
v1.7.0 component-layer refactor removed ChatLogWindow.cs (which housed
the auto-translate popup) and dropped Ui/AutoCompleteInfo.cs without
migrating the logic into the new InputBar component — v2.x spec §3
said "LÖSCHEN + Logik migrieren", but only the deletion happened.
Result: Tab key did nothing in v1.7.1, and even manually typed
<at:group,key> tokens were never resolved into real auto-translate
payloads on send.

Root cause confirmed empirically via VN-1 diagnostic build
(_logger.LogDebug in SlashCommandCallback proved CallbackCompletion
fires on Tab once the flag is set). Following the diagnose-zuerst
pattern established by Issue #3 to avoid the source-code-only
hypothesis trap from Issue #2.

Migration follows v1.5.6 ChatLogWindow.DrawAutoComplete + ChatTwo
upstream AutoCompleteHandler patterns, but ported to v1.7.0 stil:

- ImGuiInputTextFlags extended with CallbackCompletion (Tab trigger)
  and CallbackAlways (cursor restore via _activatePos analog v1.5.6
  ActivatePos)
- SlashCommandCallback now dispatches three branches: CallbackAlways
  (cursor restore), CallbackCompletion (Tab → word-boundary search
  via Encoding.UTF8.GetString on the byte span, char-offset DTO
  construction to avoid the byte-vs-char drift in v1.5.6's raw
  pointer arithmetic), CallbackEdit (existing slash-command help
  detection, now properly scoped)
- 7 new private state fields (_autoCompleteInfo, _autoCompleteOpen,
  _autoCompleteList, _fixCursor, _autoCompleteSelection,
  _autoCompleteShouldScroll, _activatePos)
- DrawAutoCompletePopup renders the picker at the end of Draw():
  IsWindowAppearing seeds _fixCursor + focus, ListClipper-wrapper
  from Util/SearchSelector.cs (IDisposable, automatic Destroy) for
  the result list, Ctrl+0-9 quick-pick, Enter/Escape handling,
  char-splice commit (_pendingMessage = before + replacement + after)
- AutoCompleteCallback handles popup-input-field fix-cursor seeding,
  Up/Down navigation with wrap-around, Tab cycle in the default case
- TrySend now runs AutoTranslate.ReplaceWithPayload(ref bytes) and
  sends via ChatBox.SendMessageUnsafe(byte[]) with a manual 500-byte
  guard, because SendMessage(string) would route through SanitiseText
  which destroys the binary SeString macro bytes that
  ReplaceWithPayload emits
- AutoCompleteInfo DTO added as sealed internal companion type at the
  end of InputBar.cs (15 LOC, exclusively consumed by InputBar);
  ToComplete is a mutable field rather than auto-property so it can
  be passed as ref to ImGui.InputTextWithHint without CS0206

Verified in-game (Flo): Tab on empty input opens picker with full
list, "fire" + Tab filters correctly, Up/Down/Tab navigate, Enter
commits <at:group,key>, send resolves to real auto-translate payload
in chat, Ctrl+0-9 quick-pick works, Escape closes without commit.
dotnet build clean, dotnet csharpier check clean.

Single minor plan-drift: scroll-to-selected uses
ImGui.SetScrollY(selection * lineHeight) instead of
SetScrollFromPosY(clipper.StartPosY) because the local
ListClipper-wrapper does not expose StartPosY — same UX effect.
2026-05-28 17:23:11 +02:00
JonKazama-Hellion 0319636fc5 fix(chat): route inventory item-link addIfNotPresent into InputBar
The AddonChatLog.OnRefresh hook is registered and fires correctly
when the user picks "Link item" from the inventory right-click menu
in-game. The detour extracts addIfNotPresent="<item>" from the
AtkValue array — verified empirically via a temporary _logger.LogDebug
diagnostic build (eventId=31 valueUInt=C addIfNotPresent=<item>).

Pre-fix the extracted value was discarded with `_ = addIfNotPresent;`
and a comment "Chat-window Activated integration is offline until the
new chat layer surfaces an Activated entry point." The Activated entry
point on the new v1.7.0 component layer has existed since that cycle
(InputBar.AppendPending + InputBar.Activate, same pattern as
PayloadHandler.DrawStatusPopup:546-549), but the rewiring was forgotten
when ChatLogWindow.Activated() was removed.

Route addIfNotPresent through InputBar.AppendPending with a
v1.5.6-equivalent !PendingMessage.Contains() guard to prevent
double-insertion on repeated OnRefresh events. Activate = true marks
the input bar for ImGui.SetKeyboardFocusHere on the next draw, so the
user can immediately keep typing after the link is inserted.

Verified in-game: right-click "Link item" on multiple inventory items
inserts <item> into the HellionChat input bar, repeated link insertion
does not produce <item><item>, MainWindow gains keyboard focus.
2026-05-28 16:03:57 +02:00
JonKazama-Hellion b954a19b67 fix(payload-handler): popup-pfad in MessageList-Child-Scope verschieben
Seit dem v1.7.0-Components-Layer-Refactor lebte der PayloadHandler-
Popup-Render in MainWindow.Draw als _messages.DrawHandlerPopups()-
Aufruf nach dem ##hellion-body-Child-Close. ImGui.OpenPopup (in
RightClickPayload, innerhalb ##hellion-main-area-Child) und
ImGui.BeginPopup (in PayloadHandler.DrawPopups, im MainWindow-Root
nach Child-Close) hashed die Popup-ID per g.CurrentWindow->GetID(...)
window-relativ — also unterschiedlich. OpenPopupStack-Eintrag wurde
nie gefunden, popup.Success blieb false, _popup wurde auf null
zurückgesetzt. Alle vier Popup-Switch-Cases waren tot: URL-Rechtsklick,
Player, Item (inkl. EventItem-Subpfad), Status.

Fix nach v1.5.6/ChatTwo-Pattern: _handler?.Draw() ans Ende von
MessageList.Draw() verschieben. MessageList läuft im
##hellion-main-area-Scope und öffnet selbst kein Child, also teilen
OpenPopup und BeginPopup denselben Window-Stack. ID-Hash matched,
Popup rendert.

DrawHandlerPopups-Wrapper aus MessageList und der Aufruf in
MainWindow.Draw entfallen — kein toter Code mehr (grep
DrawHandlerPopups: 0 Treffer).

Hypothese verifiziert gegen imgui.h:845 + imgui.cpp:12282+12528
(beide BeginPopup-Hash und OpenPopup-Hash sind window-relativ),
v1.5.6 ChatLogWindow.cs:1667 (handler.Draw im
##chat2-messages-Child), ChatTwo ChatLog.Window.cs:620 (identisches
Pattern). Reader-Lock auf tab.Messages bleibt während DrawPopups
gehalten — identisch zu v1.5.6-Semantik.

Verifiziert in-game (Flo): Linksklick auf URL öffnet Browser direkt
(v1.5.6-konform), Rechtsklick öffnet wieder das Kontext-Popup. dotnet
build clean, dotnet csharpier check clean.

Plan-Runde 1 dieses Cycles (4-LOC-Reroute LeftClick → RightClickPayload)
wurde verworfen weil empirischer Test zeigte dass auch Rechtsklick
broken war — der Reroute hätte das Symptom nur sichtbarer gemacht
ohne die Root-Cause zu adressieren.
2026-05-28 15:25:05 +02:00
JonKazama-Hellion 29fb4b92eb fix(input-preview): wire Inside-mode + Tooltip-mode render paths
InputPreview was only rendered for PreviewPosition.Top/Bottom (the
DrawConditions IsWindowMode gate). Inside-mode (the default) and
Tooltip-mode had no caller at all because v1.5.6's inline-render path
lived on the deleted ChatLogWindow and was not migrated to the v1.7.0
Components-Layer.

Wire Inside-mode by calling CalculatePreviewHeight + DrawPreview
inline from MainWindow.DrawMainArea between the message-list child
and the input bar, with the message-list height reserved for the
preview block. Wire Tooltip-mode by sampling IsItemHovered() on the
input text widget inside InputBar.DrawInputField (analog to the
existing _isFocused = ImGui.IsItemFocused() idiom on the same line)
and exposing it as WasInputTextHovered; MainWindow opens the tooltip
after _input.Draw when both the hover-flag and PreviewPosition.Tooltip
are active.

Plan-drift acknowledged: the plan stated Plugin.InputPreview is
statically reachable, but the property was declared as an instance
member on Plugin.cs:101. Hoisted to internal static to match the
plan's intention (analog to Plugin.Config); updated the single
external instance-access site in PluginLifecycle.RegisterWindows
to the type-qualified form.

Verified in-game: Inside-mode preview block appears between message
list and input bar on first keystroke; tooltip-mode shows preview on
text-field hover only; Top/Bottom-mode unchanged; empty buffer hides
the preview in all modes. dotnet build clean, dotnet csharpier check
clean.
2026-05-28 13:21:59 +02:00
JonKazama-Hellion 24d3f69041 fix(host): break InputBar/CommandHelpWindow/MainWindow DI cycle
J + J2 closed a singleton cycle:
  InputBar.ctor -> CommandHelpWindow (J2)
  CommandHelpWindow.ctor -> MainWindow (J)
  MainWindow.ctor -> InputBar (pre-existing)

MS.DI does not detect cycles through FactoryCallSite registrations,
so resolution recursed silently on the async plugin-init thread until
the worker died with an uncatchable StackOverflowException. Dalamud's
LoadAsync task never resolved; the plugin UI hung on "Enabling..."
with no exception in the log. First triggered at Plugin.cs:289
(TypingIpc.ctor needs InputBar).

Fix: break the cycle on the laziest edge.
  - CommandHelpWindow.ctor no longer takes MainWindow.
  - New AttachMainWindow setter wired in
    CommandHelpWindowInitHostedService.StartAsync, mirroring the
    existing §6.2 MessageList.AttachPayloadHandler pattern.
  - UpdateContent throws InvalidOperationException if the setter
    never ran, so a future regression fails loudly instead of a
    silent NullRef during input draw.

Also enable UseDefaultServiceProvider(ValidateOnBuild + ValidateScopes)
so future ConstructorCallSite cycles throw at Build time instead of
silently hanging. Catches reflection-based registrations; will not
catch FactoryCallSite cycles like this one (those still need code review).

Verified via 6 enable/disable cycles in-game; plugin loads cleanly,
Hosting starts, FilterAllTabs completes, command help popup renders
for /em and /say (exercises AttachMainWindow), hover counter ticks
(exercises PayloadHandlerInitHostedService AddonLifecycle wiring).
2026-05-28 08:16:27 +02:00
JonKazama-Hellion f6749d206b chore(polish): cycle-end sweep — drop dead fields, dep-cycle, comments
Accumulated polish across the v1.7.1 R-Block reviewer findings. Single
sweep before Phase-3 Smoke-Gate.

Dep-cycle cleanup (Block H + #30):
- CommandHelpWindow drops the dead _inputBar ctor-param + discard that
  was J's speculative prep; this eliminates the InputBar <-> CommandHelpWindow
  ctor cycle at its root
- InputBar replaces Lazy<CommandHelpWindow> wrapper with direct
  CommandHelpWindow ctor-param now that the cycle is broken
- PluginHostFactory InputBar + CommandHelpWindow DI-regs simplified

Dead-field removals:
- MessageList drops _themes + _resolver (no reads after H's render-path
  swap to _chunkRenderer.DrawChunks)
- InputBar drops FocusedPreview (no consumer wiring in the new architecture)
- InputPreview drops SelectedCursorPos (v1.5.6 letter-by-letter renderer
  artifact, no callers in R1)
- InputPreview drops WhitespaceRegex + partial keyword on class (dead
  GeneratedRegex with no callers)

Visibility fixes:
- InputPreview + CommandHelpWindow + DebuggerWindow ctors flip
  public -> internal for consistency with internal sealed class declarations

DI helper extraction:
- PluginHostFactory MakePayloadHandler private static helper DRYs the
  7-arg list shared between PayloadHandler-singleton and Lender<T> factory

ImGui-rendering fix:
- MessageList.DrawCompactRow uses SameLine(0f, 0f) — eliminates visible
  ItemSpacing.X gap between sender-prefix and chunk content

Bug fixes:
- PayloadHandler.LeftClickPayload drops spurious unsafe keyword (no
  pointer ops in the method body; v1.5.6 had no unsafe here)
- PayloadHandler.StringifyMessage Aggregate seeded with string.Empty to
  fix empty-sequence crash for pure-icon messages
- PayloadHandler.MoveTooltip args==null LogWarning template simplified
  (?.GetType().Name was always null after the null-check — misleading)
- InputBar.SlashCommandCallback drops redundant BufTextLen==0 guard
  (BufTextSpan handles empty correctly)

Comment improvements (WHY-not-WHAT):
- ImGuiUtil.cs payload-state cluster comment moved below Buttons array
- PayloadHandler: §6.9 trimmed to 1 line, FindCharacterForPayload
  documented, hq symbol marker restored, MoveTooltip guard documented
  as defensive v1.7.1 addition, NativeItemTooltips branch explained,
  §4.2 theme colour swap explained
- DebuggerWindow class comment mentions PayloadHandler counters section
- InitHostedServices StopAsync explains params-overload semantics
- InputBar AppendPending null policy vs SetPendingMessage documented,
  CommandManager leading-slash assumption noted
- PluginHostFactory block comment explains singleton+Lender split

Build: 0 warnings, 0 errors. csharpier: clean. Version unchanged.
2026-05-27 23:42:28 +02:00
JonKazama-Hellion d1bfddd9b8 feat(main-window): wire Lender + handler.Draw() (A2, MessageList popups)
A2 completes the deferred Lender-cycle from A1 and addresses the
handler.Draw() gap identified in I code-quality-review:

- MainWindow ctor takes Lender<PayloadHandler> as new param (DI-reg
  extended in PluginHostFactory); _handlerLender.ResetCounter() called
  at top of Draw() as primary pool-reset path (InputPreview has the
  secondary defensive fallback for MainWindow-closed edge case)

- MessageList.DrawHandlerPopups() new passthrough method
  (=> _handler?.Draw()) provides the per-frame popup-tick that
  PayloadHandler needs to render the right-click context popup;
  MainWindow.Draw() calls it after the message-list body renders

Without this fix, right-clicking a player/item/status in the chat log
would silently fail to open a popup (handler.Draw() never fired for the
MessageList's _handler). Phase 3 smoke steps 3/4/5 unblocked.

Polish-Sweep + Smoke-Gate are the last cycle-tasks.
2026-05-27 23:29:18 +02:00
JonKazama-Hellion cba6a16f8e feat(input-bar): wire slash-command callback + AllCommands (J2)
J2 closes the trigger-gap discovered in J review (2026-05-27): J
migrated CommandHelpWindow as a window but the v1.5.6 trigger-path
was never ported. J2 restores it:

- InputBar.cs adds ImGuiInputTextFlags.CallbackEdit + character-level
  callback that reads data.BufTextSpan, detects /-prefix, extracts
  command word, and calls _commandHelpWindow.Value.UpdateContent(desc)
- AllCommands.cs (new file, 1:1 port from v1.5.6) populates a static
  Dictionary<string, TextCommand> from Sheets.TextCommandSheet at
  startup; Plugin.CommandManager.Commands is the fallback for
  non-hardcoded commands
- CommandHelpWindow injected into InputBar via Lazy<T> ctor param to
  break the InputBar <-> CommandHelpWindow circular dep; PluginHostFactory
  DI-reg extended with the Lazy wrapper accordingly

Closes the smoke-step-9 gap. Phase-3 windows are now all reachable
end-to-end (R1 InputPreview, R2 CommandHelpWindow, R3 DebuggerWindow).
2026-05-27 23:19:21 +02:00
JonKazama-Hellion c652a1c450 feat(debugger): reactivate PayloadHandler counters (R3)
K reactivates the debugger's PayloadHandler counter readout
(HandleTooltips / HoveredItem / HoverCounter / LastHoverCounter —
populated in E1's PayloadHandler skeleton). PayloadHandler injected
via DI-extended ctor; class flipped to internal sealed to match
PayloadHandler's internal visibility and avoid CS0051. Plugin.cs
property updated public → internal accordingly (same pattern as I/J).

Last Phase-3 window sub-task before A2 (Lender + handler.Draw fix),
J2 (InputBar slash-callback), Polish-Sweep, and Smoke-Gate.
2026-05-27 22:54:33 +02:00
JonKazama-Hellion 830d247eda feat(command-help-window): full R2 migration (ctor-injected + DI-reg)
J resurrects CommandHelpWindow from the v1.7.0 stub state:

- Class header public → internal sealed
- Ctor takes 4 DI deps (ChunkRenderer, MainWindow, InputBar, ILogger)
  via Factory-Lambda DI-reg. NO Lender<PayloadHandler> — command-help
  chunks are read-only command-description text with no click-targets
  (per spec §5-J + F W8 consumer audit).
- Draw() calls _chunkRenderer.DrawChunks(desc chunks, wrap: true,
  handler: null, lineWidth: 0f) — null-handler is intentional.
- Plugin.cs property visibility flipped public → internal to satisfy
  CS0053 (analogous to I's InputPreview fix).

K (R3 DebuggerWindow counters) and A2 (Lender + handler.Draw fix) are
the remaining Phase-3 sub-tasks before Polish-Sweep + Smoke-Gate.
2026-05-27 21:04:42 +02:00
JonKazama-Hellion 8431fbcf80 feat(input-preview): full R1 migration (PreOpenCheck/PreDraw split + Lender)
I resurrects InputPreview as a fully ctor-injected window:

- Class header public → internal sealed (Components-Layer style); Plugin.cs
  property visibility corrected to internal to match
- Ctor takes 5 DI deps (ChunkRenderer, Lender<PayloadHandler>, MainWindow,
  InputBar, ILogger) via Factory-Lambda DI-reg
- Window-hook split: PreOpenCheck() owns the state (Drawing/PreviewMessage/
  HasEvaluation/PreviewHeight/LastLength), PreDraw() owns position/size
  computation. Matches v1.5.6's split — avoids wasted position-math when
  Window isn't drawn (DrawConditions gates on IsDrawable getter).
- Framework.Update subscribe/unsubscribe removed (PreOpenCheck runs per
  draw-frame, same cadence as Framework.Update for our needs)
- Draw() borrows fresh PayloadHandler per-frame from Lender for popup
  isolation (preview hover doesn't bleed into log)
- Defensive ResetCounter fallback when MainWindow closed + InputPreview
  open — primary path is A2's MainWindow.Draw() ResetCounter

R2/R3 (J/K) next. A2 closes out the Lender DI-cycle for MainWindow.
2026-05-27 20:35:25 +02:00
JonKazama-Hellion 931a152d00 feat(infra): wire PayloadHandlerInitHostedService (AddonLifecycle + setter)
G connects PayloadHandler to the runtime — this is the activation point
after E1-E6 built the type and F registered it in DI:

- StartAsync calls MessageList.AttachPayloadHandler(_payloadHandler) to
  complete the §6.2 cycle-resolution (ctor-cycle was broken by setter,
  this is where the setter actually fires)
- StartAsync registers AddonLifecycle listener for MoveTooltip on
  PostUpdate of "ItemDetail" and "ActionDetail" addons
- StopAsync unregisters the listener
- Both Register/Unregister wrapped in Plugin.Framework.RunOnFrameworkThread
  as defensive insurance — IAddonLifecycle thread-affinity is not
  explicitly documented in Dalamud API; wrap keeps the v1.5.6 runtime
  contract intact (per spec §5-G note)

Mirrors existing IpcManagerInitHostedService / TypingIpcInitHostedService
pattern in Infrastructure/Hosting/. PluginHostFactory adds the
AddHostedService<PayloadHandlerInitHostedService>() registration.

After G, the chunked-message-render pipeline is end-to-end functional:
MessageList renders via ChunkRenderer, _handler is wired so popups fire
on click/hover, MoveTooltip repositions native item-tooltips away from
the chat window.
2026-05-27 20:03:52 +02:00
JonKazama-Hellion 4fb5ee6128 feat(message-list): wire ChunkRenderer ctor + AttachPayloadHandler setter
H integrates the chunk-render pipeline into MessageList:

- Extends ctor to 4 params (themes, resolver, fonts, chunkRenderer);
  TokenResolver preserved as load-bearing dep
- Adds private PayloadHandler? _handler field + internal
  AttachPayloadHandler(PayloadHandler) setter
- Switches DrawCompactRow/DrawCardRow render-path to
  _chunkRenderer.DrawChunks(message.Content, wrap, handler, 0f)
  instead of plain TextUnformatted

Setter-injection for PayloadHandler is the §6.2 cycle-resolution
(PayloadHandler → MainWindow → MessageList → PayloadHandler ctor-cycle
broken by post-construction wiring). G's HostedService.StartAsync will
call AttachPayloadHandler after both singletons resolve.

Also extends MessageList DI-reg in PluginHostFactory.cs with the
ChunkRenderer arg (4th GetRequiredService).
2026-05-27 19:24:20 +02:00
JonKazama-Hellion 2e143686af feat(host-factory): register ChunkRenderer + PayloadHandler + Lender (F)
F adds the 3 new DI registrations needed for the v1.7.1 R-Block:

- ChunkRenderer (4-param ctor: themes, fonts, logger, gameFunctions)
- PayloadHandler singleton (7-param ctor: themes, ipc, functions,
  inputBar, mainWindow, chunkRenderer, logger)
- Lender<PayloadHandler> factory (closure over sp, constructs a fresh
  PayloadHandler per Borrow() — used by InputPreview in Sub-Task I)

All three use Factory-Lambdas because Lender<T> has an internal ctor and
ChunkRenderer/PayloadHandler are internal sealed (ActivatorUtilities
can't reflect into internal ctors per [[reference_hellion_chat_di_container_v150]]).

MainWindow DI-reg update is deferred to Sub-Task A2 (split per Flo
2026-05-27 to avoid the DI-cycle that would otherwise emerge from the
PayloadHandler → MainWindow → MessageList → PayloadHandler graph —
cycle resolved via setter-injection on MessageList in G/H).

G is next: wires PayloadHandlerInitHostedService.StartAsync to register
the AddonLifecycle listener for MoveTooltip and call MessageList.
AttachPayloadHandler. H adds the MessageList ChunkRenderer ctor-param +
AttachPayloadHandler setter.
2026-05-27 18:44:46 +02:00
JonKazama-Hellion d6012a9459 feat(payload-handler): wire MoveTooltip (E6 completes PayloadHandler)
E6 closes out the PayloadHandler resurrection. MoveTooltip handles the
cross-viewport AddonLifecycle tooltip-repositioning logic — reads
MainWindow.LastViewport/LastWindowPos/LastWindowSize (from A1) to filter
events and reposition the native item tooltip away from the chat window.

Whole method marked `public unsafe void` per spec §4.2 (matches v1.5.6
exactly — avoids per-read unsafe-block scoping).

LogWarning added on the unexpected-AddonArgs early-out branch (wires
_logger into real use, prevents CS0414 unused-field warning).

PayloadHandler is now feature-complete. F registers it in DI; G wires
the AddonLifecycle.RegisterListener for MoveTooltip from a HostedService;
H adds MessageList.AttachPayloadHandler setter-injection.
2026-05-27 14:31:23 +02:00
JonKazama-Hellion 121c96f79e feat(payload-handler): wire Hover/Click + LeftClick/RightClick/LinkClick paths
E5 fills the hover/click handler layer (10 methods):

- Hover/Click: replaces E1's empty stubs with real 1:1 bodies; Click uses
  unsafe for FFXIVClientStructs pointer access (UIGlobals.PlaySoundEffect
  via PopupSfx const from E2)
- DoHover: §4.2 swap LogWindow.DefaultText → _themes.Active.Colors.TextPrimary
- HoverStatus, HoverItem, HoverEventItem: 2x _chunkRenderer.DrawChunks
  swaps each (name + description rendering)
- HoverUri: pure 1:1, no LogWindow deps
- LeftClickPayload: unsafe-preserved, Plugin.GameGui static stays
- ClickLinkPayload: pure 1:1, Plugin.ChatGui / Plugin.Framework statics stay
- RightClickPayload: sets _popup field (per E1/E2 field-syntax convention)

Adds FFXIVClientStructs.FFXIV.Client.UI using for UIGlobals; adds
Action alias and DalamudPartyFinderPayload/ChatTwoPartyFinderPayload
aliases required by LeftClickPayload switch arms.

E6 will wire MoveTooltip. After E5, PayloadHandler is functionally complete
except for the MoveTooltip AddonLifecycle wiring.
2026-05-27 13:51:18 +02:00
JonKazama-Hellion 6da8ac93fe feat(payload-handler): wire DrawItem/EventItem/Status/Uri popups + InlineIcon
E4 fills the remaining popup-body methods:

- DrawItemPopup: shows item-name, icon (via InlineIcon), and description
  via _chunkRenderer.DrawChunks; dispatches to DrawEventItemPopup when
  payload.Kind == ItemKind.EventItem (per v1.5.6 internal split)
- DrawEventItemPopup: same shape, Sheets.EventItemSheet/EventItemHelpSheet
  reads, _chunkRenderer.DrawChunks for description rendering
- DrawStatusPopup: status-name + description via _chunkRenderer.DrawChunks;
  "Link" action appends " <status>" via _inputBar.AppendPending (per §4.2)
- DrawUriPopup: open-in-browser + copy-link selectables (no LogWindow deps)
- InlineIcon: pure static helper for popup-icon rendering

Replaces E2's TODO(E4) markers in DrawPopups' Item/Status/Uri switch-cases
with real calls + drawn=true. E5 will wire Hover/Click bodies; E6
MoveTooltip.
2026-05-27 13:20:59 +02:00
JonKazama-Hellion abc0617d58 feat(payload-handler): wire DrawPlayerPopup + FindCharacterForPayload (E3)
E3 fills the player-payload right-click menu. DrawPlayerPopup migrates
1:1 from v1.5.6 with all §4.2/§6.9 substitutions:

- Tell-prefix builds via _inputBar.SetPendingMessage (single string build)
  + _inputBar.Activate = true (replaces v1.5.6's 3x LogWindow.Chat
  incremental writes + LogWindow.Activate flip)
- Channel-switch routes through _mainWindow.ActiveTab?.CurrentChannel?
  .SetChannel(channel) (per §6.3, ActiveTab is public getter on
  MainWindow per v1.7.0 refactor)
- SendFriendRequest / AddToBlacklist / AddToMuteList / AddToTermsList
  / SetEurekaTellChannel all route through injected _functions
- Player-name renderings route through _chunkRenderer.DrawChunks

FindCharacterForPayload migrates 1:1 (pure helper, Plugin.ObjectTable
static stays as-is).

Replaces E2's TODO(E3) marker in DrawPopups' PlayerPayload case with
real DrawPlayerPopup(chunk, player) call.

E4 will wire Item/EventItem/Status/Uri popup bodies; E5 the Hover/Click
bodies; E6 MoveTooltip.
2026-05-27 12:50:23 +02:00
JonKazama-Hellion 63f5a28834 feat(payload-handler): wire DrawPopups + Integrations/ContextFooter/StringifyMessage
E2 fills the popup-dispatch layer of PayloadHandler:
- DrawPopups: switch-dispatch over payload types, with TODO(E3)/(E4)
  markers at the deferred Draw{Player,Item,Status,Uri}Popup call sites
- Integrations: invokes registered IPC integrations (LogWindow.Plugin.Ipc
  -> _ipc substitution per §4.2)
- ContextFooter: ScreenshotMode + HideChat checkboxes (Plugin.Config
  static-bridge substitutions per §4.2)
- StringifyMessage: pure helper, 1:1 from v1.5.6

Adds PopupSfx const (E1 polish — needed by E5's Click for
UIGlobals.PlaySoundEffect). Removes #pragma CS0169 for _popup since
DrawPopups now writes the field; the warning no longer triggers.

E3 will fill DrawPlayerPopup + FindCharacterForPayload; E4 the
Item/Status/Uri popups; E5 the Hover/Click bodies; E6 MoveTooltip.
2026-05-27 12:19:50 +02:00
JonKazama-Hellion e46b6a7520 feat(imgui-util): resurrect WrapText pipeline (~220 LOC from v1.5.6)
Replaces C2's no-op WrapText stub with the full word-wrap pipeline
(WrapText / WrapEncodedLine / CalcWordWrap / DrawText / FindFirstSpace).
ChunkRenderer.DrawChunk's text-path now renders properly wrapped text
with payload hover-highlights and click-binding via PostPayload (which
was already full-ported in C2).

Also adds LastLink and PayloadBounds static fields that C2's PostPayload
port required but did not declare; DrawText needs both for per-segment
hover-rectangle accumulation across wrapped lines.

Unblocks E5's Hover paths that depend on functional WrapText for
status/item tooltip rendering. No structural changes — pure body
migration of the v1.5.6 unsafe word-wrap implementation.
2026-05-27 10:27:58 +02:00
JonKazama-Hellion 2067a54467 feat(payload-handler): add skeleton with 7-param ctor + Draw() popup tick
Replaces the 15-LOC C2 forward-stub with the full PayloadHandler
skeleton. Class header flips to `internal sealed` per §4.1; ctor takes
7 DI-registered services (ThemeRegistry, IpcManager, GameFunctions,
InputBar, MainWindow, ChunkRenderer, ILogger) per Flo decision
2026-05-27 (ChunkRenderer was added to the ctor list to satisfy the
§4.2 _chunkRenderer.DrawChunks references in HoverStatus/HoverItem/
DrawItemPopup paths — those land in E2-E5).

Draw() per-frame popup tick is a 1:1 port from v1.5.6 PayloadHandler.
DrawPopups() call is stubbed as TODO(E2) since that method lands in E2.
Hover/Click signatures remain empty (E5 fills the bodies, but the
signatures must compile so ChunkRenderer + ImGuiUtil callers stay live).

Skeleton-only — DrawPopups/Integrations (E2), DrawPlayerPopup (E3),
DrawItemPopup/DrawStatusPopup (E4), Hover/Click bodies (E5),
MoveTooltip (E6) all defer to their respective sub-sub-tasks.
2026-05-27 09:58:22 +02:00
JonKazama-Hellion 61a1e6bf87 feat(chunk-renderer): wire DrawIcon + icon-dispatch + EmoteCache path
Completes the ChunkRenderer pipeline. DrawIcon is a 1:1 port of v1.5.6
ChatLogWindow.DrawIcon (GFD-icon font-relative rendering via
Plugin.TextureProvider + ImGuiUtil.PostPayload). C2's TODO(C3) stub in
DrawChunk's IconChunk branch is replaced with the real dispatch.
EmotePayload special-case wired via EmoteCache.GetEmote (static helper
per §6.8).

Also adds a one-line rationale comment for the surviving _logger discard
(C2 code-quality-review polish — discard kept because _logger is not yet
consumed; E-task wiring will likely add call-sites later).
2026-05-27 09:29:35 +02:00
JonKazama-Hellion dec0daf30c feat(chunk-renderer): add DrawChunks + DrawChunk text-path (C3 stubs icon)
Resurrects v1.5.6 ChatLogWindow's DrawChunks/DrawChunk text-rendering
pipeline into the new ChunkRenderer Components-Layer class. Text-chunk
path is the full v1.5.6 migration (Plugin.Config.ScreenshotMode,
_themes.Active.Colors.TextPrimary, _fonts.ItalicFont/_fonts.AxisItalic
substitutions applied per §4.2/§4.5); icon-chunk dispatch in DrawChunk
is stubbed pending C3 (EmoteCache + DrawIcon path).

ImGuiUtil.WrapText is forward-stubbed in Util/ImGuiUtil.cs as a no-op
TextUnformatted wrapper — Sub-Task D will replace the body with the
full ~220-LOC word-wrap pipeline. ImGuiUtil.PostPayload is also
forward-stubbed (payload hover/click routing belongs to Sub-Task E).
Both stubs are the cleanest cut to keep DrawChunk's body faithful to
v1.5.6 and avoid temporary fallback paths inside ChunkRenderer.

PayloadHandler.cs is a minimal forward-stub class (Hover + Click stubs
only) required by the DrawChunks/DrawChunk and PostPayload signatures.
Sub-Task E will replace this stub with the full implementation.

Discard pattern from C1 removed for _themes/_fonts (now genuinely
consumed by DrawChunks/DrawChunk); _logger discard kept — not yet
consumed in C2, deferred to E-task wiring.
2026-05-27 08:59:23 +02:00
JonKazama-Hellion 7e541ac842 feat(chunk-renderer): add skeleton + per-ctor salt + player-hide helpers
Extracts v1.5.6's `ChatLogWindow.HidePlayerInString` / `HashPlayer` into
a standalone `Ui/Components/ChunkRenderer` class. C1 lands the skeleton
(ctor + DI-deps + salt + two pure helpers); C2 will add DrawChunks/DrawChunk
text-path; C3 will add DrawIcon + EmoteCache integration.

Salt is per-ctor random matching v1.5.6 session-random behavior — hashed
player names change every plugin reload to avoid stable cross-session
linkage (Spec §6.5 decision).

GameFunctions injected via ctor (not static Plugin.Functions) because
Plugin.Functions is a non-static internal property — injection is the
correct Components-layer pattern for this dependency.

Not yet DI-registered (Sub-Task F) and not yet consumed by MessageList
(Sub-Task H) — class compiles standalone.
2026-05-27 08:19:08 +02:00
JonKazama-Hellion 94fdef38ad feat(main-window): track per-frame window pos/size/viewport for PayloadHandler
Replaces the v1.5.6 `LogWindow.LastViewport/LastWindowPos/LastWindowSize`
window-instance state with public/internal MainWindow surfaces refreshed
at the top of Draw() each frame. PayloadHandler.MoveTooltip in Phase 2
will read these to filter cross-viewport AddonLifecycle events and to
reposition the native item tooltip away from the chat window.

LastViewport is `internal unsafe` (not public) — the only consumer is
PayloadHandler.MoveTooltip in the same assembly; keeping the raw pointer
out of the public surface is the safer default.

Split from Sub-Task A — Lender injection lives in A2 (after F's DI-reg).
2026-05-27 08:08:29 +02:00
JonKazama-Hellion 01fc69efda feat(input-bar): add SetPendingMessage/AppendPending mutators + Activate/FocusedPreview flags
Replaces v1.5.6's direct LogWindow.Chat mutation pattern with typed mutators
that LogWarning + clip/drop on BufferCapacity overflow (silent-overwrite
semantics preserved, but overflow is now observable via /xllog).

Plumbing for v1.7.1 PayloadHandler resurrection — DrawPlayerPopup (tell-
prefix) and DrawStatusPopup (status-link append) will call these mutators
instead of mutating a public field.
2026-05-27 07:59:39 +02:00