diff --git a/bin/style.css b/bin/style.css index f2c8493d..940792a9 100644 --- a/bin/style.css +++ b/bin/style.css @@ -3484,6 +3484,17 @@ div.gradient-box { padding-right: 2px; cursor: pointer; } +.remoteconsole input { + margin-left: 2px; + margin-right: 2px; + background-color: #333333; +} +.remoteconsole input:disabled { + background-color: #222222; +} +.remoteconsole input:disabled:hover { + border-color: #505050; +} .remoteconsole .logs { margin-top: 2px; margin-bottom: 2px; @@ -3512,13 +3523,6 @@ div.gradient-box { .remoteconsole .remoteconsole-panel .logs { height: 100px; } -.remoteconsole .remoteconsole-panel .commands input { - margin-left: 2px; - margin-right: 2px; -} -.remoteconsole .remoteconsole-panel .commands input:disabled { - background-color: #333333; -} .remoteconsole .remoteconsole-panel .commands fieldset { border: 1px dashed #333333; } diff --git a/bin/style.less b/bin/style.less index 4540e6b2..795617b2 100644 --- a/bin/style.less +++ b/bin/style.less @@ -4070,6 +4070,20 @@ div.gradient-box { cursor: pointer; } + input { + margin-left: 2px; + margin-right: 2px; + background-color: #333333; + } + + input:disabled { + background-color: #222222; + } + + input:disabled:hover { + border-color: #505050; + } + .logs { margin-top: 2px; margin-bottom: 2px; @@ -4104,13 +4118,6 @@ div.gradient-box { } .commands { - input { - margin-left: 2px; - margin-right: 2px; - } - input:disabled { - background-color: #333333; - } fieldset { border: 1px dashed #333333; } diff --git a/hide/view/RemoteConsoleView.hx b/hide/view/RemoteConsoleView.hx index 57cbdccc..4e8fc5e2 100644 --- a/hide/view/RemoteConsoleView.hx +++ b/hide/view/RemoteConsoleView.hx @@ -191,8 +191,10 @@ class RemoteConsoleView extends hide.ui.View<{}> { class RemoteConsolePanel extends hide.comp.Component { var view : RemoteConsoleView; - public var connection(default, set) : hrt.impl.RemoteConsole.RemoteConsoleConnection; var statusIcon : Element; + public var connection(default, set) : hrt.impl.RemoteConsole.RemoteConsoleConnection; + public var peerPath(default, null) : String; + public var peerCwd(default, null) : String; public function new( view : RemoteConsoleView, connection : Null, commands : Null> ) { super(null, null); this.view = view; @@ -202,6 +204,10 @@ class RemoteConsolePanel extends hide.comp.Component {
+
+ Peer Info + +
@@ -224,6 +230,13 @@ class RemoteConsolePanel extends hide.comp.Component { c.onClose = () -> refreshStatusIcon(); c.log = (msg) -> log(msg); c.logError = (msg) -> log(msg, true); + c.sendCommand("info", null, function(d) { + peerPath = d?.programPath == null ? "???" : haxe.io.Path.normalize(d.programPath); + var peerArgs = d?.args ?? []; + peerCwd = d?.cwd == null ? null : haxe.io.Path.normalize(d.cwd); + var peerId = peerPath + (peerArgs.length == 0 ? "" : " " + peerArgs.join(" ")); + element.find("#peerInfo").val(peerId); + }); } if( connection != null ) { connection.onClose = () -> {}; @@ -295,14 +308,34 @@ class RemoteConsoleCommand extends hide.comp.Component { class RemoteConsoleCommandDump extends RemoteConsoleCommand { public function new( panel : RemoteConsolePanel ) { super(panel); - new Element('Memory dump').appendTo(element); + new Element('GC Memory').appendTo(element); + var subcmd = new Element('
').appendTo(element); + var gcBtn = new Element('').appendTo(subcmd); + gcBtn.on('click', function(e) { + panel.sendCommand("gcMajor", null, function(r) { + panel.log('Gc.major took ${r/1000} ms'); + }); + }); var subcmd = new Element('
').appendTo(element); var dumpBtn = new Element('').appendTo(subcmd); var dumpFile = new Element('').appendTo(subcmd); dumpBtn.on('click', function(e) { - panel.sendCommand("dump", null, function(r) { - panel.log("Dump saved to hlmemory.dump"); - dumpFile.val(hide.Ide.inst.projectDir + "/hlmemory.dump"); + panel.sendCommand("dumpMemory", null, function(r) { + var dir = (panel.peerCwd ?? hide.Ide.inst.projectDir) + "/"; + var file = "hlmemory.dump"; + try { + var now = DateTools.format(Date.now(), "%Y-%m-%d_%H-%M-%S"); + var outfile = "hlmemory_" + now; + sys.FileSystem.rename(dir + file, dir + outfile + ".dump"); + file = outfile + ".dump"; + if( panel.peerPath != null && sys.FileSystem.exists(panel.peerPath) ) { + sys.io.File.copy(panel.peerPath, dir + outfile + ".hl"); + } + } catch( e ) { + panel.log(e.message, true); + } + panel.log("Dump saved to " + file); + dumpFile.val(dir + file); }); }); var openBtn = new Element('').appendTo(subcmd); @@ -315,25 +348,18 @@ class RemoteConsoleCommandDump extends RemoteConsoleCommand { } }); var subcmd = new Element('
').appendTo(element); - var programBtn = new Element('').appendTo(subcmd); - var programFile = new Element('').appendTo(subcmd); - programBtn.on('click', function(e) { - panel.sendCommand("programPath", null, function(r) { - if( r != null ) { - programFile.val(r); - } else { - panel.log("Unknown program path: " + r); + var liveBtn = new Element('').appendTo(subcmd); + var liveClass = new Element('').appendTo(subcmd); + liveBtn.on('click', function(e) { + var clname = liveClass.val(); + panel.sendCommand("liveObjects", { clname : clname }, function(r) { + if( r >= 0 ) { + panel.log('Live Objects of class $clname: count $r'); } }); }); - var openBtn = new Element('').appendTo(subcmd); - openBtn.on('click', function(e) { - var file = programFile.val(); - if( file.length > 0 && sys.FileSystem.exists(file) ) { - hide.Ide.showFileInExplorer(file); - } else { - panel.log('File $file does not exist', true); - } + liveClass.keydown(function(e) { + if( e.key == 'Enter' ) liveBtn.click(); }); } static var _ = RemoteConsoleView.registerCommandView("dump", RemoteConsoleCommandDump); @@ -342,20 +368,34 @@ class RemoteConsoleCommandDump extends RemoteConsoleCommand { class RemoteConsoleCommandProf extends RemoteConsoleCommand { public function new( panel : RemoteConsolePanel ) { super(panel); - new Element('CPU Profile').appendTo(element); + new Element('Profile').appendTo(element); var subcmd = new Element('
').appendTo(element); var startBtn = new Element('').appendTo(subcmd); startBtn.on('click', function(e) { - panel.sendCommand("prof", { action : "start" }, function(r) { + panel.sendCommand("profCpu", { action : "start" }, function(r) { panel.log("Profiling started"); }); }); var dumpBtn = new Element('').appendTo(subcmd); var dumpFile = new Element('').appendTo(subcmd); dumpBtn.on('click', function(e) { - panel.sendCommand("prof", { action : "dump" }, function(r) { - panel.log("Profil raw dump saved to hlprofile.dump"); - dumpFile.val(hide.Ide.inst.projectDir + "/hlprofile.dump"); + panel.sendCommand("profCpu", { action : "dump" }, function(r) { + var dir = (panel.peerCwd ?? hide.Ide.inst.projectDir) + "/"; + var file = "hlprofile.dump"; + panel.log('Profil raw dump saved to $file'); + #if (hashlink >= "1.15.0") + try { + var outfile = "hlprofile.json"; + hlprof.ProfileGen.run([dir + file, "-o", dir + outfile]); + panel.log('Profil converted dump saved to $outfile'); + file = outfile; + } catch (e) { + panel.log(e.message, true); + } + #else + panel.log("Please use hlpro.ProfileGen to convert it to json, or compile hide with lib hashlink >= 1.15.0"); + #end + dumpFile.val(dir + file); }); }); var openBtn = new Element('').appendTo(subcmd); @@ -367,33 +407,6 @@ class RemoteConsoleCommandProf extends RemoteConsoleCommand { panel.log('File $dumpfile does not exist', true); } }); - #if (hashlink >= "1.15.0") - var subcmd = new Element('
').appendTo(element); - var convertBtn = new Element('').appendTo(subcmd); - var jsonFile = new Element('').appendTo(subcmd); - convertBtn.on('click', function(e) { - var file = dumpFile.val(); - if( file.length < 0 ) - file = hide.Ide.inst.projectDir + "/hlprofile.dump"; - var outfile = hide.Ide.inst.projectDir + "/hlprofile.json"; - jsonFile.val(outfile); - try { - hlprof.ProfileGen.run([file, "-o", outfile]); - panel.log("Profil converted dump saved to hlprofile.json"); - } catch (e) { - panel.log(e.message, true); - } - }); - var openBtn = new Element('').appendTo(subcmd); - openBtn.on('click', function(e) { - var jsonfile = jsonFile.val(); - if( jsonfile.length > 0 && sys.FileSystem.exists(jsonfile) ) { - hide.Ide.showFileInExplorer(jsonfile); - } else { - panel.log('File $jsonfile does not exist', true); - } - }); - #end } static var _ = RemoteConsoleView.registerCommandView("prof", RemoteConsoleCommandProf); } diff --git a/hrt/impl/RemoteConsole.hx b/hrt/impl/RemoteConsole.hx index 8a63adf6..f7d62deb 100644 --- a/hrt/impl/RemoteConsole.hx +++ b/hrt/impl/RemoteConsole.hx @@ -80,10 +80,8 @@ class RemoteConsole { sock.close(); sock = null; } - if( connections != null ) { - for( s in connections ) - s.close(); - } + for( s in connections ) + s.close(); connections = []; onClose(); } @@ -277,50 +275,147 @@ class RemoteConsoleConnection { log("[>] " + args); } - @cmd function cwd() { - return Sys.getCwd(); + @cmd("logError") function logErrorCmd( args : Dynamic ) { + logError("[>] " + args); + } + + function sendLogError( msg : String ) { + sendCommand("logError", msg); } - @cmd function programPath() { - return Sys.programPath(); + @cmd function info() { + return { + programPath : Sys.programPath(), + args : Sys.args(), + cwd : Sys.getCwd(), + }; } #if editor - @cmd function open( args : { file : String, line : Int, column : Int, cdbsheet : String } ) { + // ----- Hide ------ + + var parser : hscript.Parser; + @cmd function open( args : { file : String, ?line : Int, ?column : Int, ?cdbsheet : String, + ?selectExpr : String } ) { if( args == null ) return; + if( parser == null ) { + parser = new hscript.Parser(); + parser.identChars += "$"; + } if( args.cdbsheet != null ) { var sheet = hide.Ide.inst.database.getSheet(args.cdbsheet); hide.Ide.inst.open("hide.view.CdbTable", {}, null, function(view) { hide.Ide.inst.focus(); - Std.downcast(view,hide.view.CdbTable).goto(sheet,args.line,args.column); + Std.downcast(view, hide.view.CdbTable).goto(sheet, args.line, args.column); }); } else { hide.Ide.inst.showFileInResources(args.file); hide.Ide.inst.openFile(args.file, null, function(view) { hide.Ide.inst.focus(); - var domkit = Std.downcast(view, hide.view.Domkit); - if (domkit != null && args.line != null) { - @:privateAccess domkit.cssEditor.focus(); - @:privateAccess domkit.cssEditor.editor.setPosition({column: args.column, lineNumber: args.line+1}); + var domkitView = Std.downcast(view, hide.view.Domkit); + if( domkitView != null ) { + @:privateAccess domkitView.cssEditor.focus(); + @:privateAccess domkitView.cssEditor.editor.setPosition({column: args.column??0, lineNumber: (args.line??0)+1}); + } + if( args.selectExpr != null ) { + var sceneEditor : hide.comp.SceneEditor = null; + var prefabView = Std.downcast(view, hide.view.Prefab); + if( prefabView != null ) { + sceneEditor = prefabView.sceneEditor; + } + var fxView = Std.downcast(view, hide.view.FXEditor); + if( fxView != null ) { + @:privateAccess sceneEditor = fxView.sceneEditor; + } + var modelView = Std.downcast(view, hide.view.Model); + if( modelView != null ) { + @:privateAccess sceneEditor = modelView.sceneEditor; + } + if( sceneEditor != null ) { + try { + var expr = parser.parseString(args.selectExpr); + @:privateAccess var objs = sceneEditor.sceneData.findAll(null, function(o) { + return evalExpr(o, expr); + }); + sceneEditor.selectElements(objs); + } catch( e ) { + hide.Ide.inst.quickError(e); + } + } } }); } } + + function evalExpr( o : Dynamic, e : hscript.Expr ) : Dynamic { + switch( e.e ) { + case EConst(c): + switch( c ) { + case CInt(v): return v; + case CFloat(f): return f; + case CString(s): return s; + } + case EIdent("$"): + return o; + case EIdent(v): + return v; // Unknown ident, consider as a String literal + case EField(e, f): + var v = evalExpr(o, e); + return Reflect.field(v, f); + case EBinop(op, e1, e2): + var v1 = evalExpr(o, e1); + var v2 = evalExpr(o, e2); + switch( op ) { + case "==": return Reflect.compare(v1, v2) == 0; + default: + throw "Can't eval " + Std.string(v1) + " " + op + " " + Std.string(v2); + } + default: + throw "Unsupported expression " + hscript.Printer.toString(e); + } + } #end #if hl - @cmd function dump( args : { file : String } ) { + // ----- Hashlink ------ + + @cmd function gcMajor() : Int { + var start = haxe.Timer.stamp(); + hl.Gc.major(); + var duration_us = (haxe.Timer.stamp() - start) * 1_000_000.; + return Std.int(duration_us); + } + + @cmd function dumpMemory( args : { file : String } ) { hl.Gc.major(); hl.Gc.dumpMemory(args?.file); if( hxd.res.Resource.LIVE_UPDATE ) { var msg = "hxd.res.Resource.LIVE_UPDATE is on, you may want to disable it for mem dumps; RemoteConsole can also impact memdumps."; logError(msg); - sendCommand("log", msg); + sendLogError(msg); + } + } + + @cmd function liveObjects( args : { clname : String } ) : Int { + if( args == null || args.clname == null ) + return -1; + #if( hl_ver >= version("1.15.0") && haxe >= version("5.0.0-alpha.1") ) + hl.Gc.major(); + var cl = std.Type.resolveClass(args.clname); + if( cl == null ) { + sendLogError('Failed to find class for ${args.clname}'); + return -1; } + var c = hl.Gc.getLiveObjects(cl, 0); + return c.count; + #else + sendLogError("getLiveObjects not supported, please use hl >= 1.15.0 and haxe >= 5.0.0"); + return -1; + #end } - @cmd function prof( args : { action : String, samples : Int, delay_ms : Int }, onDone : Dynamic -> Void ) { + @cmd function profCpu( args : { action : String, samples : Int, delay_ms : Int }, onDone : Dynamic -> Void ) { function doProf( args ) { switch( args.action ) { case "start": @@ -336,7 +431,7 @@ class RemoteConsoleConnection { hl.Profile.event(-4); // pause all hl.Profile.event(-3); // clear data default: - sendCommand("log", "Missing argument action for prof"); + sendLogError('profCpu: action ${args?.action} not supported'); } } if( args == null ) { diff --git a/hrt/impl/RemoteTools.hx b/hrt/impl/RemoteTools.hx index 6b78012d..5b87002a 100644 --- a/hrt/impl/RemoteTools.hx +++ b/hrt/impl/RemoteTools.hx @@ -71,4 +71,13 @@ class RemoteTools { rc?.sendCommand("open", { file : file, line : line, column : column }); } + /** + @param selectExpr hscript expression that are used for select some elements in the view. + Example: `$.name == SomeName`, `$.props.id == Some_Unique_Id` + (`"` can be omitted in String literal when no ambiguity). + */ + public static function openPrefab( file : String, ?selectExpr : String ) { + rc?.sendCommand("open", { file : file, selectExpr : selectExpr }); + } + }