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).
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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).
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.
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.
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).
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.
Adds persisted ScreenshotMode flag to Configuration (was previously a
ChatLogWindow-instance field in v1.5.6). Schema bump is additive — no
breaking change. SelfTest renamed V20→V21 with matching version-gate
flip and new touch-test for the new field.
Pre-flight for v1.7.1 PayloadHandler-Pipeline Resurrection.