464 lines
15 KiB
Lua
464 lines
15 KiB
Lua
--[[
|
|
Expression 2 Helper for Expression 2
|
|
-HP- (and tomylobo, though he breaks a lot ^^) Divran made CPU support
|
|
]] --
|
|
|
|
E2Helper = {}
|
|
local E2Helper = E2Helper -- faster access
|
|
E2Helper.Descriptions = {}
|
|
|
|
include("e2descriptions.lua")
|
|
|
|
-------------------------------
|
|
---- CPU support
|
|
E2Helper.CPUDescriptions = {}
|
|
E2Helper.CPUTable = {}
|
|
E2Helper.CurrentMode = true -- E2/CPU. True = E2, false = CPU
|
|
|
|
local function AddCPUDesc(FuncName, Args, Desc, Platform, Type)
|
|
table.insert(E2Helper.CPUTable, { [1] = FuncName, [2] = Args, [3] = Platform, [4] = Type })
|
|
E2Helper.CPUDescriptions[FuncName] = Desc
|
|
end
|
|
|
|
-- Add help on all opcodes
|
|
for _, instruction in ipairs(CPULib.InstructionTable) do
|
|
if (instruction.Mnemonic ~= "RESERVED") and
|
|
(not instruction.Obsolete) then
|
|
|
|
local instructionArgs = instruction.Operand1
|
|
if instruction.Operand2 ~= "" then
|
|
instructionArgs = instructionArgs .. ", " .. instruction.Operand2
|
|
end
|
|
|
|
AddCPUDesc(instruction.Mnemonic,
|
|
instructionArgs,
|
|
instruction.Reference,
|
|
instruction.Set,
|
|
instruction.Opcode)
|
|
end
|
|
end
|
|
|
|
|
|
-- Which tables are we going to use?
|
|
local function CurrentDescs()
|
|
if E2Helper.CurrentMode == true then
|
|
return E2Helper.Descriptions
|
|
else
|
|
return E2Helper.CPUDescriptions
|
|
end
|
|
end
|
|
|
|
local function CurrentTable()
|
|
if E2Helper.CurrentMode == true then
|
|
return wire_expression2_funcs
|
|
else
|
|
return E2Helper.CPUTable
|
|
end
|
|
end
|
|
|
|
-------------------------------
|
|
|
|
local lastmax = 0
|
|
local cookie_maxresults, cookie_tooltip, cookie_w, cookie_h
|
|
local function cookie_update()
|
|
local current_maxresults = E2Helper.MaxEntry:GetValue()
|
|
if current_maxresults > lastmax then
|
|
lastmax = current_maxresults
|
|
E2Helper.Update()
|
|
return -- return, since E2Helper.Update() already called cookie_update again.
|
|
end
|
|
|
|
if current_maxresults ~= cookie_maxresults then
|
|
cookie.Set("e2helper_maxresults", current_maxresults)
|
|
cookie_maxresults = current_maxresults
|
|
end
|
|
|
|
local current_tooltip = E2Helper.Tooltip:GetChecked(true) and 1 or 0
|
|
if current_tooltip ~= cookie_tooltip then
|
|
cookie.Set("e2helper_tooltip", current_tooltip)
|
|
cookie_tooltip = current_tooltip
|
|
end
|
|
|
|
local current_w, current_h = E2Helper.Frame:GetSize()
|
|
if current_w ~= cookie_w then
|
|
cookie.Set("e2helper_w", current_w)
|
|
cookie_w = current_w
|
|
end
|
|
|
|
if current_h ~= cookie_h then
|
|
cookie.Set("e2helper_h", current_h)
|
|
cookie_h = current_h
|
|
end
|
|
end
|
|
|
|
-- returns a function that executes <func>, delayed by <t> seconds
|
|
local function delayed(t, func)
|
|
return function()
|
|
timer.Remove("e2helper_delayed")
|
|
timer.Create("e2helper_delayed", t, 1, func)
|
|
end
|
|
end
|
|
|
|
local function getdesc(name, args)
|
|
return CurrentDescs()[string.format("%s(%s)", name, args)] or CurrentDescs()[name]
|
|
end
|
|
|
|
function E2Helper.Create(reset)
|
|
local x, y, w, h
|
|
|
|
E2Helper.Frame = vgui.Create("DFrame")
|
|
E2Helper.Frame:SetSize(280, 425)
|
|
E2Helper.Frame:Center()
|
|
E2Helper.Frame:SetSizable(true)
|
|
E2Helper.Frame:SetScreenLock(true)
|
|
E2Helper.Frame:SetDeleteOnClose(false)
|
|
E2Helper.Frame:SetVisible(false)
|
|
E2Helper.Frame:SetTitle("E2Helper")
|
|
E2Helper.Frame._PerformLayout = E2Helper.Frame.PerformLayout
|
|
function E2Helper.Frame:PerformLayout(...)
|
|
local w, h = E2Helper.Frame:GetSize()
|
|
if w < 240 then w = 240 end
|
|
if h < 300 then h = 300 end
|
|
E2Helper.Frame:SetSize(w, h)
|
|
|
|
self:_PerformLayout(...)
|
|
E2Helper.Resize()
|
|
end
|
|
|
|
-- holds all the lines describing a constant
|
|
E2Helper.constants = {}
|
|
|
|
E2Helper.DescriptionEntry = vgui.Create("DTextEntry", E2Helper.Frame)
|
|
E2Helper.DescriptionEntry:SetPos(5, 330)
|
|
E2Helper.DescriptionEntry:SetSize(270, 45)
|
|
E2Helper.DescriptionEntry:SetEditable(true)
|
|
E2Helper.DescriptionEntry:SetMultiline(true)
|
|
|
|
E2Helper.ResultFrame = vgui.Create("DListView", E2Helper.Frame)
|
|
E2Helper.ResultFrame:SetPos(5, 60)
|
|
E2Helper.ResultFrame:SetSize(270, 240)
|
|
E2Helper.ResultFrame:SetMultiSelect(false)
|
|
E2Helper.ResultFrame:AddColumn("Function"):SetWidth(126)
|
|
E2Helper.ResultFrame:AddColumn("Takes"):SetWidth(60)
|
|
E2Helper.ReturnsColumn = E2Helper.ResultFrame:AddColumn("Returns")
|
|
E2Helper.ReturnsColumn:SetWidth(60)
|
|
E2Helper.CostColumn = E2Helper.ResultFrame:AddColumn("Cost")
|
|
E2Helper.CostColumn:SetWidth(30)
|
|
|
|
function E2Helper.ResultFrame:OnClickLine(line)
|
|
self:ClearSelection()
|
|
self:SelectItem(line)
|
|
|
|
-- don't try describing the function when it is actually a constant
|
|
if E2Helper.constants[line] then
|
|
E2Helper.FuncEntry:SetText("Constant value")
|
|
|
|
E2Helper.DescriptionEntry:SetText("Constants do not support descriptions (yet)")
|
|
E2Helper.DescriptionEntry:SetTextColor(Color(128, 128, 128))
|
|
else
|
|
E2Helper.FuncEntry:SetText(E2Helper.GetFunctionSyntax(line:GetValue(1), line:GetValue(2), line:GetValue(3)))
|
|
local desc = getdesc(line:GetValue(1), line:GetValue(2))
|
|
if desc then
|
|
E2Helper.DescriptionEntry:SetText(desc)
|
|
E2Helper.DescriptionEntry:SetTextColor(Color(0, 0, 0))
|
|
else
|
|
E2Helper.DescriptionEntry:SetText("No description found :(")
|
|
E2Helper.DescriptionEntry:SetTextColor(Color(128, 128, 128))
|
|
end
|
|
end
|
|
end
|
|
|
|
E2Helper.Image = vgui.Create("DImage", E2Helper.Frame)
|
|
E2Helper.Image:SetPos(5, 75)
|
|
E2Helper.Image:SetImage("expression 2/cog.vtf")
|
|
E2Helper.Image:SetImageColor(Color(255, 0, 0, 8))
|
|
E2Helper.Image:SetSize(225, 225)
|
|
|
|
E2Helper.ResultLabel = vgui.Create("DLabel", E2Helper.Frame)
|
|
E2Helper.ResultLabel:SetPos(5, 405)
|
|
E2Helper.ResultLabel:SetText("")
|
|
E2Helper.ResultLabel:SizeToContents()
|
|
|
|
E2Helper.CredLabel = vgui.Create("DLabel", E2Helper.Frame)
|
|
E2Helper.CredLabel:SetPos(238, 405)
|
|
E2Helper.CredLabel:SetText("By -HP-")
|
|
E2Helper.CredLabel:SizeToContents()
|
|
E2Helper.CredLabel.Resize = { true, true, false, false }
|
|
|
|
E2Helper.NameEntry = vgui.Create("DTextEntry", E2Helper.Frame)
|
|
E2Helper.NameEntry:SetPos(5, 32)
|
|
E2Helper.NameEntry:SetWide(129)
|
|
|
|
E2Helper.ParamEntry = vgui.Create("DTextEntry", E2Helper.Frame)
|
|
E2Helper.ParamEntry:SetPos(136, 32)
|
|
E2Helper.ParamEntry:SetWide(68)
|
|
|
|
E2Helper.ReturnEntry = vgui.Create("DTextEntry", E2Helper.Frame)
|
|
E2Helper.ReturnEntry:SetPos(206, 32)
|
|
E2Helper.ReturnEntry:SetWide(68)
|
|
|
|
E2Helper.Tooltip = vgui.Create("DCheckBoxLabel", E2Helper.Frame)
|
|
E2Helper.Tooltip:SetPos(5, 384)
|
|
E2Helper.Tooltip:SetText("Tooltip")
|
|
E2Helper.Tooltip:SetValue(reset and 0 or cookie.GetNumber("e2helper_tooltip", 0))
|
|
E2Helper.Tooltip:SizeToContents()
|
|
|
|
E2Helper.FuncEntry = vgui.Create("DTextEntry", E2Helper.Frame)
|
|
E2Helper.FuncEntry:SetText("")
|
|
E2Helper.FuncEntry:SetWidth(270)
|
|
E2Helper.FuncEntry:SetPos(5, 305)
|
|
|
|
E2Helper.MaxEntry = vgui.Create("DNumberWang", E2Helper.Frame)
|
|
E2Helper.MaxEntry:SetPos(235, 380)
|
|
E2Helper.MaxEntry:SetWide(40)
|
|
E2Helper.MaxEntry:SetTooltip("E2 is being loaded, please wait...")
|
|
timer.Create("E2Helper.SetMaxEntry", 1, 0, function()
|
|
if e2_function_data_received then
|
|
E2Helper.MaxEntry:SetMax(table.Count(CurrentTable()))
|
|
timer.Remove("E2Helper.SetMaxEntry")
|
|
E2Helper.MaxEntry:SetTooltip(false)
|
|
end
|
|
end)
|
|
E2Helper.MaxEntry:SetValue(reset and 50 or cookie.GetNumber("e2helper_maxresults", 50))
|
|
E2Helper.MaxEntry:SetDecimals(0)
|
|
|
|
E2Helper.MaxLabel = vgui.Create("DLabel", E2Helper.Frame)
|
|
E2Helper.MaxLabel:SetPos(170, 384)
|
|
E2Helper.MaxLabel:SetText("Max results:")
|
|
E2Helper.MaxLabel:SizeToContents()
|
|
|
|
E2Helper.E2Mode = vgui.Create("DCheckBoxLabel", E2Helper.Frame)
|
|
E2Helper.E2Mode:SetPos(90, 384)
|
|
E2Helper.E2Mode:SetText("E2")
|
|
E2Helper.E2Mode:SetValue(true)
|
|
E2Helper.E2Mode:SizeToContents()
|
|
function E2Helper.E2Mode.Button:Toggle()
|
|
self:SetValue(true)
|
|
E2Helper.CurrentMode = true
|
|
E2Helper.CPUMode:SetValue(false)
|
|
E2Helper.CostColumn:SetName("Cost")
|
|
E2Helper.ReturnsColumn:SetName("Returns")
|
|
E2Helper.Update()
|
|
end
|
|
|
|
E2Helper.CPUMode = vgui.Create("DCheckBoxLabel", E2Helper.Frame)
|
|
E2Helper.CPUMode:SetPos(90, 404)
|
|
E2Helper.CPUMode:SetText("CPU/GPU")
|
|
E2Helper.CPUMode:SetValue(false)
|
|
E2Helper.CPUMode:SizeToContents()
|
|
function E2Helper.CPUMode.Button:Toggle()
|
|
self:SetValue(true)
|
|
E2Helper.CurrentMode = false
|
|
E2Helper.E2Mode:SetValue(false)
|
|
E2Helper.CostColumn:SetName("Opcode")
|
|
E2Helper.ReturnsColumn:SetName("Platform")
|
|
E2Helper.Update()
|
|
end
|
|
|
|
E2Helper.NameEntry.OnTextChanged = delayed(0.1, E2Helper.Update)
|
|
E2Helper.ParamEntry.OnTextChanged = delayed(0.1, E2Helper.Update)
|
|
E2Helper.ReturnEntry.OnTextChanged = delayed(0.1, E2Helper.Update)
|
|
E2Helper.Tooltip.OnChange = E2Helper.Update
|
|
E2Helper.MaxEntry.OnValueChanged = delayed(1, cookie_update)
|
|
|
|
local x, y, w, h
|
|
E2Helper.Originals = {}
|
|
for k, v in pairs(E2Helper) do
|
|
if type(v) == "Panel" then
|
|
x, y = v:GetPos()
|
|
w, h = v:GetSize()
|
|
E2Helper.Originals[k] = { x, y, w, h }
|
|
end
|
|
end
|
|
|
|
if not reset then
|
|
E2Helper.Frame:SetSize(cookie.GetNumber("e2helper_w", 280), cookie.GetNumber("e2helper_h", 425))
|
|
else
|
|
cookie_update()
|
|
end
|
|
E2Helper.Resize()
|
|
end
|
|
|
|
function E2Helper.GetFunctionSyntax(func, args, rets)
|
|
if E2Helper.CurrentMode == true then
|
|
local signature = func .. "(" .. args .. ")"
|
|
local ret = E2Lib.generate_signature(signature, rets, wire_expression2_funcs[signature].argnames)
|
|
if rets ~= "" then ret = ret:sub(1, 1):upper() .. ret:sub(2) end
|
|
return ret
|
|
else
|
|
--local args = string.gsub(args, "(%a)", "%1,", string.len( args ) - 1) -- this gsub puts a comma in between each letter
|
|
return func .. " " .. args
|
|
end
|
|
end
|
|
|
|
function E2Helper.Update()
|
|
|
|
cookie_update()
|
|
|
|
E2Helper.ResultFrame:Clear()
|
|
|
|
local search_name, search_args, search_rets = E2Helper.NameEntry:GetValue():lower(), E2Helper.ParamEntry:GetValue():lower(), E2Helper.ReturnEntry:GetValue():lower()
|
|
local count = 0
|
|
local maxcount = E2Helper.MaxEntry:GetValue()
|
|
local tooltip = E2Helper.Tooltip:GetChecked(true)
|
|
|
|
-- add E2 constants
|
|
E2Helper.constants = {}
|
|
if E2Helper.CurrentMode == true then
|
|
for k, v in pairs(wire_expression2_constants) do
|
|
-- set the type according to the functions
|
|
local strType = E2Lib.guess_type(v)
|
|
|
|
-- constants have no arguments and no cost
|
|
local name, args, rets, cost = k, nil, strType, nil
|
|
if name:lower():find(search_name, 1, true) and search_args == "" and rets:lower():find(search_rets, 1, true) then
|
|
local line = E2Helper.ResultFrame:AddLine(name, args, rets, cost, "constant")
|
|
E2Helper.constants[line] = true
|
|
count = count + 1
|
|
if count >= maxcount then break end
|
|
end
|
|
end
|
|
end
|
|
|
|
if count < maxcount then
|
|
for _, v in pairs(CurrentTable()) do
|
|
if E2Helper.CurrentMode == true then
|
|
local argnames, signature, rets, func, cost = v.argnames, unpack(v)
|
|
local name, args = string.match(signature, "^([^(]+)%(([^)]*)%)$")
|
|
|
|
if signature:sub(1, 3) ~= "op:" and
|
|
name:lower():find(search_name, 1, true) and
|
|
args:lower():find(search_args, 1, true) and
|
|
rets:lower():find(search_rets, 1, true) then
|
|
local line = E2Helper.ResultFrame:AddLine(name, args, rets, cost or 20)
|
|
if tooltip then line:SetTooltip(E2Helper.GetFunctionSyntax(name, args, rets)) end
|
|
count = count + 1
|
|
if count >= maxcount then break end
|
|
end
|
|
else
|
|
local funcname, args, forwhat, functype = unpack(v)
|
|
if (funcname:lower():find(search_name, 1, true) and
|
|
args:lower():find(search_args, 1, true) and
|
|
forwhat:lower():find(search_rets, 1, true)) then
|
|
local line = E2Helper.ResultFrame:AddLine(funcname, args, forwhat, functype)
|
|
if tooltip then line:SetTooltip(funcname .. " " .. args) end
|
|
count = count + 1
|
|
if count >= maxcount then break end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
E2Helper.ResultFrame:SortByColumn(1)
|
|
E2Helper.ResultLabel:SetText(count .. " results")
|
|
E2Helper.ResultLabel:SizeToContents()
|
|
end
|
|
|
|
function E2Helper.Show(searchtext)
|
|
if not E2Helper.Frame then E2Helper.Create(false) end
|
|
E2Helper.Frame:MakePopup()
|
|
E2Helper.Frame:SetVisible(true)
|
|
if searchtext and searchtext ~= E2Helper.NameEntry:GetValue() then
|
|
E2Helper.NameEntry:SetValue(searchtext)
|
|
E2Helper.Update()
|
|
E2Helper.FuncEntry:SetValue("")
|
|
E2Helper.DescriptionEntry:SetValue("")
|
|
else
|
|
E2Helper.NameEntry:RequestFocus()
|
|
end
|
|
end
|
|
|
|
function E2Helper.UseE2(nEditorType)
|
|
E2Helper.CurrentMode = false
|
|
E2Helper.E2Mode:Toggle()
|
|
local val = E2Helper.ReturnEntry:GetValue()
|
|
if val and (val == "CPU" or val == "GPU") then E2Helper.ReturnEntry:SetText("") end
|
|
E2Helper.CostColumn:SetName("Cost")
|
|
E2Helper.ReturnsColumn:SetName("Returns")
|
|
end
|
|
|
|
function E2Helper.UseCPU(nEditorType)
|
|
E2Helper.CurrentMode = true
|
|
E2Helper.CPUMode:Toggle()
|
|
E2Helper.CostColumn:SetName("Type")
|
|
E2Helper.ReturnsColumn:SetName("For What")
|
|
E2Helper.ReturnEntry:SetText(nEditorType)
|
|
end
|
|
|
|
local delayed_cookie_update = delayed(1, cookie_update)
|
|
|
|
local lastw, lasth
|
|
function E2Helper.Resize()
|
|
local w, h = E2Helper.Frame:GetSize()
|
|
if w == lastw and h == lasth then return end
|
|
|
|
local orig = E2Helper.Originals
|
|
local changew, changeh = w - orig.Frame[3], h - orig.Frame[4]
|
|
|
|
-- Epically messy code:
|
|
E2Helper.CredLabel:SetPos(orig.CredLabel[1] + changew, orig.CredLabel[2] + changeh)
|
|
E2Helper.MaxLabel:SetPos(orig.MaxLabel[1] + changew, orig.MaxLabel[2] + changeh)
|
|
E2Helper.MaxEntry:SetPos(orig.MaxEntry[1] + changew, orig.MaxEntry[2] + changeh)
|
|
E2Helper.ResultLabel:SetPos(orig.ResultLabel[1], orig.ResultLabel[2] + changeh)
|
|
E2Helper.Tooltip:SetPos(orig.Tooltip[1], orig.Tooltip[2] + changeh)
|
|
E2Helper.FuncEntry:SetPos(orig.FuncEntry[1], orig.FuncEntry[2] + changeh)
|
|
E2Helper.FuncEntry:SetSize(orig.FuncEntry[3] + changew, orig.FuncEntry[4])
|
|
E2Helper.DescriptionEntry:SetPos(orig.DescriptionEntry[1], orig.DescriptionEntry[2] + changeh)
|
|
E2Helper.DescriptionEntry:SetSize(orig.DescriptionEntry[3] + changew, orig.DescriptionEntry[4])
|
|
E2Helper.ResultFrame:SetSize(orig.ResultFrame[3] + changew, orig.ResultFrame[4] + changeh)
|
|
E2Helper.E2Mode:SetPos(orig.E2Mode[1], orig.E2Mode[2] + changeh)
|
|
E2Helper.CPUMode:SetPos(orig.CPUMode[1], orig.CPUMode[2] + changeh)
|
|
|
|
E2Helper.NameEntry:SetSize(orig.NameEntry[3] + changew * 0.5, orig.NameEntry[4])
|
|
E2Helper.ParamEntry:SetPos(orig.ParamEntry[1] + changew * 0.5, orig.ParamEntry[2])
|
|
E2Helper.ParamEntry:SetSize(orig.ParamEntry[3] + changew * 0.25, orig.ParamEntry[4])
|
|
E2Helper.ReturnEntry:SetPos(orig.ReturnEntry[1] + changew * 0.75, orig.ReturnEntry[2])
|
|
E2Helper.ReturnEntry:SetSize(orig.ReturnEntry[3] + changew * 0.25, orig.ReturnEntry[4])
|
|
|
|
-- Keep the (funky) image overlay centered on the listview
|
|
local w1, h1 = E2Helper.ResultFrame:GetSize()
|
|
local x1, y1 = E2Helper.ResultFrame:GetPos()
|
|
|
|
-- add borders of mysterious dimensions
|
|
x1 = x1 + 15
|
|
w1 = w1 - 30
|
|
y1 = y1 + 30
|
|
h1 = h1 - 45
|
|
|
|
-- fix aspect ratio
|
|
if w1 > h1 then
|
|
x1 = x1 + (w1 - h1) / 2
|
|
w1 = h1
|
|
else
|
|
y1 = y1 + (h1 - w1) / 2
|
|
h1 = w1
|
|
end
|
|
|
|
-- apply position and size
|
|
E2Helper.Image:SetPos(x1, y1)
|
|
E2Helper.Image:SetSize(w1, h1)
|
|
|
|
delayed_cookie_update()
|
|
|
|
lastw, lasth = w, h
|
|
end
|
|
|
|
concommand.Add("e2helper", function() E2Helper.Show() end)
|
|
concommand.Add("e2helper_reset", function()
|
|
if E2Helper.Frame then
|
|
E2Helper.Frame:SetDeleteOnClose(true)
|
|
E2Helper.Frame:Close()
|
|
end
|
|
E2Helper.Create(true)
|
|
cookie_update()
|
|
end)
|
|
|
|
local PrevCtrlQ
|
|
hook.Add("Think", "E2Helper_KeyListener", function()
|
|
if not E2Helper.Frame then return end
|
|
local CtrlQ = input.IsKeyDown(KEY_Q) and (input.IsKeyDown(KEY_LCONTROL) or input.IsKeyDown(KEY_RCONTROL))
|
|
if CtrlQ and not PrevCtrlQ and E2Helper.Frame:IsActive() then
|
|
E2Helper.Frame:SetVisible(false)
|
|
end
|
|
PrevCtrlQ = CtrlQ
|
|
end)
|