A frame's comment names the stock file or 1.12 default its shape follows; a Lua comment stays where the code would otherwise be "fixed". Notes the code contradicts are gone. With XML and Lua comments stripped every file is identical, and each is well-formed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
361 lines
21 KiB
XML
361 lines
21 KiB
XML
<Ui>
|
|
<!--
|
|
Benilla's script error log. 1.12 has no such window, so every name here carries the
|
|
`Benilla` prefix (`tests::reference_surface` checks it). It sits beside the stock
|
|
`ScriptErrors` dialog, which shows one message and keeps none: the dialog interrupts,
|
|
this window keeps the log.
|
|
Shaped like the reference's CraftFrame: 13 fixed 16px rows over the stock faux-scroll kit
|
|
and a detail pane below. It registers in `UIPanelWindows`, which seats it in the left slot
|
|
and closes it on ESC, and stays out of `UISpecialFrames`, which belongs to addons.
|
|
The engine's log API: `BenillaGetNumScriptErrors()` returns retained and total-ever
|
|
counts; `BenillaGetScriptErrorInfo(i)` returns `seq, kind, message, count` (1-based,
|
|
oldest first, nil past the end); `BenillaClearScriptErrors()`. The window polls it.
|
|
-->
|
|
<Script><![CDATA[
|
|
-- A left-slot window with a pushable above every stock panel's, so a game window opening
|
|
-- pushes the log aside.
|
|
UIPanelWindows["BenillaScriptLogFrame"] = { area = "left", pushable = 9, whileDead = 1 }
|
|
|
|
BENILLA_SCRIPTLOG_ROWS = 13
|
|
BENILLA_SCRIPTLOG_ROW_HEIGHT = 16
|
|
-- How much of a message a row shows; a wrapped row would break the faux kit's fixed rows.
|
|
BENILLA_SCRIPTLOG_ROW_CHARS = 52
|
|
|
|
-- The selected row's `seq`, not its index: indices shift when the cap evicts.
|
|
BenillaScriptLogSelected = nil
|
|
|
|
-- A message's first line, trimmed to a row. `strsub` counts bytes and messages are UTF-8,
|
|
-- so the cut backs up over continuation bytes (0x80..0xBF) onto a character boundary.
|
|
function BenillaScriptLog_RowText(message)
|
|
local cut = strfind(message, "\n", 1, 1)
|
|
local head = message
|
|
if cut then head = strsub(message, 1, cut - 1) end
|
|
if strlen(head) > BENILLA_SCRIPTLOG_ROW_CHARS then
|
|
local last = BENILLA_SCRIPTLOG_ROW_CHARS - 3
|
|
while last > 0 do
|
|
local b = strbyte(head, last + 1)
|
|
if not b or b < 128 or b >= 192 then break end
|
|
last = last - 1
|
|
end
|
|
head = strsub(head, 1, last) .. "..."
|
|
end
|
|
return head
|
|
end
|
|
|
|
-- Coloured by how much of the addon is broken:
|
|
-- `load` red the addon is not running at all
|
|
-- `error` amber code ran and raised; the addon is otherwise up
|
|
-- `warn` grey a call was accepted and quietly did not do what it said
|
|
function BenillaScriptLog_RowColor(kind)
|
|
if kind == "load" then return 1.0, 0.3, 0.3 end
|
|
if kind == "warn" then return 0.65, 0.65, 0.65 end
|
|
return 1.0, 0.82, 0.0
|
|
end
|
|
|
|
function BenillaScriptLog_Update()
|
|
local shown, total = BenillaGetNumScriptErrors()
|
|
|
|
-- `total` counts distinct failures ever recorded, `shown` what the cap kept. The
|
|
-- summary says "problems" because two of the three kinds are not errors.
|
|
local summary
|
|
if total == 0 then
|
|
summary = "No problems this session."
|
|
elseif total > shown then
|
|
summary = format("%d problems (%d older not kept)", total, total - shown)
|
|
elseif total == 1 then
|
|
summary = "1 problem"
|
|
else
|
|
summary = format("%d problems", total)
|
|
end
|
|
getglobal("BenillaScriptLogSummary"):SetText(summary)
|
|
|
|
local scrollFrame = getglobal("BenillaScriptLogListScrollFrame")
|
|
FauxScrollFrame_Update(scrollFrame, shown, BENILLA_SCRIPTLOG_ROWS, BENILLA_SCRIPTLOG_ROW_HEIGHT)
|
|
BenillaScrollTrough_Follow("BenillaScriptLogListScrollFrame")
|
|
local offset = FauxScrollFrame_GetOffset(scrollFrame)
|
|
|
|
local selectedRow = nil
|
|
for i = 1, BENILLA_SCRIPTLOG_ROWS do
|
|
local button = getglobal("BenillaScriptLogRow" .. i)
|
|
local index = offset + i
|
|
local seq, kind, message, count = BenillaGetScriptErrorInfo(index)
|
|
if seq then
|
|
button.seq = seq
|
|
button.message = message
|
|
-- `#12 x1113`: one deduplicated failure that happened 1,113 times.
|
|
local label = "#" .. seq
|
|
if count > 1 then label = label .. " x" .. count end
|
|
button.index:SetText(label)
|
|
button.label:SetText(BenillaScriptLog_RowText(message))
|
|
button.label:SetTextColor(BenillaScriptLog_RowColor(kind))
|
|
button:Show()
|
|
if seq == BenillaScriptLogSelected then selectedRow = button end
|
|
else
|
|
button.seq = nil
|
|
button.message = nil
|
|
button:Hide()
|
|
end
|
|
end
|
|
|
|
-- The highlight follows the selected row and hides when it scrolls away, as the
|
|
-- reference's CraftFrame does.
|
|
local highlight = getglobal("BenillaScriptLogHighlightFrame")
|
|
if selectedRow then
|
|
highlight:SetPoint("TOPLEFT", selectedRow:GetName(), "TOPLEFT", 0, 0)
|
|
highlight:Show()
|
|
else
|
|
highlight:Hide()
|
|
end
|
|
|
|
BenillaScriptLog_UpdateDetail()
|
|
end
|
|
|
|
-- The selected message in full, traceback and all; selection is a `seq`, so this walks
|
|
-- the log rather than indexing it.
|
|
function BenillaScriptLog_UpdateDetail()
|
|
local text = ""
|
|
if BenillaScriptLogSelected then
|
|
local shown = BenillaGetNumScriptErrors()
|
|
for i = 1, shown do
|
|
local seq, _, message = BenillaGetScriptErrorInfo(i)
|
|
if seq == BenillaScriptLogSelected then
|
|
text = message
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if text == "" then
|
|
text = "Select a row above to read it in full."
|
|
end
|
|
getglobal("BenillaScriptLogDetailText"):SetText(text)
|
|
end
|
|
|
|
-- Text rects resolve after Lua runs, so the detail child is re-measured every frame; once
|
|
-- it settles that is one compare, and OnUpdate fires only while the window is shown.
|
|
function BenillaScriptLogFrame_OnUpdate()
|
|
BenillaScroll_ResizeChild("BenillaScriptLogDetailScroll", { "BenillaScriptLogDetailText" })
|
|
end
|
|
|
|
function BenillaScriptLogRow_OnClick(button)
|
|
if not button.seq then return end
|
|
if BenillaScriptLogSelected == button.seq then
|
|
BenillaScriptLogSelected = nil
|
|
else
|
|
BenillaScriptLogSelected = button.seq
|
|
end
|
|
BenillaScriptLog_Update()
|
|
end
|
|
|
|
function BenillaScriptLogFrame_OnLoad(self)
|
|
-- Masks the square icon to the portrait ring.
|
|
SetPortraitToTexture("BenillaScriptLogFramePortrait",
|
|
"Interface\\Icons\\INV_Misc_Note_01")
|
|
end
|
|
|
|
-- Stepping the bar repaints through the list frame's OnVerticalScroll, so no repaint here.
|
|
function BenillaScriptLogFrame_OnMouseWheel(delta)
|
|
BenillaFauxScrollFrame_OnMouseWheel(getglobal("BenillaScriptLogListScrollFrame"), delta)
|
|
end
|
|
|
|
-- ── Entry points ──────────────────────────────────────────────────────────────────────
|
|
|
|
function BenillaScriptLog_Toggle()
|
|
local frame = getglobal("BenillaScriptLogFrame")
|
|
if frame:IsVisible() then
|
|
HideUIPanel(frame)
|
|
else
|
|
ShowUIPanel(frame)
|
|
end
|
|
end
|
|
|
|
-- `/errors clear`: forgets the rows but keeps the numbering, so a number never names two
|
|
-- failures. It confirms in chat because the window may be closed.
|
|
function BenillaScriptLog_Clear()
|
|
BenillaClearScriptErrors()
|
|
BenillaScriptLogSelected = nil
|
|
if getglobal("BenillaScriptLogFrame"):IsVisible() then
|
|
BenillaScriptLog_Update()
|
|
end
|
|
DEFAULT_CHAT_FRAME:AddMessage("Script log cleared.", 1.0, 1.0, 0.0)
|
|
end
|
|
]]></Script>
|
|
|
|
<!-- One list row: the `#N xCount` index column, then the message head, in fixed columns as
|
|
1.12's lists are. -->
|
|
<Button name="BenillaScriptLogRowTemplate" virtual="true" hidden="true">
|
|
<Size><AbsDimension x="293" y="16"/></Size>
|
|
<Layers>
|
|
<Layer level="ARTWORK">
|
|
<FontString name="$parentIndex" inherits="GameFontNormalSmall" justifyH="LEFT">
|
|
<Size><AbsDimension x="56" y="16"/></Size>
|
|
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="4" y="0"/></Offset></Anchor></Anchors>
|
|
</FontString>
|
|
<FontString name="$parentLabel" inherits="GameFontNormalSmall" justifyH="LEFT">
|
|
<Size><AbsDimension x="229" y="16"/></Size>
|
|
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="62" y="0"/></Offset></Anchor></Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<HighlightTexture file="Interface\Buttons\UI-Listbox-Highlight2" alphaMode="ADD"/>
|
|
<Scripts>
|
|
<OnLoad>
|
|
self.index = getglobal(self:GetName() .. "Index")
|
|
self.label = getglobal(self:GetName() .. "Label")
|
|
</OnLoad>
|
|
<OnClick>BenillaScriptLogRow_OnClick(self)</OnClick>
|
|
</Scripts>
|
|
</Button>
|
|
|
|
<Frame name="BenillaScriptLogFrame" hidden="true">
|
|
<!-- 384x512, the standard left-slot panel size. No <Anchors>: ShowUIPanel seats it. -->
|
|
<Size><AbsDimension x="384" y="512"/></Size>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<!-- A square item icon: OnLoad masks it with `SetPortraitToTexture`, since `file=`
|
|
alone shows its corners through the ring. -->
|
|
<Texture name="BenillaScriptLogFramePortrait" file="Interface\Icons\INV_Misc_Note_01">
|
|
<Size><AbsDimension x="60" y="60"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="7" y="-6"/></Offset></Anchor></Anchors>
|
|
</Texture>
|
|
</Layer>
|
|
<!-- The ClassTrainer quadrants, the one uniform set in the 1.12 art; this window
|
|
belongs to no profession. -->
|
|
<Layer level="BORDER">
|
|
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-TopLeft"><Size><AbsDimension x="256" y="256"/></Size><Anchors><Anchor point="TOPLEFT"/></Anchors></Texture>
|
|
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-TopRight"><Size><AbsDimension x="128" y="256"/></Size><Anchors><Anchor point="TOPRIGHT"/></Anchors></Texture>
|
|
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-BotLeft"><Size><AbsDimension x="256" y="256"/></Size><Anchors><Anchor point="BOTTOMLEFT"/></Anchors></Texture>
|
|
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-BotRight"><Size><AbsDimension x="128" y="256"/></Size><Anchors><Anchor point="BOTTOMRIGHT"/></Anchors></Texture>
|
|
<FontString name="BenillaScriptLogTitle" inherits="GameFontNormal" justifyH="CENTER" text="Script Errors">
|
|
<Anchors><Anchor point="TOP" relativePoint="TOP"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</FontString>
|
|
<!-- The summary line, the only place the dropped-row count shows. -->
|
|
<FontString name="BenillaScriptLogSummary" inherits="GameFontHighlightSmall" justifyH="LEFT" text="">
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="26" y="-76"/></Offset></Anchor></Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Frames>
|
|
<Button name="BenillaScriptLogCloseButton" inherits="UIPanelCloseButton">
|
|
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-29" y="-8"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
|
|
<!-- Declared before the rows so their text draws over the glow. -->
|
|
<Frame name="BenillaScriptLogHighlightFrame" hidden="true">
|
|
<Size><AbsDimension x="293" y="16"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
|
<Layers><Layer level="ARTWORK">
|
|
<Texture file="Interface\Buttons\UI-Listbox-Highlight2">
|
|
<Anchors><Anchor point="TOPLEFT"/><Anchor point="BOTTOMRIGHT"/></Anchors>
|
|
</Texture>
|
|
</Layer></Layers>
|
|
</Frame>
|
|
|
|
<Button name="BenillaScriptLogRow1" inherits="BenillaScriptLogRowTemplate">
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="22" y="-94"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="BenillaScriptLogRow2" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow1" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow3" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow2" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow4" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow3" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow5" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow4" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow6" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow5" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow7" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow6" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow8" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow7" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow9" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow8" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow10" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow9" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow11" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow10" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow12" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow11" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
<Button name="BenillaScriptLogRow13" inherits="BenillaScriptLogRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="BenillaScriptLogRow12" relativePoint="BOTTOMLEFT"/></Anchors></Button>
|
|
|
|
<!-- The faux kit over the 13-row span; only its right-hand Slider renders. -->
|
|
<ScrollFrame name="BenillaScriptLogListScrollFrame" inherits="FauxScrollFrameTemplate">
|
|
<Size><AbsDimension x="293" y="208"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="22" y="-94"/></Offset></Anchor></Anchors>
|
|
<Scripts>
|
|
<!-- The stock kit sets the offset only from here and has no `updateFunc`, so
|
|
the repaint is wired here too. -->
|
|
<OnVerticalScroll>FauxScrollFrame_OnVerticalScroll(BENILLA_SCRIPTLOG_ROW_HEIGHT, BenillaScriptLog_Update)</OnVerticalScroll>
|
|
</Scripts>
|
|
</ScrollFrame>
|
|
|
|
<!-- The detail pane, on the real-scroll kit: a message with its `stack traceback:` tail
|
|
has variable height. -->
|
|
<ScrollFrame name="BenillaScriptLogDetailScroll">
|
|
<Size><AbsDimension x="293" y="128"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="22" y="-314"/></Offset></Anchor></Anchors>
|
|
<Scripts>
|
|
<OnLoad>self:SetScrollChild(getglobal(self:GetName() .. "Child"))</OnLoad>
|
|
<OnMouseWheel>BenillaScroll_OnMouseWheel(self, arg1)</OnMouseWheel>
|
|
<OnVerticalScroll>BenillaScroll_SyncBar(self)</OnVerticalScroll>
|
|
<OnScrollRangeChanged>BenillaScroll_SyncBar(self)</OnScrollRangeChanged>
|
|
</Scripts>
|
|
<Frames>
|
|
<Slider name="$parentBar" inherits="BenillaScrollBarTemplate" hidden="true">
|
|
<Anchors>
|
|
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="6" y="-16"/></Offset></Anchor>
|
|
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="6" y="16"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts><OnValueChanged>BenillaScrollBar_OnValueChanged(self, arg1)</OnValueChanged></Scripts>
|
|
</Slider>
|
|
<Frame name="$parentChild">
|
|
<Size><AbsDimension x="293" y="128"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
|
<Layers>
|
|
<Layer level="ARTWORK">
|
|
<!-- 270 wide so the traceback wraps rather than clips. -->
|
|
<FontString name="BenillaScriptLogDetailText" inherits="GameFontHighlightSmall" justifyH="LEFT" justifyV="TOP" text="">
|
|
<Size><AbsDimension x="270" y="0"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="6" y="-6"/></Offset></Anchor></Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
</Frame>
|
|
</Frames>
|
|
</ScrollFrame>
|
|
|
|
<Button name="BenillaScriptLogClearButton" inherits="UIPanelButtonTemplate" text="Clear">
|
|
<Size><AbsDimension x="96" y="22"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="22" y="-455"/></Offset></Anchor></Anchors>
|
|
<Scripts><OnClick>BenillaScriptLog_Clear()</OnClick></Scripts>
|
|
</Button>
|
|
<Button name="BenillaScriptLogCloseBottomButton" inherits="UIPanelButtonTemplate" text="Close">
|
|
<Size><AbsDimension x="96" y="22"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="219" y="-455"/></Offset></Anchor></Anchors>
|
|
<Scripts><OnClick>HideUIPanel(getglobal("BenillaScriptLogFrame"))</OnClick></Scripts>
|
|
</Button>
|
|
</Frames>
|
|
<Scripts>
|
|
<OnLoad>BenillaScriptLogFrame_OnLoad(self)</OnLoad>
|
|
<!-- The list's wheel handler is on the window, since a spin bubbles up the parent
|
|
chain; the detail pane's own handler wins over its rect. -->
|
|
<OnMouseWheel>BenillaScriptLogFrame_OnMouseWheel(arg1)</OnMouseWheel>
|
|
<OnShow>BenillaScriptLog_Update()</OnShow>
|
|
<OnUpdate>BenillaScriptLogFrame_OnUpdate()</OnUpdate>
|
|
</Scripts>
|
|
</Frame>
|
|
<!-- Benilla's slash commands in the stock SlashCmdList, which ChatEdit_ParseText walks after
|
|
its built-ins; each hands its line to SubmitChatInput, where ui_chat::input parses it.
|
|
This file loads after the stock ChatFrame.xml, which declares the table. -->
|
|
<Script><![CDATA[
|
|
local BENILLA_COMMANDS = {
|
|
{ "CHATTEST", "/chattest" },
|
|
{ "SHOT", "/shot" },
|
|
{ "LIQUID", "/liquid" },
|
|
{ "CASTVIS", "/castvis" },
|
|
{ "PARTYTEST", "/partytest" },
|
|
{ "REACTION", "/reaction", "/react" },
|
|
{ "RELOAD", "/reload" },
|
|
{ "ERRORS", "/errors", "/err" },
|
|
{ "CONVERTRAID", "/convertraid" },
|
|
}
|
|
for _, row in ipairs(BENILLA_COMMANDS) do
|
|
local key = "BENILLA_" .. row[1]
|
|
for i = 2, table.getn(row) do
|
|
setglobal("SLASH_" .. key .. (i - 1), row[i])
|
|
end
|
|
SlashCmdList[key] = function(msg)
|
|
SubmitChatInput(row[2] .. " " .. (msg or ""))
|
|
end
|
|
end
|
|
]]></Script>
|
|
</Ui>
|