@ -11,6 +11,8 @@ local ui =
}
}
local lfs = require ( " lfs " )
local lfs = require ( " lfs " )
local wx = require ( " wx " )
require ( " coxpcall " )
require ( " coxpcall " )
local coxpcall = coxpcall
local coxpcall = coxpcall
local copcall = copcall
local copcall = copcall
@ -37,6 +39,15 @@ local meta = { __index = {} }
local complexValueManagerMeta = { __index = { } }
local complexValueManagerMeta = { __index = { } }
local function createClientConfig ( name )
return {
name = name ,
mappings = { } ,
breakpoints = { } ,
scrollPositions = { } ,
}
end
function new ( engine , window )
function new ( engine , window )
local res =
local res =
{
{
@ -101,9 +112,9 @@ end
function meta . __index : run_ ( )
function meta . __index : run_ ( )
self : sleep_ ( )
self : sleep_ ( )
--@GRLD_PROTECTION@
--@GRLD_PROTECTION@
self.engine . init ( )
self.engine . init ( )
for _ , listener in ipairs ( self.toListen ) do
for _ , listener in ipairs ( self.toListen ) do
self.engine . listen ( listener.ip , listener.port )
self.engine . listen ( listener.ip , listener.port )
@ -114,7 +125,7 @@ function meta.__index:run_()
for _ , cbName in ipairs ( { " onNewClient " , " onClientBreak " , " onClientLost " } ) do
for _ , cbName in ipairs ( { " onNewClient " , " onClientBreak " , " onClientLost " } ) do
self.engine . registerEvent ( cbName , function ( ... ) return self [ cbName .. " _ " ] ( self , ... ) end )
self.engine . registerEvent ( cbName , function ( ... ) return self [ cbName .. " _ " ] ( self , ... ) end )
end
end
local wrapCb = function ( cb )
local wrapCb = function ( cb )
return function ( ... )
return function ( ... )
if self : ready_ ( ) then
if self : ready_ ( ) then
@ -122,30 +133,31 @@ function meta.__index:run_()
end
end
end
end
end
end
self.window : registerEvent ( ui.mainWindow . ID_BREAK , wrapCb ( function ( ) self : onDebugCommand_ ( " breaknow " , " running " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_BREAK , wrapCb ( function ( ) self : onDebugCommand_ ( " breaknow " , " running " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_CONTINUE , wrapCb ( function ( ) self : onDebugCommand_ ( " run " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_CONTINUE , wrapCb ( function ( ) self : onDebugCommand_ ( " run " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_STEP_OVER , wrapCb ( function ( ) self : onDebugCommand_ ( " stepover " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_STEP_OVER , wrapCb ( function ( ) self : onDebugCommand_ ( " stepover " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_STEP_INTO , wrapCb ( function ( ) self : onDebugCommand_ ( " stepin " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_STEP_INTO , wrapCb ( function ( ) self : onDebugCommand_ ( " stepin " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_STEP_OUT , wrapCb ( function ( ) self : onDebugCommand_ ( " stepout " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_STEP_OUT , wrapCb ( function ( ) self : onDebugCommand_ ( " stepout " , " break " ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_TOGGLE_BREAKPOINT , wrapCb ( function ( ) self : onToggleBreakpoint_ ( ) end ) )
self.window : registerEvent ( ui.mainWindow . ID_TOGGLE_BREAKPOINT , wrapCb ( function ( ) self : onToggleBreakpoint_ ( ) end ) )
self.window : registerEvent ( " onBreakPointChanged " , wrapCb ( function ( ... ) self : onBreakPointChanged_ ( ... ) end ) )
self.window : registerEvent ( " onBreakPointChanged " , wrapCb ( function ( ... ) self : onBreakPointChanged_ ( ... ) end ) )
self.window : registerEvent ( " onFileOpen " , wrapCb ( function ( ... ) self : onFileOpen_ ( ... ) end ) )
self.window : registerEvent ( " onFileOpen " , wrapCb ( function ( ... ) self : onFileOpen_ ( ... ) end ) )
self.window : registerEvent ( " onFileClosed " , wrapCb ( function ( ... ) self : onFileClosed_ ( ... ) end ) )
self.window : registerEvent ( " onFileClosed " , wrapCb ( function ( ... ) self : onFileClosed_ ( ... ) end ) )
self.window : registerEvent ( " onScrollChanged " , wrapCb ( function ( ... ) self : onScrollChanged_ ( ... ) end ) )
self.window : registerEvent ( " onApplicationExiting " , wrapCb ( function ( ... ) self : onApplicationExiting_ ( ... ) end ) )
self.window : registerEvent ( " onApplicationExiting " , wrapCb ( function ( ... ) self : onApplicationExiting_ ( ... ) end ) )
self.window . threads : registerEvent ( " onThreadClicked " , wrapCb ( function ( ... ) self : onThreadClicked_ ( ... ) end ) )
self.window . threads : registerEvent ( " onThreadClicked " , wrapCb ( function ( ... ) self : onThreadClicked_ ( ... ) end ) )
self.window . threads : registerEvent ( " onBreakOnConnectionChanged " , wrapCb ( function ( ... ) self : onBreakOnConnectionChanged_ ( ... ) end ) )
self.window . threads : registerEvent ( " onBreakOnConnectionChanged " , wrapCb ( function ( ... ) self : onBreakOnConnectionChanged_ ( ... ) end ) )
self.window . callstack : registerEvent ( " onCallstackClicked " , wrapCb ( function ( ... ) self : onCallstackClicked_ ( ... ) end ) )
self.window . callstack : registerEvent ( " onCallstackClicked " , wrapCb ( function ( ... ) self : onCallstackClicked_ ( ... ) end ) )
self.window . watch.evaluateCallback = wrapCb ( function ( expr ) return self : evaluateExpression_ ( expr ) end )
self.window . watch.evaluateCallback = wrapCb ( function ( expr ) return self : evaluateExpression_ ( expr ) end )
self.configs . global = { name = " global " , breakpoints = { } }
self.configs . global = createClientConfig ( ' global ' )
self : loadConfig_ ( " global " )
self : loadConfig_ ( " global " )
self : sleep_ ( )
self : sleep_ ( )
while not self.exiting do
while not self.exiting do
for clientId , clientData in pairs ( self.clients ) do
for clientId , clientData in pairs ( self.clients ) do
@ -188,18 +200,34 @@ function meta.__index:run_()
end
end
end , function ( msg ) print ( " Error refreshing client " .. clientId ) print ( msg ) print ( debug.traceback ( ) ) end )
end , function ( msg ) print ( " Error refreshing client " .. clientId ) print ( msg ) print ( debug.traceback ( ) ) end )
end
end
if self.threadsDirty then
if self.threadsDirty then
coxpcall ( function ( )
coxpcall ( function ( )
self.threadsDirty = false
self.threadsDirty = false
self : refreshThreads_ ( )
self : refreshThreads_ ( )
end , function ( msg ) print ( " Error refreshing threads " ) print ( msg ) print ( debug.traceback ( ) ) end )
end , function ( msg ) print ( " Error refreshing threads " ) print ( msg ) print ( debug.traceback ( ) ) end )
end
end
self : sleep_ ( )
self : sleep_ ( )
end
end
end
end
function meta . __index : getActiveClientConfig_ ( )
local activeClientId = self.activeClient
if activeClientId == nil then
return self.configs . global
end
local clientData = self.clients [ activeClientId ]
if clientData == nil then
return self.configs . global
end
return clientData.config
end
function meta . __index : evaluateExpression_ ( expr )
function meta . __index : evaluateExpression_ ( expr )
local clientId = self.activeClient
local clientId = self.activeClient
local client = self.engine . getClient ( clientId )
local client = self.engine . getClient ( clientId )
@ -224,6 +252,7 @@ function meta.__index:refreshSourcePageFocus_( remoteSource, line )
local clientData = assert ( self.clients [ clientId ] )
local clientData = assert ( self.clients [ clientId ] )
local sourceType = string.sub ( remoteSource , 1 , 1 )
local sourceType = string.sub ( remoteSource , 1 , 1 )
if sourceType == " @ " then
if sourceType == " @ " then
self.window : raise ( )
print ( " Setting focus to " .. remoteSource .. " ( " .. line .. " ) " )
print ( " Setting focus to " .. remoteSource .. " ( " .. line .. " ) " )
remoteSource = grldc.utilities . normalizePath ( string.sub ( remoteSource , 2 ) )
remoteSource = grldc.utilities . normalizePath ( string.sub ( remoteSource , 2 ) )
local source , remotePath , remoteFile = self : getLocalSource_ ( clientId , remoteSource )
local source , remotePath , remoteFile = self : getLocalSource_ ( clientId , remoteSource )
@ -243,16 +272,16 @@ function meta.__index:refreshSourcePageFocus_( remoteSource, line )
clientData.config . mappings [ mount ] = path
clientData.config . mappings [ mount ] = path
clientData.config . dirty = true
clientData.config . dirty = true
source = self : getLocalSource_ ( clientId , remoteSource )
source = self : getLocalSource_ ( clientId , remoteSource )
assert ( source ~= nil )
assert ( source ~= nil )
end
end
end
end
if source ~= nil then
if source ~= nil then
print ( source )
print ( source )
source = grldc.utilities . normalizePath ( source )
source = grldc.utilities . normalizePath ( source )
self : setSourceFocus_ ( " @ " .. source , line )
self : setSourceFocus_ ( " @ " .. source , line )
end
end
--print( source )
--print( source )
return source
return source
end
end
@ -264,12 +293,12 @@ function meta.__index:refreshSourceFocus_( callstack, level )
if type ( callstack ) == " table " and callstack [ level ] ~= nil then
if type ( callstack ) == " table " and callstack [ level ] ~= nil then
local remoteSource = callstack [ level ] . source
local remoteSource = callstack [ level ] . source
local line = callstack [ level ] . line
local line = callstack [ level ] . line
local source = self : refreshSourcePageFocus_ ( remoteSource , line )
local source = self : refreshSourcePageFocus_ ( remoteSource , line )
self : setPointers_ ( level , source , line )
self : setPointers_ ( level , source , line )
self : refreshPointers_ ( )
self : refreshPointers_ ( )
self : refreshWatches_ ( level )
self : refreshWatches_ ( level )
end
end
end
end
@ -333,10 +362,10 @@ function meta.__index:onBreakPointChanged_( source, line )
else
else
local clientData = self.clients [ clientId ]
local clientData = self.clients [ clientId ]
if clientData == nil then return end
if clientData == nil then return end
config = clientData.config
config = clientData.config
end
end
if config.breakpoints [ source ] == nil then
if config.breakpoints [ source ] == nil then
config.breakpoints [ source ] = { }
config.breakpoints [ source ] = { }
end
end
@ -345,9 +374,9 @@ function meta.__index:onBreakPointChanged_( source, line )
if not newValue then
if not newValue then
config.breakpoints [ source ] [ line ] = nil
config.breakpoints [ source ] [ line ] = nil
end
end
print ( " Setting breakpoint at " .. source .. " ( " .. line .. " ) to " .. tostring ( newValue ) )
print ( " Setting breakpoint at " .. source .. " ( " .. line .. " ) to " .. tostring ( newValue ) )
assert ( string.sub ( source , 1 , 1 ) == " @ " )
assert ( string.sub ( source , 1 , 1 ) == " @ " )
source = string.sub ( source , 2 )
source = string.sub ( source , 2 )
for clientId , clientData in pairs ( self.clients ) do
for clientId , clientData in pairs ( self.clients ) do
@ -375,7 +404,7 @@ function meta.__index:onBreakPointChanged_( source, line )
assert ( remoteSource ~= nil )
assert ( remoteSource ~= nil )
end
end
end
end
if remoteSource ~= nil then
if remoteSource ~= nil then
client : setbreakpoint ( " @ " .. remoteSource , line , newValue )
client : setbreakpoint ( " @ " .. remoteSource , line , newValue )
clientData.config . dirty = true
clientData.config . dirty = true
@ -396,6 +425,17 @@ function meta.__index:onApplicationExiting_()
self.window . threads : setData ( nil )
self.window . threads : setData ( nil )
end
end
function meta . __index : refreshScrollPosition_ ( )
local config = self : getActiveClientConfig_ ( )
for source , sp in pairs ( config.scrollPositions ) do
local page = self.window : getSourcePage ( source )
if page ~= nil then
page : SetScrollPos ( sp )
end
end
end
function meta . __index : refreshBreakPoints_ ( )
function meta . __index : refreshBreakPoints_ ( )
local clientId = self.activeClient
local clientId = self.activeClient
local config = nil
local config = nil
@ -406,14 +446,14 @@ function meta.__index:refreshBreakPoints_()
config = self.clients [ clientId ] . config
config = self.clients [ clientId ] . config
client = self.engine . getClient ( clientId )
client = self.engine . getClient ( clientId )
end
end
local remoteBreakPoints = { }
local remoteBreakPoints = { }
if client ~= nil then
if client ~= nil then
remoteBreakPoints = client : breakpoints ( )
remoteBreakPoints = client : breakpoints ( )
end
end
self.window : clearBreakPoints ( )
self.window : clearBreakPoints ( )
local goodBreakpoints = { }
local goodBreakpoints = { }
for remoteSource , lines in pairs ( remoteBreakPoints ) do
for remoteSource , lines in pairs ( remoteBreakPoints ) do
if next ( lines ) ~= nil then
if next ( lines ) ~= nil then
local source = self : getLocalSource_ ( clientId , string.sub ( remoteSource , 2 ) )
local source = self : getLocalSource_ ( clientId , string.sub ( remoteSource , 2 ) )
@ -437,7 +477,7 @@ function meta.__index:refreshBreakPoints_()
end
end
end
end
end
end
for source , lines in pairs ( config.breakpoints ) do
for source , lines in pairs ( config.breakpoints ) do
local page = self.window : findSourcePage ( source )
local page = self.window : findSourcePage ( source )
if page ~= nil then
if page ~= nil then
@ -459,6 +499,7 @@ function meta.__index:onFileOpen_( path )
self : setSourceFocus_ ( source , 1 )
self : setSourceFocus_ ( source , 1 )
self : refreshPointers_ ( )
self : refreshPointers_ ( )
self : refreshBreakPoints_ ( )
self : refreshBreakPoints_ ( )
self : refreshScrollPosition_ ( )
end
end
function meta . __index : onFileClosed_ ( source )
function meta . __index : onFileClosed_ ( source )
@ -467,6 +508,12 @@ function meta.__index:onFileClosed_( source )
end
end
end
end
function meta . __index : onScrollChanged_ ( source , position )
local clientConfig = self : getActiveClientConfig_ ( )
clientConfig.scrollPositions [ source ] = position
clientConfig.dirty = true
end
function meta . __index : onThreadClicked_ ( clientId , threadId )
function meta . __index : onThreadClicked_ ( clientId , threadId )
print ( " Thread clicked: client= " .. clientId .. " , thread= " .. threadId )
print ( " Thread clicked: client= " .. clientId .. " , thread= " .. threadId )
local clientData = self.clients [ clientId ]
local clientData = self.clients [ clientId ]
@ -492,9 +539,9 @@ function meta.__index:onDebugCommand_( command, neededState, targetClientId )
return
return
end
end
if neededState ~= nil and client : status ( ) ~= neededState then return end
if neededState ~= nil and client : status ( ) ~= neededState then return end
self : invalidateState_ ( false )
self : invalidateState_ ( false )
local clientData = assert ( self.clients [ targetClientId ] )
local clientData = assert ( self.clients [ targetClientId ] )
local ok , msg = xpcall ( function ( ) client [ command ] ( client ) end , debug.traceback )
local ok , msg = xpcall ( function ( ) client [ command ] ( client ) end , debug.traceback )
if not ok then
if not ok then
@ -514,7 +561,7 @@ function meta.__index:invalidateState_( immediate )
self.window : clearMarkers ( )
self.window : clearMarkers ( )
self.window . callstack : setData ( nil )
self.window . callstack : setData ( nil )
self : refreshBreakPoints_ ( )
self : refreshBreakPoints_ ( )
local client = self.engine . getClient ( self.activeClient )
local client = self.engine . getClient ( self.activeClient )
if client == nil then
if client == nil then
self.window . auto : clear ( )
self.window . auto : clear ( )
@ -636,7 +683,7 @@ function meta.__index:refreshThreads_()
cdata.status = client : status ( )
cdata.status = client : status ( )
cdata.active = ( clientId == self.activeClient )
cdata.active = ( clientId == self.activeClient )
cdata.breakOnConnection = clientData.config . breakOnConnection
cdata.breakOnConnection = clientData.config . breakOnConnection
if cdata.status == " break " then
if cdata.status == " break " then
local current = client : getcurrentthread ( )
local current = client : getcurrentthread ( )
local active = client : getactivethread ( )
local active = client : getactivethread ( )
@ -644,7 +691,7 @@ function meta.__index:refreshThreads_()
active = current
active = current
end
end
table.insert ( cdata.coroutines , { id = " main " , current = ( current == " main " ) , active = ( active == " main " and cdata.clientId == self.activeClient and client : getactivethread ( ) ~= " current " ) } )
table.insert ( cdata.coroutines , { id = " main " , current = ( current == " main " ) , active = ( active == " main " and cdata.clientId == self.activeClient and client : getactivethread ( ) ~= " current " ) } )
local coroutines = client : coroutines ( )
local coroutines = client : coroutines ( )
--print( coroutines )
--print( coroutines )
for _ , data in ipairs ( coroutines ) do
for _ , data in ipairs ( coroutines ) do
@ -655,7 +702,7 @@ function meta.__index:refreshThreads_()
table.insert ( cdata.coroutines , codata )
table.insert ( cdata.coroutines , codata )
end
end
end
end
table.insert ( data , cdata )
table.insert ( data , cdata )
end
end
end
end
@ -683,15 +730,15 @@ function meta.__index:onNewClient_( clientId )
local client = self.engine . getClient ( clientId )
local client = self.engine . getClient ( clientId )
local name = client : name ( )
local name = client : name ( )
if self.configs [ name ] == nil then
if self.configs [ name ] == nil then
self.configs [ name ] = { name = name , mappings = { } , breakpoints = { } }
self.configs [ name ] = createClientConfig ( name )
self : loadConfig_ ( name )
self : loadConfig_ ( name )
end
end
self.clients [ clientId ] = { dirty = true , activeThread = " current " , activeLevel = 1 , config = self.configs [ name ] }
self.clients [ clientId ] = { dirty = true , activeThread = " current " , activeLevel = 1 , config = self.configs [ name ] }
for source , lines in pairs ( self.configs [ name ] . breakpoints ) do
for source , lines in pairs ( self.configs [ name ] . breakpoints ) do
assert ( string.sub ( source , 1 , 1 ) == " @ " )
assert ( string.sub ( source , 1 , 1 ) == " @ " )
source = string.sub ( source , 2 )
source = string.sub ( source , 2 )
local remoteSource , dir = self : getRemoteSource_ ( clientId , source )
local remoteSource , dir = self : getRemoteSource_ ( clientId , source )
if remoteSource ~= nil then
if remoteSource ~= nil then
for line , value in pairs ( lines ) do
for line , value in pairs ( lines ) do
if value then
if value then
@ -700,12 +747,12 @@ function meta.__index:onNewClient_( clientId )
end
end
end
end
end
end
self.threadsDirty = true
self.threadsDirty = true
if self.activeClient == nil then
if self.activeClient == nil then
self : setActiveClient_ ( clientId )
self : setActiveClient_ ( clientId )
end
end
if not self.configs [ name ] . breakOnConnection then
if not self.configs [ name ] . breakOnConnection then
self.clients [ clientId ] . ignoreNextBreak = true
self.clients [ clientId ] . ignoreNextBreak = true
end
end
@ -717,7 +764,7 @@ function meta.__index:onClientBreak_( clientId )
clientData.dirty = true
clientData.dirty = true
clientData.activeLevel = 1
clientData.activeLevel = 1
self.threadsDirty = true
self.threadsDirty = true
if clientData.ignoreNextBreak then
if clientData.ignoreNextBreak then
clientData.ignoreNextBreak = false
clientData.ignoreNextBreak = false
self : onDebugCommand_ ( " run " , " break " , clientId )
self : onDebugCommand_ ( " run " , " break " , clientId )
@ -741,12 +788,19 @@ function meta.__index:saveConfig_( name )
openFiles [ page.pageIdx + 1 ] = source
openFiles [ page.pageIdx + 1 ] = source
end
end
local breakpoints = clientConfig.breakpoints
local breakpoints = clientConfig.breakpoints
local scrollPositions = clientConfig.scrollPositions
local path = " clients/ " .. name .. " /config.lua "
local path = " clients/ " .. name .. " /config.lua "
lfs.mkdir ( " clients " )
lfs.mkdir ( " clients " )
lfs.mkdir ( " clients/ " .. name )
lfs.mkdir ( " clients/ " .. name )
local file = assert ( io.open ( path , " w " ) )
local file = assert ( io.open ( path , " w " ) )
file : write ( grldc.net . serialize ( { mappings = clientConfig.mappings , openFiles = openFiles , breakpoints = breakpoints , breakOnConnection = clientConfig.breakOnConnection } ) )
file : write ( grldc.net . serialize ( {
mappings = clientConfig.mappings ,
openFiles = openFiles ,
breakpoints = breakpoints ,
scrollPositions = scrollPositions ,
breakOnConnection = clientConfig.breakOnConnection
} ) )
file : close ( )
file : close ( )
print ( " Saved config \" " .. name .. " \" " )
print ( " Saved config \" " .. name .. " \" " )
clientConfig.lastConfigSave = os.time ( )
clientConfig.lastConfigSave = os.time ( )
@ -774,6 +828,12 @@ function meta.__index:loadConfig_( name )
end
end
end
end
end
end
if config.scrollPositions ~= nil then
for source , sp in pairs ( config.scrollPositions ) do
clientConfig.scrollPositions [ source ] = sp
end
end
end
end
if clientConfig.breakOnConnection == nil then
if clientConfig.breakOnConnection == nil then
clientConfig.breakOnConnection = true
clientConfig.breakOnConnection = true