1764 lines
50 KiB
Lua
Executable File
1764 lines
50 KiB
Lua
Executable File
local DEBUG_INACTIVE = 1 -- debug is inactive, hooks are not set
|
|
local DEBUG_ACTIVE = 2 -- debug should be active and running, until we found a breakpoint or the program ends
|
|
local DEBUG_STOPPED = 3 -- debug should be active and running, we are waiting to stop in the next opportunity, we have to abort
|
|
local DEBUG_STEP_INTO = 4 -- debug should be active and running, we are waiting until its steps into the function to pause, or we found a breakpoint
|
|
local DEBUG_STEP_OVER = 5 -- debug should be active and running, we are waiting until its steps over the function to pause, or we found a breakpoint
|
|
local DEBUG_STEP_OUT = 6 -- debug should be active and running, we are waiting until its steps out of the function to pause, or we found a breakpoint
|
|
local DEBUG_PAUSED = 7 -- debug should be active, but paused
|
|
local DEBUG_ERRORPAUSED = 8 -- debug should be active, but paused in an error
|
|
|
|
local FUNC_STATE_INSIDE = 1
|
|
local FUNC_STATE_OUTSIDE = 2
|
|
|
|
local debugger = {
|
|
debugState = DEBUG_INACTIVE,
|
|
|
|
currentFuncLevel = 0,
|
|
stepFuncLevel = 0,
|
|
stepFuncState = 0,
|
|
|
|
startFile = nil,
|
|
currentLine = nil,
|
|
currentFile = nil,
|
|
|
|
breakpoints = {},
|
|
|
|
main_dialog = nil,
|
|
panel_tabs = nil,
|
|
multitext_tabs = nil,
|
|
console_pos = 0,
|
|
debug_pos = 0,
|
|
}
|
|
|
|
function iup.DebuggerInit(panelTabs, multitextTabs)
|
|
debugger.main_dialog = iup.GetDialog(panelTabs)
|
|
debugger.multitext_tabs = multitextTabs
|
|
debugger.panel_tabs = panelTabs
|
|
debugger.console_pos = panelTabs.count - 4
|
|
debugger.debug_pos = panelTabs.count - 2
|
|
|
|
debugger.panel_tabs.valuepos = debugger.console_pos -- show console tab
|
|
end
|
|
|
|
function iup.DebuggerShowConsoleTab()
|
|
debugger.panel_tabs.valuepos = debugger.console_pos -- show console tab
|
|
end
|
|
|
|
function iup.DebuggerShowDebugTab()
|
|
debugger.panel_tabs.valuepos = debugger.debug_pos -- show debug tab
|
|
end
|
|
|
|
function iup.DebuggerGetCurrentMultitext()
|
|
return debugger.multitext_tabs.value_handle
|
|
end
|
|
|
|
----------- IupScintillaDlg Usage ---------------------
|
|
|
|
function iup.DebuggerNewFile()
|
|
debugger.main_dialog.newfile = nil
|
|
end
|
|
|
|
function iup.DebuggerOpenFile(filename)
|
|
debugger.main_dialog.openfile = filename
|
|
end
|
|
|
|
function iup.DebuggerForceCloseFile(pos)
|
|
debugger.main_dialog.forceclosefile = pos
|
|
end
|
|
|
|
function iup.DebuggerUpdateTitle()
|
|
debugger.main_dialog.updatetitle = "Yes"
|
|
end
|
|
|
|
function iup.DebuggerSaveFile()
|
|
debugger.main_dialog.savefile = nil
|
|
end
|
|
|
|
function iup.DebuggerToggleMarker(lin)
|
|
debugger.main_dialog["togglemarker"..lin] = 2 -- margin=2
|
|
end
|
|
|
|
-----------------------------------------__________----
|
|
|
|
function iup.DebuggerFindMultitext(filename)
|
|
local multitext = iup.GetChild(debugger.multitext_tabs, 0)
|
|
while multitext do
|
|
if multitext.filename == filename then
|
|
return multitext
|
|
end
|
|
|
|
multitext = iup.GetBrother(multitext)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerRestoreBreakpoints(multitext, m_filename)
|
|
local list_break = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_BREAK")
|
|
|
|
local index = 1
|
|
local filename = list_break["FILENAME" .. index]
|
|
while filename do
|
|
if filename == m_filename then
|
|
local line = tonumber(list_break["LINE" .. index])
|
|
multitext["MARKERADD".. (line - 1)] = 1 -- (margin=1)
|
|
end
|
|
|
|
index = index + 1
|
|
filename = list_break["FILENAME" .. index]
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerOpenMultitext(filename, source)
|
|
local old_count = tonumber(debugger.multitext_tabs.count)
|
|
|
|
local s = string.sub(filename, 1, 6)
|
|
if s == "string" then
|
|
iup.DebuggerNewFile()
|
|
else
|
|
iup.DebuggerOpenFile(filename)
|
|
end
|
|
|
|
local count = tonumber(debugger.multitext_tabs.count)
|
|
if count > old_count then
|
|
local multitext = iup.GetChild(debugger.multitext_tabs, old_count)
|
|
|
|
if s == "string" then
|
|
multitext.filename = filename
|
|
multitext.value = source
|
|
multitext.temporary = "Yes"
|
|
|
|
iup.DebuggerRestoreBreakpoints(multitext, filename)
|
|
end
|
|
|
|
if iup.DebuggerIsActive() then
|
|
multitext.readonly = "Yes"
|
|
end
|
|
|
|
return multitext
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerCloseTemporary()
|
|
local multitext = iup.GetChild(debugger.multitext_tabs, 0)
|
|
local pos = 0
|
|
while multitext do
|
|
if multitext.temporary == "Yes" then
|
|
local temp = multitext
|
|
multitext = iup.GetBrother(multitext)
|
|
|
|
iup.DebuggerForceCloseFile(pos)
|
|
else
|
|
multitext = iup.GetBrother(multitext)
|
|
pos = pos + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerSetAttribAllMultitext(name, value)
|
|
local multitext = iup.GetChild(debugger.multitext_tabs, 0)
|
|
while multitext do
|
|
multitext[name] = value
|
|
multitext = iup.GetBrother(multitext)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerSetDialogChildAttrib(child_name, name, value)
|
|
iup.SetAttribute(iup.GetDialogChild(debugger.main_dialog, child_name), name, value)
|
|
end
|
|
|
|
local function setparent_param_cb(param_dialog, param_index)
|
|
if param_index == iup.GETPARAM_MAP then
|
|
param_dialog.parentdialog = debugger.main_dialog
|
|
end
|
|
|
|
return 1
|
|
end
|
|
|
|
|
|
------------------------------------- User Interface State -------------------------------------
|
|
|
|
|
|
function iup.DebuggerSetStateString(state)
|
|
local map_state = { -- only the ones used in C
|
|
DEBUG_ACTIVE = DEBUG_ACTIVE,
|
|
DEBUG_STOPPED = DEBUG_STOPPED,
|
|
DEBUG_STEP_INTO = DEBUG_STEP_INTO,
|
|
DEBUG_STEP_OVER = DEBUG_STEP_OVER,
|
|
DEBUG_STEP_OUT = DEBUG_STEP_OUT,
|
|
DEBUG_PAUSED = DEBUG_PAUSED,
|
|
}
|
|
|
|
iup.DebuggerSetState(map_state[state])
|
|
end
|
|
|
|
function iup.DebuggerIsActive()
|
|
if debugger.debugState ~= DEBUG_INACTIVE then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerSetState(st)
|
|
local stop, step, pause, run, dbg, curline
|
|
|
|
if debugger.debugState == st then
|
|
return
|
|
end
|
|
|
|
iup.DebuggerSetAttribAllMultitext("READONLY", "Yes")
|
|
|
|
if st == DEBUG_STOPPED then
|
|
|
|
stop = "NO"
|
|
step = "NO"
|
|
run = "NO"
|
|
pause = "NO"
|
|
dbg = "NO"
|
|
curline = "NO"
|
|
elseif st == DEBUG_ACTIVE or st == DEBUG_STEP_INTO or st == DEBUG_STEP_OVER or st == DEBUG_STEP_OUT then
|
|
stop = "YES"
|
|
step = "NO"
|
|
run = "NO"
|
|
pause = "YES"
|
|
dbg = "NO"
|
|
curline = "NO"
|
|
|
|
if st == DEBUG_STEP_OUT then
|
|
debugger.stepFuncLevel = debugger.currentFuncLevel
|
|
debugger.stepFuncState = FUNC_STATE_INSIDE
|
|
else
|
|
debugger.stepFuncLevel = 0
|
|
debugger.stepFuncState = FUNC_STATE_OUTSIDE
|
|
end
|
|
elseif st == DEBUG_PAUSED then
|
|
stop = "YES"
|
|
step = "YES"
|
|
run = "NO"
|
|
pause = "NO"
|
|
dbg = "YES"
|
|
curline = "Yes"
|
|
elseif st == DEBUG_ERRORPAUSED then
|
|
stop = "YES"
|
|
step = "NO"
|
|
run = "NO"
|
|
pause = "NO"
|
|
dbg = "NO"
|
|
curline = "Yes"
|
|
else -- st == DEBUG_INACTIVE
|
|
stop = "NO"
|
|
step = "NO"
|
|
run = "YES"
|
|
pause = "NO"
|
|
dbg = "YES"
|
|
curline = "NO"
|
|
|
|
iup.DebuggerSetAttribAllMultitext("READONLY", "No")
|
|
|
|
iup.DebuggerClearLocalVariablesTree()
|
|
iup.DebuggerClearStackList()
|
|
iup.DebuggerInitGlobalsTree()
|
|
end
|
|
|
|
debugger.debugState = st
|
|
|
|
iup.DebuggerSetAttribAllMultitext("MARKERDELETEALL", "2") -- clear all line highlight (margin=2)
|
|
iup.DebuggerSetAttribAllMultitext("MARKERDELETEALL", "3") -- clear all line arrow (margin=3)
|
|
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_RUN", "ACTIVE", run)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_STOP", "ACTIVE", stop)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_PAUSE", "ACTIVE", pause)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_DEBUG", "ACTIVE", dbg)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_STEPINTO", "ACTIVE", step)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_STEPOVER", "ACTIVE", step)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_STEPOUT", "ACTIVE", step)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_ITM_CURRENTLINE", "ACTIVE", curline)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_RUN", "ACTIVE", run)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_STOP", "ACTIVE", stop)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_PAUSE", "ACTIVE", pause)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_DEBUG", "ACTIVE", dbg)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_STEPINTO", "ACTIVE", step)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_STEPOVER", "ACTIVE", step)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_STEPOUT", "ACTIVE", step)
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_BTN_CURRENTLINE", "ACTIVE", curline)
|
|
end
|
|
|
|
function iup.DebuggerHighlightLine(filename, line, source)
|
|
if line == nil or line <= 0 then
|
|
return
|
|
end
|
|
|
|
debugger.currentLine = line
|
|
debugger.currentFile = filename
|
|
|
|
local multitext = iup.DebuggerGetMultitext(filename, true, true, source) -- find and open if necessary
|
|
if not multitext then
|
|
return
|
|
end
|
|
|
|
local pos = iup.TextConvertLinColToPos(multitext, line-1, 0) -- line here starts at 0
|
|
multitext.caretpos = pos
|
|
|
|
-- highlight
|
|
multitext["MARKERADD"..(line-1)] = 2 -- (margin=2)
|
|
-- arrow
|
|
multitext["MARKERADD"..(line-1)] = 3 -- (margin=3)
|
|
end
|
|
|
|
function iup.DebuggerShowCurrentLine()
|
|
if debugger.currentLine and debugger.currentFile then
|
|
iup.DebuggerSelectLine(debugger.currentFile, debugger.currentLine, true) -- find
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerGetMultitext(filename, find, open, source)
|
|
local multitext = iup.DebuggerGetCurrentMultitext()
|
|
|
|
if filename ~= multitext.filename then
|
|
if find then
|
|
multitext = iup.DebuggerFindMultitext(filename)
|
|
if open then
|
|
debugger.multitext_tabs.value = multitext
|
|
iup.DebuggerUpdateTitle()
|
|
|
|
if not multitext then
|
|
multitext = iup.DebuggerOpenMultitext(filename, source)
|
|
if not multitext then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
else
|
|
return
|
|
end
|
|
end
|
|
|
|
return multitext
|
|
end
|
|
|
|
function iup.DebuggerSelectLine(filename, line, find, source)
|
|
if line == nil or line <= 0 then
|
|
return
|
|
end
|
|
|
|
local multitext = iup.DebuggerGetMultitext(filename, find, true, source) -- find and always open if necessary
|
|
if not multitext then
|
|
return
|
|
end
|
|
|
|
local pos = iup.TextConvertLinColToPos(multitext, line-1, 0) -- line here starts at 0
|
|
multitext.caretpos = pos
|
|
|
|
-- select
|
|
multitext.selection = line-1 .. ",0:" .. line-1 .. ",9999"
|
|
end
|
|
|
|
|
|
------------------------------------- Breakpoints -------------------------------------
|
|
|
|
function iup.DebuggerHasBreakpoint(filename, line)
|
|
local file_breaks = debugger.breakpoints[filename]
|
|
if file_breaks and file_breaks[line] then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function iup.DebuggerRestoreLastListValue(list, last_value)
|
|
-- maintain visual position of the selection on the list, not necessarily the same item
|
|
last_value = tonumber(last_value)
|
|
local count = tonumber(list.count)
|
|
if last_value > count then
|
|
list.value = count
|
|
else
|
|
list.value = last_value
|
|
end
|
|
end
|
|
|
|
function table.count(t)
|
|
local count = 0
|
|
for i, v in pairs(t) do
|
|
count = count + 1
|
|
end
|
|
return count
|
|
end
|
|
|
|
function iup.DebuggerUpdateBreakpointsListLines(list_break, m_filename, m_line, new_line)
|
|
local count = tonumber(list_break.count)
|
|
for i = 1, count do
|
|
local filename = list_break["FILENAME" .. i]
|
|
local line = tonumber(list_break["LINE" .. i])
|
|
|
|
if m_filename == filename and m_line == line then
|
|
-- update list (just title, index remains the same)
|
|
list_break[i] = "Line " .. new_line .. " of \"" .. filename .. "\""
|
|
|
|
-- update FILENAME#LINE
|
|
list_break["LINE" .. i] = new_line
|
|
end
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerRemoveBreakpointsListItem(list_break, m_filename, m_line)
|
|
local count = tonumber(list_break.count)
|
|
for i = 1, count do
|
|
local filename = list_break["FILENAME" .. i]
|
|
local line = tonumber(list_break["LINE" .. i])
|
|
|
|
if m_filename == filename and m_line == line then
|
|
iup.DebuggerRemoveBreakpointsListIndex(list_break, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerRemoveBreakpointsListIndex(list_break, index)
|
|
-- update list
|
|
list_break.removeitem = index
|
|
local count = tonumber(list_break.count)
|
|
|
|
-- update FILENAME#LINE
|
|
for i = index, count do
|
|
list_break["FILENAME"..i] = list_break["FILENAME"..(i+1)]
|
|
list_break["LINE"..i] = list_break["LINE"..(i+1)]
|
|
end
|
|
list_break["FILENAME" .. count+1] = nil
|
|
list_break["LINE" .. count+1] = nil
|
|
end
|
|
|
|
function iup.DebuggerRemoveBreakpoint(list_break, index)
|
|
local last_value = list_break.value
|
|
local line = tonumber(list_break["LINE" .. index])
|
|
local filename = list_break["FILENAME" .. index]
|
|
local count = tonumber(list_break.count)
|
|
|
|
-- update multitext
|
|
local multitext = iup.DebuggerGetMultitext(filename, true, false) -- find but do NOT open if not found
|
|
if multitext then
|
|
multitext["MARKERDELETE" .. (line - 1)] = 1 -- margin=1
|
|
end
|
|
|
|
-- update breakpoints table
|
|
local file_breaks = debugger.breakpoints[filename]
|
|
if file_breaks then
|
|
file_breaks[line] = nil
|
|
if table.count(file_breaks) == 0 then
|
|
debugger.breakpoints[filename] = nil
|
|
end
|
|
end
|
|
|
|
-- update list and FILENAME#LINE
|
|
iup.DebuggerRemoveBreakpointsListIndex(list_break, index)
|
|
|
|
if count == 1 then
|
|
-- update buttons, it is now empty
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_BREAK", "ACTIVE", "NO")
|
|
else
|
|
iup.DebuggerRestoreLastListValue(list_break, last_value)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerAddBreakpoint(list_break, filename, line)
|
|
local last_value = list_break.value
|
|
|
|
-- update multitext
|
|
local multitext = iup.DebuggerGetMultitext(filename, true, false) -- find but do NOT open if not found
|
|
if multitext then
|
|
multitext["MARKERADD" .. (line - 1)] = 1 -- margin=1
|
|
end
|
|
|
|
-- update breakpoints table
|
|
local file_breaks = debugger.breakpoints[filename]
|
|
if not file_breaks then
|
|
file_breaks = {}
|
|
debugger.breakpoints[filename] = file_breaks
|
|
end
|
|
file_breaks[line] = { } -- other breakpoint info can be saved here
|
|
|
|
-- update list
|
|
list_break.appenditem = "Line " .. line .. " of \"" .. filename .. "\""
|
|
local count = tonumber(list_break.count)
|
|
|
|
-- update FILENAME#LINE
|
|
list_break["FILENAME"..count] = filename
|
|
list_break["LINE"..count] = line
|
|
|
|
if count == 1 then
|
|
-- update buttons, it was empty
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_BREAK", "ACTIVE", "Yes")
|
|
end
|
|
|
|
-- select the new item
|
|
list_break.value = count
|
|
end
|
|
|
|
function table_compare_lines(elem1, elem2)
|
|
if (elem1.line < elem2.line) then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerBreakpointsChanged(multitext, start_lin, num_lin)
|
|
local filename = multitext.filename
|
|
local list_break = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_BREAK")
|
|
local last_value = list_break.value
|
|
|
|
local file_breaks = debugger.breakpoints[filename]
|
|
if not file_breaks then
|
|
return
|
|
end
|
|
|
|
local new_file_breaks = {}
|
|
|
|
for line, bp in pairs(file_breaks) do
|
|
if line >= start_lin then
|
|
if num_lin < 0 and line < start_lin - num_lin then
|
|
-- removed lines and removed breakpoint
|
|
|
|
-- update multitext
|
|
multitext["MARKERDELETE" .. (start_lin - 1)] = 1 -- margin=1 -- all breakpoints inside the region are collapsed to the start_lin
|
|
|
|
-- update breakpoints table
|
|
-- simply don't copy to new_file_breaks
|
|
|
|
-- update list and FILENAME#LINE
|
|
iup.DebuggerRemoveBreakpointsListItem(list_break, filename, line)
|
|
else
|
|
-- added or removed lines, just change line in breakpoints
|
|
|
|
-- update breakpoints table
|
|
-- copy breakpoint at the new position
|
|
new_file_breaks[line + num_lin] = bp
|
|
|
|
-- update list and FILENAME#LINE
|
|
iup.DebuggerUpdateBreakpointsListLines(list_break, filename, line, line + num_lin)
|
|
end
|
|
else
|
|
-- no changes, just copy
|
|
new_file_breaks[line] = bp
|
|
end
|
|
end
|
|
|
|
-- update breakpoints table
|
|
if table.count(new_file_breaks) == 0 then
|
|
debugger.breakpoints[filename] = nil
|
|
else
|
|
debugger.breakpoints[filename] = new_file_breaks
|
|
end
|
|
|
|
local count = tonumber(list_break.count)
|
|
if count == 0 then
|
|
-- update buttons, it is now empty
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_BREAK", "ACTIVE", "NO")
|
|
else
|
|
iup.DebuggerRestoreLastListValue(list_break, last_value)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerRemoveAllBreakpoints()
|
|
local list_break = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_BREAK")
|
|
|
|
-- update all multitext
|
|
iup.DebuggerSetAttribAllMultitext("MARKERDELETEALL", "1") -- margin=1
|
|
|
|
-- update list
|
|
list_break.removeitem = "ALL"
|
|
|
|
-- update breakpoints table
|
|
debugger.breakpoints = {}
|
|
|
|
-- update FILENAME#LINE
|
|
local index = 1
|
|
local filename = list_break["FILENAME" .. index]
|
|
while filename do
|
|
list_break["FILENAME" .. index] = nil
|
|
list_break["LINE" .. index] = nil
|
|
|
|
index = index + 1
|
|
filename = list_break["FILENAME" .. index]
|
|
end
|
|
|
|
-- update buttons
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_BREAK", "ACTIVE", "NO")
|
|
end
|
|
|
|
function iup.DebuggerInitBreakpointsList(list_break)
|
|
-- From FILENAME#LINE, initialize list and breakpoints table
|
|
-- each multitext will be updated when created/loaded, see restoremarkers_cb
|
|
|
|
list_break.removeitem = "ALL"
|
|
debugger.breakpoints = {}
|
|
|
|
local index = 1
|
|
local filename = list_break["FILENAME" .. index]
|
|
while filename do
|
|
local line = tonumber(list_break["LINE" .. index])
|
|
|
|
-- update list
|
|
list_break[index] = "Line " .. line .. " of \"" .. filename .. "\""
|
|
|
|
-- update breakpoints table
|
|
local file_breaks = debugger.breakpoints[filename]
|
|
if not file_breaks then
|
|
file_breaks = {}
|
|
debugger.breakpoints[filename] = file_breaks
|
|
end
|
|
file_breaks[line] = { } -- other breakpoint info can be saved here
|
|
|
|
index = index + 1
|
|
filename = list_break["FILENAME" .. index]
|
|
end
|
|
|
|
-- update buttons
|
|
if index > 1 then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_BREAK", "ACTIVE", "Yes")
|
|
|
|
list_break.value = 1 -- select first item on list
|
|
else
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_BREAK", "ACTIVE", "NO")
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerAddBreakpointList()
|
|
local multitext = iup.DebuggerGetCurrentMultitext()
|
|
local suggest_filename = multitext.filename
|
|
if (not suggest_filename) then suggest_filename = "" end
|
|
local suggest_lin, suggest_col = iup.TextConvertPosToLinCol(multitext, multitext.caretpos)
|
|
|
|
local status, filename, line = iup.GetParam("Add Breakpoint", setparent_param_cb, "Filename: %s\nLine: %i[1,]\n", suggest_filename, suggest_lin + 1)
|
|
|
|
if (status) then
|
|
local list_break = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_BREAK")
|
|
|
|
if iup.DebuggerHasBreakpoint(filename, line) then
|
|
iup.MessageError(debugger.main_dialog, "Breakpoint already exists.")
|
|
return
|
|
end
|
|
|
|
iup.DebuggerAddBreakpoint(list_break, filename, line)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerBreaksListAction(list_break, index)
|
|
local filename = list_break["FILENAME" .. index]
|
|
local line = tonumber(list_break["LINE" .. index])
|
|
|
|
iup.DebuggerSelectLine(filename, line, false) -- do not find
|
|
end
|
|
|
|
function iup.DebuggerBreaksListActivate(list_break, index)
|
|
local filename = list_break["FILENAME" .. index]
|
|
local line = tonumber(list_break["LINE" .. index])
|
|
|
|
iup.DebuggerSelectLine(filename, line, true) -- find
|
|
end
|
|
|
|
|
|
------------------------------------- Locals -------------------------------------
|
|
|
|
|
|
function iup.DebuggerClearLocalVariablesTree()
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_LOCAL", "ACTIVE", "NO")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_LOCAL", "ACTIVE", "NO")
|
|
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_TREE_LOCAL", "DELNODE", "ALL")
|
|
end
|
|
|
|
function iup.DebuggerSetLocalVariable()
|
|
local tree_local = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_LOCAL")
|
|
local id = tree_local.value
|
|
if (not id or tonumber(id) < 0) then
|
|
iup.MessageError(debugger.main_dialog, "Select a variable on the list.")
|
|
return
|
|
end
|
|
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
|
|
local name = userdata.name
|
|
local value = userdata.value
|
|
|
|
if (value == nil) then value = "nil" end
|
|
local valueType = type(value)
|
|
if valueType ~= "string" and valueType ~= "number" and valueType ~= "boolean" then
|
|
iup.MessageError(debugger.main_dialog, "Can edit only strings, numbers and booleans.")
|
|
return
|
|
end
|
|
|
|
local status, newValue = iup.GetParam("Set Local", setparent_param_cb, name.." = ".."%s{true, false and nil are translated to Lua values.}\n", tostring(value))
|
|
|
|
if (status) then
|
|
local bol = string.lower(newValue)
|
|
if bol == "true" then
|
|
newValue = true
|
|
elseif bol == "false" then
|
|
newValue = false
|
|
elseif bol == "nil" then
|
|
newValue = nil
|
|
else
|
|
local num = tonumber(newValue)
|
|
if num then
|
|
newValue = num
|
|
end
|
|
end
|
|
|
|
local list_stack = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_STACK")
|
|
local index = tonumber(list_stack.value)
|
|
|
|
-- here there are 4 levels on top of the stack:
|
|
-- 1-DebuggerSetLocalVariable,
|
|
-- 2-LoopStep
|
|
-- 3-DebuggerLineHook,
|
|
-- 4-DebuggerHookFunction
|
|
local startLevel = 5
|
|
local level = index - 1 + startLevel -- this is the level of the function
|
|
|
|
iup.DebuggerSetLocalValue(tree_local, level, id, newValue)
|
|
iup.DebuggerSetLocalTreeItem(tree_local, id, name, newValue)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerPrintLocalVariable()
|
|
local tree_local = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_LOCAL")
|
|
local id = tree_local.value
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
local pos = userdata.pos
|
|
local value = userdata.value
|
|
|
|
iup.ConsolePrint(tree_local["TITLE"..id] .. " (pos="..pos..")")
|
|
iup.ConsolePrintValue(value)
|
|
end
|
|
|
|
function iup.DebuggerPrintAllLocalVariables()
|
|
local tree_local = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_LOCAL")
|
|
local count = tonumber(tree_local.rootcount) -- print all at root only
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
local id = 0
|
|
for i = 0, count-1 do
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
local pos = userdata.pos
|
|
local value = userdata.value
|
|
|
|
iup.ConsolePrint(tree_local["TITLE"..id] .. " (pos="..pos..")")
|
|
iup.ConsolePrintValue(value)
|
|
|
|
id = tree_local["NEXT"..id]
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerSetTreeTableValue(tree, name, id, newValue)
|
|
local parentId = tree["parent"..id]
|
|
local parentUdata = iup.TreeGetUserId(tree, parentId)
|
|
local parent = parentUdata.value
|
|
parent[name] = newValue
|
|
end
|
|
|
|
function iup.DebuggerSetLocalValue(tree_local, level, id, newValue)
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
local depth = tonumber(tree_local["depth"..id])
|
|
|
|
if depth > 0 then
|
|
iup.DebuggerSetTreeTableValue(tree_local, userdata.name, id, newValue)
|
|
else
|
|
local pos = userdata.pos
|
|
local s = string.sub(userdata.name, 1, 3)
|
|
if s == ":: " then
|
|
debug.setupvalue(tree_local.func, pos, newValue)
|
|
else
|
|
level = level + 1 -- this is the level inside this function
|
|
debug.setlocal(level, pos, newValue)
|
|
end
|
|
end
|
|
|
|
userdata.value = newValue
|
|
end
|
|
|
|
--[[ UNUSED
|
|
function iup.DebuggerGetLocal(tree_local, level, id)
|
|
local name, value
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
local pos = userdata.pos
|
|
local tree_value = tree_local["TITLE"..id]
|
|
local s = string.sub(tree_value, 1, 3)
|
|
if s == ":: " then
|
|
name, value = debug.getupvalue(tree_local.func, pos)
|
|
else
|
|
level = level + 1 -- this is the level inside this function
|
|
name, value = debug.getlocal(level, pos)
|
|
end
|
|
return name, value
|
|
end
|
|
]]
|
|
|
|
function iup.DebuggerLocalVariablesTreeAction(tree_local, id)
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
local valueType = type(userdata.value)
|
|
if valueType == "string" or valueType == "number" or valueType == "boolean" then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_LOCAL", "ACTIVE", "Yes")
|
|
else
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_LOCAL", "ACTIVE", "No")
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerLocalVariablesBranchOpenAction(tree_local, id)
|
|
local userdata = iup.TreeGetUserId(tree_local, id)
|
|
local tableValue = userdata.value
|
|
local pos = userdata.pos
|
|
|
|
if type(tableValue) ~= "table" or userdata.expanded then
|
|
return
|
|
end
|
|
|
|
local dummy_id = id + 1
|
|
userdata.expanded = true
|
|
|
|
id = dummy_id
|
|
|
|
-- the same algorithm used in ConsolePrintTable
|
|
local name
|
|
local tmp = {}
|
|
for name, value in ipairs(tableValue) do
|
|
id = iup.DebuggerAddLocalTreeItem(tree_local, id, name, value, pos)
|
|
tmp[name] = true
|
|
end
|
|
for name, value in pairs(tableValue) do
|
|
if (not tmp[name]) then
|
|
id = iup.DebuggerAddLocalTreeItem(tree_local, id, name, value, pos)
|
|
end
|
|
end
|
|
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_TREE_LOCAL", "DELNODE"..dummy_id, "SELECTED")
|
|
end
|
|
|
|
function iup.DebuggerGetTreeTitle(tree, id, name, value)
|
|
local depth = tonumber(tree["depth"..id])
|
|
local pref = ""
|
|
local suff = ""
|
|
if depth and depth > 0 then
|
|
pref = "["
|
|
suff = "]"
|
|
end
|
|
|
|
local title = pref .. name .. suff .. " = "
|
|
|
|
if type(value) == "string" then
|
|
title = title .. "\"" .. value .. "\""
|
|
else
|
|
title = title .. tostring(value)
|
|
end
|
|
|
|
title = title .. " <" .. type(value) .. ">"
|
|
|
|
return title
|
|
end
|
|
|
|
function iup.DebuggerSetLocalTreeItem(tree_local, id, name, value)
|
|
tree_local["TITLE"..id] = iup.DebuggerGetTreeTitle(tree_local, id, name, value)
|
|
end
|
|
|
|
function iup.DebuggerAddLocalTreeItem(tree_local, id, name, value, pos)
|
|
local userdata = {}
|
|
local lastAddedNode
|
|
|
|
if type(value) == "table" then
|
|
tree_local["INSERTBRANCH"..id] = iup.DebuggerGetTreeTitle(tree_local, id, name, value)
|
|
lastAddedNode = tree_local.lastaddnode
|
|
|
|
tree_local["ADDLEAF"..lastAddedNode] = "dummy"
|
|
userdata.expanded = false
|
|
else
|
|
tree_local["INSERTLEAF"..id] = iup.DebuggerGetTreeTitle(tree_local, id, name, value)
|
|
lastAddedNode = tree_local.lastaddnode
|
|
end
|
|
|
|
userdata.name = name
|
|
userdata.value = value
|
|
userdata.pos = pos
|
|
|
|
iup.TreeSetUserId(tree_local, lastAddedNode, userdata)
|
|
|
|
return tonumber(lastAddedNode)
|
|
end
|
|
|
|
function iup.DebuggerUpdateLocalVariablesTree(level)
|
|
local name, value
|
|
local pos
|
|
local id = -1
|
|
|
|
level = level + 1 -- this is the level inside this function
|
|
|
|
iup.DebuggerClearLocalVariablesTree()
|
|
|
|
local tree_local = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_LOCAL")
|
|
|
|
pos = 1
|
|
name, value = debug.getlocal(level, pos)
|
|
while name ~= nil do
|
|
if string.sub(name, 1, 1) ~= "(" then -- do not include internal variables (loop control variables, temporaries, etc).
|
|
id = iup.DebuggerAddLocalTreeItem(tree_local, id, name, value, pos)
|
|
end
|
|
|
|
pos = pos + 1
|
|
name, value = debug.getlocal(level, pos)
|
|
end
|
|
|
|
-- vararg (only for Lua >= 5.2, ignored in Lua 5.1)
|
|
pos = -1
|
|
name, value = debug.getlocal(level, pos)
|
|
while name ~= nil do
|
|
name = "vararg[" .. -pos .. "]"
|
|
id = iup.DebuggerAddLocalTreeItem(tree_local, id, name, value, pos)
|
|
|
|
pos = pos - 1
|
|
name, value = debug.getlocal(level, pos)
|
|
end
|
|
|
|
local call = debug.getinfo(level, "uf")
|
|
if call.nups > 0 then
|
|
pos = 1
|
|
tree_local.func = call.func
|
|
name, value = debug.getupvalue(call.func, pos)
|
|
while name ~= nil do
|
|
name = ":: " .. name
|
|
id = iup.DebuggerAddLocalTreeItem(tree_local, id, name, value, pos)
|
|
|
|
pos = pos + 1
|
|
name, value = debug.getupvalue(call.func, pos)
|
|
end
|
|
else
|
|
tree_local.func = nil
|
|
end
|
|
|
|
if (id > 0) then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_LOCAL", "ACTIVE", "Yes")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_LOCAL", "ACTIVE", "Yes")
|
|
|
|
tree_local.value = 1 -- select first item on list
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerShowTip(word, line)
|
|
|
|
if debugger.debugState ~= DEBUG_PAUSED and debugger.debugState ~= DEBUG_ERRORPAUSED then
|
|
return
|
|
end
|
|
|
|
local list_stack = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_STACK")
|
|
local index = tonumber(list_stack.value)
|
|
|
|
-- here there are 4 levels on top of the stack:
|
|
-- 1-DebuggerShowTip,
|
|
-- 2-LoopStep
|
|
-- 3-DebuggerLineHook,
|
|
-- 4-DebuggerHookFunction
|
|
local startLevel = 5
|
|
local level = index - 1 + startLevel -- this is the level of the function
|
|
|
|
-- check if inside the current function
|
|
local info = debug.getinfo(level, "SlL") -- linedefined, lastlinedefined, activelines
|
|
if info.linedefined == 0 and info.lastlinedefined == 0 then
|
|
if not info.activelines[line] then
|
|
return
|
|
end
|
|
elseif line < info.linedefined or line > info.lastlinedefined then
|
|
return
|
|
end
|
|
|
|
-- check for local
|
|
local pos = 1
|
|
local name, value = debug.getlocal(level, pos)
|
|
while name ~= nil do
|
|
if name == word then
|
|
return tostring(value)
|
|
end
|
|
|
|
pos = pos + 1
|
|
name, value = debug.getlocal(level, pos)
|
|
end
|
|
|
|
-- check for upvalues
|
|
local call = debug.getinfo(level, "uf")
|
|
if call.nups > 0 then
|
|
pos = 1
|
|
name, value = debug.getupvalue(call.func, pos)
|
|
while name ~= nil do
|
|
if name == word then
|
|
return tostring(value)
|
|
end
|
|
|
|
pos = pos + 1
|
|
name, value = debug.getupvalue(call.func, pos)
|
|
end
|
|
end
|
|
|
|
-- check for global
|
|
if _G[word] then
|
|
return tostring(_G[word])
|
|
end
|
|
end
|
|
|
|
|
|
------------------------------------- Stack -------------------------------------
|
|
|
|
|
|
function iup.DebuggerStackListAction(list_stack, index)
|
|
|
|
-- here there are 4 levels on top of the stack:
|
|
-- 1-DebuggerStackListAction,
|
|
-- 2-LoopStep
|
|
-- 3-DebuggerLineHook,
|
|
-- 4-DebuggerHookFunction
|
|
local startLevel = 5
|
|
local level = index - 1 + startLevel -- this is the level of the function
|
|
|
|
iup.DebuggerUpdateLocalVariablesTree(level)
|
|
|
|
local filename = list_stack["FILENAME" .. index]
|
|
local line = list_stack["LINE" .. index]
|
|
|
|
iup.DebuggerSelectLine(filename, tonumber(line), false) -- do not find
|
|
end
|
|
|
|
function iup.DebuggerStackListActivate(list_stack, index)
|
|
local startLevel = 5
|
|
local level = index - 1 + startLevel -- this is the level of the function
|
|
|
|
iup.DebuggerUpdateLocalVariablesTree(level)
|
|
|
|
local filename = list_stack["FILENAME" .. index]
|
|
local line = list_stack["LINE" .. index]
|
|
local source = list_stack["SOURCE" .. index]
|
|
|
|
iup.DebuggerSelectLine(filename, tonumber(line), true, source) -- find
|
|
end
|
|
|
|
function iup.DebuggerClearStackList()
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_LEVEL", "ACTIVE", "NO")
|
|
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_LIST_STACK", "REMOVEITEM", "ALL")
|
|
end
|
|
|
|
function iup.DebuggerPrintStackLevel()
|
|
local list_stack = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_STACK")
|
|
local index = list_stack.value
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
local defined = list_stack["DEFINED" .. index]
|
|
|
|
iup.ConsolePrint(list_stack[index] .. " (level=" .. index..")")
|
|
iup.ConsolePrint(defined)
|
|
end
|
|
|
|
function iup.DebuggerPrintAllStackLevel()
|
|
local list_stack = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_STACK")
|
|
local count = tonumber(list_stack.count)
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
for index = 1, count do
|
|
local defined = list_stack["DEFINED" .. index]
|
|
|
|
iup.ConsolePrint(list_stack[index] .. " (level=" .. index..")")
|
|
iup.ConsolePrint(defined)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerUpdateStackList()
|
|
local info, desc, defined
|
|
|
|
-- here there are 3 levels on top of the stack:
|
|
-- 1-DebuggerUpdateStackList,
|
|
-- 2-DebuggerLineHook,
|
|
-- 3-DebuggerHookFunction
|
|
local startLevel = 4
|
|
local level = startLevel
|
|
|
|
iup.DebuggerClearStackList()
|
|
|
|
local list_stack = iup.GetDialogChild(debugger.main_dialog, "DEBUG_LIST_STACK")
|
|
|
|
info = debug.getinfo(level)--, "Snl") -- source, name, namewhat, what, currentline, linedefined
|
|
while info ~= nil do
|
|
if info.what == "main" then
|
|
desc = "<main>"
|
|
elseif info.name and info.name ~= "" then
|
|
desc = info.name
|
|
else
|
|
desc = "<noname>"
|
|
end
|
|
if _VERSION ~= "Lua 5.1" then
|
|
local call = debug.getinfo(level, "uf")
|
|
local params = ""
|
|
local pos = 1
|
|
local name, value = debug.getlocal(call.func, pos)
|
|
while name ~= nil do
|
|
params = params .. name .. ", "
|
|
pos = pos + 1
|
|
name, value = debug.getlocal(call.func, pos)
|
|
end
|
|
if params ~= "" then
|
|
if call.isvararg then
|
|
params = params .. "..."
|
|
else
|
|
params = string.sub(params, 1, -3) -- remove last ", "
|
|
end
|
|
desc = desc .. "(" .. params .. ")"
|
|
end
|
|
end
|
|
if info.namewhat ~= "" then
|
|
desc = desc .. " <".. info.namewhat .. ">"
|
|
end
|
|
if info.currentline > 0 then
|
|
desc = desc .. " at line " .. info.currentline
|
|
end
|
|
|
|
local filename
|
|
if info.what == "C" then
|
|
defined = " [Defined in C"
|
|
else
|
|
local s = string.sub(info.source, 1, 1)
|
|
if s == "@" then
|
|
filename = string.sub(info.source, 2)
|
|
defined = " [Defined in the file: \"" .. filename .. "\""
|
|
else
|
|
filename = string.sub(info.short_src, 2, -2)
|
|
defined = " [Defined in a " .. filename
|
|
end
|
|
end
|
|
if info.linedefined > 0 then
|
|
defined = defined .. ", line " .. info.linedefined .. "]"
|
|
else
|
|
defined = defined .. "]"
|
|
end
|
|
|
|
local index = (level - startLevel) + 1
|
|
list_stack[index] = desc
|
|
list_stack["DEFINED" .. index] = defined
|
|
list_stack["FILENAME" .. index] = filename
|
|
list_stack["SOURCE" .. index] = info.source
|
|
list_stack["LINE" .. index] = info.currentline
|
|
|
|
level = level + 1
|
|
|
|
info = debug.getinfo(level)--, "Snl") -- source, name, namewhat, what, currentline, linedefined
|
|
end
|
|
|
|
if level > startLevel then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_LEVEL", "ACTIVE", "YES")
|
|
|
|
list_stack.value = 1 -- select first item on list (startLevel)
|
|
iup.DebuggerUpdateLocalVariablesTree(startLevel)
|
|
end
|
|
|
|
end
|
|
|
|
|
|
---------------------------- Globals --------------------------
|
|
|
|
function iup.DebuggerIsExpression(name)
|
|
if string.find(name, "[^%w_]") then -- finds any non alphanumeric character, but allows underscore
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerGetGlobalNameFromTree(tree_global, id)
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
return userdata.globalname
|
|
end
|
|
|
|
function iup.DebuggerGetGlobalValue(name)
|
|
local value
|
|
-- used only for root nodes, and only when debuger is active
|
|
|
|
if iup.DebuggerIsExpression(name) then
|
|
local cmd, msg = loadstring("return " .. name)
|
|
if not cmd then
|
|
value = "<Invalid Expression> " .. msg
|
|
else
|
|
local result = {pcall(cmd)}
|
|
if result[1] then
|
|
value = result[2]
|
|
else
|
|
value = "<Invalid Expression>" .. result[2]
|
|
end
|
|
end
|
|
else
|
|
value = _G[name]
|
|
end
|
|
|
|
return value
|
|
end
|
|
|
|
function iup.DebuggerGlobalsTreeAction(tree_global, id)
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
local name = userdata.globalname
|
|
if iup.DebuggerIsExpression(name) then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "NO")
|
|
else
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "YES")
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerGlobalVariablesBranchOpenAction(tree_global, id)
|
|
-- can not expand when debugger is not active
|
|
if not iup.DebuggerIsActive() then
|
|
return iup.IGNORE
|
|
end
|
|
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
local tableValue = userdata.value
|
|
|
|
if type(tableValue) ~= "table" or userdata.expanded then
|
|
return
|
|
end
|
|
|
|
local dummy_id = id + 1
|
|
userdata.expanded = true
|
|
|
|
id = dummy_id
|
|
|
|
-- the same algorithm used in ConsolePrintTable
|
|
local name
|
|
local tmp = {}
|
|
for name, value in ipairs(tableValue) do
|
|
id = iup.DebuggerAddGlobalsTreeItem(tree_global, id, name, value)
|
|
tmp[name] = true
|
|
end
|
|
for name, value in pairs(tableValue) do
|
|
if (not tmp[name]) then
|
|
id = iup.DebuggerAddGlobalsTreeItem(tree_global, id, name, value)
|
|
end
|
|
end
|
|
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_TREE_GLOBAL", "DELNODE"..dummy_id, "SELECTED")
|
|
end
|
|
|
|
function iup.DebuggerInitGlobalsTree(tree_global)
|
|
if not tree_global then
|
|
tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
end
|
|
|
|
local count = tonumber(tree_global.rootcount)
|
|
|
|
local id = 0
|
|
for i = 0, count-1 do
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
local name = userdata.globalname
|
|
tree_global["TITLE"..id] = name
|
|
tree_global["IMAGE"..id] = "IUP_TreeEmpty"
|
|
tree_global["IMAGEEXPANDED"..id] = "IUP_TreeEmpty"
|
|
tree_global["DELNODE"..id] = "CHILDREN"
|
|
|
|
id = tree_global["NEXT"..id]
|
|
end
|
|
|
|
tree_global.expandall = "NO"
|
|
|
|
local count = tonumber(tree_global.rootcount)
|
|
if (count > 0) then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_GLOBAL", "ACTIVE", "Yes")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "Yes")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_GLOBAL", "ACTIVE", "Yes")
|
|
|
|
tree_global.value = 1 -- select first item on list
|
|
iup.DebuggerGlobalsTreeAction(tree_global, tree_global.value)
|
|
else
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_GLOBAL", "ACTIVE", "NO")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "NO")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_GLOBAL", "ACTIVE", "NO")
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerUpdateGlobalsTree()
|
|
-- this is called only during debug
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
local count = tonumber(tree_global.rootcount) -- print all at root only
|
|
|
|
-- clear all secondary branches (including "dummy")
|
|
local id = 0
|
|
for i = 0, count-1 do
|
|
tree_global["DELNODE"..id] = "CHILDREN"
|
|
id = tree_global["NEXT"..id]
|
|
end
|
|
|
|
id = 0
|
|
for i = 0, count-1 do
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
local name = userdata.globalname
|
|
local value = iup.DebuggerGetGlobalValue(name)
|
|
userdata.value = value
|
|
userdata.expanded = false
|
|
|
|
iup.DebuggerSetGlobalsTreeItem(tree_global, id, name, value)
|
|
|
|
id = tree_global["NEXT"..id]
|
|
end
|
|
|
|
tree_global.expandall = "NO"
|
|
end
|
|
|
|
function iup.DebuggerSetGlobalsTreeItem(tree_global, id, name, value)
|
|
tree_global["TITLE"..id] = iup.DebuggerGetTreeTitle(tree_global, id, name, value)
|
|
|
|
if type(value) == "table" then
|
|
tree_global["IMAGE"..id] = "IUP_TreePlus"
|
|
tree_global["IMAGEEXPANDED"..id] = "IUP_TreeMinus"
|
|
|
|
-- restore "dummy"
|
|
tree_global["ADDLEAF"..id] = "dummy"
|
|
else
|
|
tree_global["IMAGE"..id] = "IUP_TreeEmpty"
|
|
tree_global["IMAGEEXPANDED"..id] = "IUP_TreeEmpty"
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerAddGlobalsTreeItem(tree_global, id, name, value)
|
|
local userdata = {}
|
|
local lastAddedNode
|
|
|
|
if type(value) == "table" then
|
|
tree_global["INSERTBRANCH"..id] = iup.DebuggerGetTreeTitle(tree_global, id, name, value)
|
|
lastAddedNode = tree_global.lastaddnode
|
|
tree_global["IMAGE"..lastAddedNode] = "IUP_TreePlus"
|
|
tree_global["IMAGEEXPANDED"..lastAddedNode] = "IUP_TreeMinus"
|
|
|
|
tree_global["ADDLEAF"..lastAddedNode] = "dummy"
|
|
else
|
|
tree_global["INSERTBRANCH"..id] = iup.DebuggerGetTreeTitle(tree_global, id, name, value)
|
|
lastAddedNode = tree_global.lastaddnode
|
|
tree_global["IMAGE"..lastAddedNode] = "IUP_TreeEmpty"
|
|
tree_global["IMAGEEXPANDED"..lastAddedNode] = "IUP_TreeEmpty"
|
|
end
|
|
|
|
userdata.globalname = name
|
|
userdata.expanded = false
|
|
userdata.value = value
|
|
|
|
iup.TreeSetUserId(tree_global, lastAddedNode, userdata)
|
|
|
|
return lastAddedNode
|
|
end
|
|
|
|
function iup.DebuggerAddGlobal(tree_global, name)
|
|
local id = tonumber(tree_global.last0)
|
|
if not id then id = -1 end
|
|
|
|
if iup.DebuggerIsActive() then
|
|
local value = iup.DebuggerGetGlobalValue(name)
|
|
return iup.DebuggerAddGlobalsTreeItem(tree_global, id, name, value)
|
|
else
|
|
local userdata = {}
|
|
|
|
userdata.globalname = name
|
|
userdata.expanded = false
|
|
|
|
tree_global["INSERTBRANCH"..id] = name
|
|
local lastAddedNode = tree_global.lastaddnode
|
|
tree_global["IMAGE"..lastAddedNode] = "IUP_TreeEmpty"
|
|
tree_global["IMAGEEXPANDED"..lastAddedNode] = "IUP_TreeEmpty"
|
|
|
|
iup.TreeSetUserId(tree_global, lastAddedNode, userdata)
|
|
return lastAddedNode
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerAddGlobalVariable()
|
|
local status, newName = iup.GetParam("Add Global", setparent_param_cb, "Name = ".."%s\n", "")
|
|
if (status) then
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
local count = tonumber(tree_global.rootcount)
|
|
|
|
local lastAddedNode = iup.DebuggerAddGlobal(tree_global, newName)
|
|
|
|
if (count == 0) then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_GLOBAL", "ACTIVE", "Yes")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "Yes")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_GLOBAL", "ACTIVE", "Yes")
|
|
end
|
|
|
|
iup.DebuggerGlobalsTreeAction(tree_global, lastAddedNode)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerRemoveGlobalVariable()
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
local id = tree_global.value
|
|
if (not id or tonumber(id) < 0) then
|
|
iup.MessageError(debugger.main_dialog, "Select a variable or expression on the list.")
|
|
return
|
|
end
|
|
|
|
-- get the root item
|
|
local parentId = tree_global["parent"..id]
|
|
while parentId do
|
|
id = parentId
|
|
parentId = tree_global["parent"..id]
|
|
end
|
|
|
|
-- select the next item
|
|
local next_id = tree_global["next"..id]
|
|
if next_id then
|
|
tree_global.value = next_id
|
|
else
|
|
local previous_id = tree_global["previous"..id]
|
|
if previous_id then
|
|
tree_global.value = previous_id
|
|
end
|
|
end
|
|
|
|
tree_global["DELNODE"..id] = "SELECTED"
|
|
|
|
local count = tonumber(tree_global.rootcount)
|
|
if (count == 0) then
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_GLOBAL", "ACTIVE", "No")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "No")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_GLOBAL", "ACTIVE", "No")
|
|
else
|
|
|
|
iup.DebuggerGlobalsTreeAction(tree_global, tree_global.value)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerRemoveAllGlobalVariable()
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
|
|
tree_global["DELNODE"] = "ALL"
|
|
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_PRINT_GLOBAL", "ACTIVE", "No")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_SET_GLOBAL", "ACTIVE", "No")
|
|
iup.DebuggerSetDialogChildAttrib("DEBUG_REMOVE_GLOBAL", "ACTIVE", "No")
|
|
end
|
|
|
|
function iup.DebuggerSetGlobalVariable()
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
local id = tree_global.value
|
|
if (not id or tonumber(id) < 0) then
|
|
iup.MessageError(debugger.main_dialog, "Select a variable on the list.")
|
|
return
|
|
end
|
|
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
|
|
local name = userdata.globalname
|
|
|
|
if iup.DebuggerIsExpression(name) then
|
|
iup.MessageError(debugger.main_dialog, "Can not change expressions values.")
|
|
return
|
|
end
|
|
|
|
local value
|
|
local depth = tonumber(tree_global["depth"..id])
|
|
if depth > 0 then
|
|
value = userdata.value
|
|
else
|
|
value = iup.DebuggerGetGlobalValue(name)
|
|
end
|
|
|
|
if (value == nil) then value = "nil" end
|
|
local valueType = type(value)
|
|
if valueType ~= "string" and valueType ~= "number" and valueType ~= "boolean" then
|
|
iup.MessageError(debugger.main_dialog, "Can edit only strings, numbers and booleans.")
|
|
return
|
|
end
|
|
|
|
local status, newValue = iup.GetParam("Set Global", setparent_param_cb, name.." = ".."%s{true, false and nil are translated to Lua values.}\n", tostring(value))
|
|
|
|
if (status) then
|
|
local bol = string.lower(newValue)
|
|
if bol == "true" then
|
|
newValue = true
|
|
elseif bol == "false" then
|
|
newValue = false
|
|
elseif bol == "nil" then
|
|
newValue = nil
|
|
else
|
|
local num = tonumber(newValue)
|
|
if num then
|
|
newValue = num
|
|
end
|
|
end
|
|
|
|
if depth > 0 then
|
|
iup.DebuggerSetTreeTableValue(tree_global, name, id, newValue)
|
|
else
|
|
_G[name] = newValue
|
|
end
|
|
|
|
if iup.DebuggerIsActive() then
|
|
iup.DebuggerSetGlobalsTreeItem(tree_global, id, name, newValue)
|
|
else
|
|
tree_global["TITLE"..id] = name
|
|
tree_global["IMAGE"..id] = "IUP_TreeEmpty"
|
|
tree_global["IMAGEEXPANDED"..id] = "IUP_TreeEmpty"
|
|
end
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerPrintGlobalVariable()
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
local id = tree_global.value
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
|
|
local value
|
|
local depth = tonumber(tree_global["depth"..id])
|
|
if depth > 0 then
|
|
value = userdata.value
|
|
else
|
|
value = iup.DebuggerGetGlobalValue(userdata.globalname)
|
|
end
|
|
|
|
iup.ConsolePrint(tree_global["TITLE"..id])
|
|
iup.ConsolePrintValue(value)
|
|
end
|
|
|
|
function iup.DebuggerPrintAllGlobalVariables()
|
|
local tree_global = iup.GetDialogChild(debugger.main_dialog, "DEBUG_TREE_GLOBAL")
|
|
local count = tonumber(tree_global.rootcount) -- print all at root only
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
local id = 0
|
|
for i = 0, count-1 do
|
|
local userdata = iup.TreeGetUserId(tree_global, id)
|
|
local value = iup.DebuggerGetGlobalValue(userdata.globalname)
|
|
|
|
iup.ConsolePrint(tree_global["TITLE"..id])
|
|
iup.ConsolePrintValue(value)
|
|
|
|
id = tree_global["NEXT"..id]
|
|
end
|
|
end
|
|
|
|
|
|
---------------------------- Debug State --------------------------
|
|
|
|
|
|
function iup.DebuggerGetFuncLevel()
|
|
-- level 0 is the current function (getinfo itself);
|
|
-- level 1 is the function that called getinfo (DebuggerGetFuncLevel)
|
|
local func_level = 1
|
|
repeat
|
|
func_level = func_level + 1
|
|
until debug.getinfo(func_level, "l") == nil -- only current line, default is all info
|
|
return func_level - 1
|
|
end
|
|
|
|
function iup.DebuggerUpdateState(filename, line)
|
|
if debugger.debugState == DEBUG_STEP_OUT then
|
|
if debugger.stepFuncState == FUNC_STATE_OUTSIDE then
|
|
iup.DebuggerSetState(DEBUG_PAUSED)
|
|
|
|
debugger.stepFuncState = FUNC_STATE_OUTSIDE
|
|
debugger.stepFuncLevel = debugger.currentFuncLevel
|
|
end
|
|
elseif debugger.debugState == DEBUG_STEP_INTO or
|
|
(debugger.debugState == DEBUG_STEP_OVER and debugger.stepFuncState == FUNC_STATE_OUTSIDE) or
|
|
(debugger.debugState ~= DEBUG_PAUSED and iup.DebuggerHasBreakpoint(filename, line)) then
|
|
iup.DebuggerSetState(DEBUG_PAUSED)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerErrorMessage(message)
|
|
local dlg = iup.messagedlg
|
|
{
|
|
parentdialog = debugger.main_dialog,
|
|
dialogtype = "ERROR",
|
|
buttons = "OKCANCEL",
|
|
title = "Lua Error!",
|
|
}
|
|
|
|
dlg.value = message .. "\n\nWould you like to debug at error location?"
|
|
|
|
dlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
|
|
local ret = dlg.buttonresponse
|
|
dlg:destroy()
|
|
|
|
if ret == "1" then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerForcePause(filename, currentline, source)
|
|
iup.DebuggerSetState(DEBUG_ERRORPAUSED)
|
|
|
|
iup.DebuggerHighlightLine(filename, currentline, source)
|
|
|
|
iup.DebuggerUpdateGlobalsTree()
|
|
|
|
iup.DebuggerUpdateStackList()
|
|
|
|
while debugger.debugState == DEBUG_ERRORPAUSED do
|
|
local ret = iup.LoopStep()
|
|
if ret == iup.CLOSE then
|
|
iup.ExitLoop() -- repost to MainLoop
|
|
end
|
|
end
|
|
|
|
-- in any change of state, simply stop the debugger
|
|
iup.DebuggerSetState(DEBUG_INACTIVE)
|
|
iup.DebuggerCloseTemporary()
|
|
end
|
|
|
|
function iup.DebuggerTraceBack(msg)
|
|
if not msg then
|
|
return
|
|
end
|
|
|
|
-- hook is always at level 2 when called
|
|
local info = debug.getinfo(2, "Sl") -- what, source, currentline
|
|
local s = string.sub(info.source, 1, 1)
|
|
local filename
|
|
if s == "@" then
|
|
filename = string.sub(info.source, 2)
|
|
else
|
|
filename = string.sub(info.short_src, 2, -2)
|
|
end
|
|
|
|
iup._TRACEBACK = nil
|
|
debug.sethook() -- turns off the hook
|
|
|
|
-- NOT necessary
|
|
-- msg = debug.traceback(msg)
|
|
|
|
iup.ConsolePrint("Lua Error:")
|
|
iup.ConsolePrint(msg)
|
|
|
|
if iup.DebuggerErrorMessage(msg) then
|
|
iup.DebuggerForcePause(filename, info.currentline, info.source)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerLineHook(filename, line, source)
|
|
debugger.currentFuncLevel = iup.DebuggerGetFuncLevel()
|
|
|
|
iup.DebuggerUpdateState(filename, line)
|
|
|
|
if debugger.debugState == DEBUG_PAUSED then
|
|
|
|
iup.DebuggerHighlightLine(filename, line, source)
|
|
|
|
iup.DebuggerUpdateGlobalsTree()
|
|
|
|
iup.DebuggerUpdateStackList()
|
|
|
|
debug.sethook() -- turns off the hook
|
|
|
|
while debugger.debugState == DEBUG_PAUSED do
|
|
local ret = iup.LoopStep()
|
|
if ret == iup.CLOSE then
|
|
iup.ExitLoop() -- repost to MainLoop
|
|
end
|
|
end
|
|
|
|
if iup.DebuggerIsActive() then
|
|
debug.sethook(iup.DebuggerHookFunction, "lcr") -- restore the hook if still active
|
|
end
|
|
end
|
|
|
|
if debugger.debugState == DEBUG_STOPPED then
|
|
iup.DebuggerEndDebug(true)
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerCallHook()
|
|
if debugger.debugState == DEBUG_STEP_OVER then
|
|
if debugger.stepFuncLevel == 0 then
|
|
local func_level = iup.DebuggerGetFuncLevel()
|
|
debugger.stepFuncState = FUNC_STATE_INSIDE
|
|
debugger.stepFuncLevel = func_level
|
|
end
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerReturnHook(filename, what)
|
|
if filename == debugger.startFile and what == "main" then
|
|
iup.DebuggerSetState(DEBUG_INACTIVE)
|
|
elseif debugger.debugState == DEBUG_STEP_OUT or debugger.debugState == DEBUG_STEP_OVER then
|
|
local func_level = iup.DebuggerGetFuncLevel()
|
|
if debugger.stepFuncLevel == func_level then
|
|
debugger.stepFuncState = FUNC_STATE_OUTSIDE
|
|
debugger.stepFuncLevel = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerHookFunction(event, line)
|
|
-- how many levels we have before the hook was invoked?
|
|
-- hook is always at level 2 when called
|
|
-- Inside a hook, you can call getinfo with level 2 to get more information about the running function
|
|
local info = debug.getinfo(2, "S") -- what, source
|
|
local s = string.sub(info.source, 1, 1)
|
|
local filename
|
|
if s == "@" then
|
|
filename = string.sub(info.source, 2)
|
|
else
|
|
filename = string.sub(info.short_src, 2, -2)
|
|
end
|
|
|
|
if iup.DebuggerIsActive() then
|
|
if event == "call" then
|
|
iup.DebuggerCallHook()
|
|
elseif event == "return" then
|
|
iup.DebuggerReturnHook(filename, info.what)
|
|
elseif event == "line" then
|
|
iup.DebuggerLineHook(filename, line, info.source)
|
|
end
|
|
end
|
|
|
|
local ret = iup.LoopStep()
|
|
if ret == iup.CLOSE then
|
|
iup.ExitLoop() -- repost to MainLoop
|
|
end
|
|
end
|
|
|
|
function iup.DebuggerStartDebug(filename)
|
|
debugger.startFile = filename
|
|
|
|
iup.DebuggerShowDebugTab()
|
|
|
|
iup.ConsolePrint("-- Debug start")
|
|
|
|
iup.DebuggerSetState(DEBUG_ACTIVE)
|
|
|
|
debug.sethook(iup.DebuggerHookFunction, "lcr")
|
|
|
|
iup._TRACEBACK = iup.DebuggerTraceBack
|
|
end
|
|
|
|
function iup.DebuggerEndDebug(stop)
|
|
iup._TRACEBACK = nil
|
|
|
|
debug.sethook() -- turns off the hook
|
|
|
|
iup.DebuggerSetState(DEBUG_INACTIVE)
|
|
|
|
iup.DebuggerShowConsoleTab()
|
|
|
|
if stop then
|
|
iup.ConsolePrint("-- Debug stop!")
|
|
error() -- abort processing, no error message
|
|
else
|
|
iup.ConsolePrint("-- Debug finish")
|
|
end
|
|
|
|
iup.DebuggerCloseTemporary()
|
|
end
|
|
|
|
function iup.DebuggerExit()
|
|
if iup.DebuggerIsActive() then
|
|
iup.DebuggerEndDebug(true) -- make a stop
|
|
end
|
|
end
|