Эх сурвалжийг харах

Work on jumping to the the editor and line as you step through the code with the debugger. Prep for moving the duktape debugger ui into it’s own panel so that pause, step over, step into, and step out bring up the proper editors.

Shaddock Heath 8 жил өмнө
parent
commit
bda9cb6bbc

+ 1 - 0
Script/AtomicEditor/editor/EditorEvents.ts

@@ -26,3 +26,4 @@ export const IPCPlayerExitRequestEventType: Atomic.EventType = "IPCPlayerExitReq
 export const IPCPlayerWindowChangedEventType: Atomic.EventType = "IPCPlayerWindowChanged";
 export const IPCPlayerWindowChangedEventType: Atomic.EventType = "IPCPlayerWindowChanged";
 export const IPCPlayerPauseResumeRequestEventType: Atomic.EventType = "IPCPlayerPauseResumeRequest";
 export const IPCPlayerPauseResumeRequestEventType: Atomic.EventType = "IPCPlayerPauseResumeRequest";
 export const IPCPlayerPauseStepRequestEventType: Atomic.EventType = "IPCPlayerPauseStepRequest";
 export const IPCPlayerPauseStepRequestEventType: Atomic.EventType = "IPCPlayerPauseStepRequest";
+export const IPCPlayerUpdatesPausedResumedEventType: Atomic.EventType = "IPCPlayerUpdatesPausedResumed";

+ 87 - 7
Script/AtomicEditor/hostExtensions/coreExtensions/DuktapeDebuggerExtension.ts

@@ -19,6 +19,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 // THE SOFTWARE.
 //
 //
+import EditorEvents = require("../../editor/EditorEvents");
 
 
 export interface Breakpoint {
 export interface Breakpoint {
     fileName: string;
     fileName: string;
@@ -87,6 +88,10 @@ interface ClientProxyMappings {
     toggleBreakpoint: string;
     toggleBreakpoint: string;
     addBreakpoint: string;
     addBreakpoint: string;
     removeBreakpoint: string;
     removeBreakpoint: string;
+    pause: string;
+    step: string;
+    resume: string;
+    stop: string;
 }
 }
 
 
 interface ClientListener {
 interface ClientListener {
@@ -95,6 +100,8 @@ interface ClientListener {
     callbacks: ClientProxyMappings;
     callbacks: ClientProxyMappings;
 }
 }
 
 
+const DUKTAPE_DEBUGGER_NAME = "Duktape Debugger";
+
 /**
 /**
  * extension that will communicate with the duktape debugger
  * extension that will communicate with the duktape debugger
  */
  */
@@ -117,6 +124,29 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
         serviceLocator.projectServices.register(this);
         serviceLocator.projectServices.register(this);
         serviceLocator.uiServices.register(this);
         serviceLocator.uiServices.register(this);
         this.serviceRegistry = serviceLocator;
         this.serviceRegistry = serviceLocator;
+
+        this.subscribeToEvent(Editor.EditorResourceCloseEvent((data) => this.handleResourceClosedEvent(data)));
+        this.subscribeToEvent(Editor.EditorPlayerPausedEvent((data) => this.handlePause()));
+        this.subscribeToEvent(Editor.EditorPlayerResumedEvent((data) => this.handleResume()));
+        this.subscribeToEvent(Editor.EditorPlayerStoppedEvent((data) => this.handleStop()));
+        //this.subscribeToEvent(Atomic.PauseStepRequestedEvent((data) => console.log("step")));
+        //this.subscribeToEvent(Atomic.PauseResumeRequestedEvent((data) => console.log("step resume")));
+
+
+        //this.subscribeToEvent(Atomic.ScriptEvent(EditorEvents.IPCPlayerPauseResumeRequestEventType, (data) => console.log("step resume")));
+        this.subscribeToEvent(Atomic.ScriptEvent(EditorEvents.IPCPlayerPauseStepRequestEventType, (data) => this.handleStep()));
+
+
+    }
+
+    handleResourceClosedEvent(data: Editor.EditorResourceCloseEvent) {
+        // Remove the editor we are listening to
+        this.listeners = this.listeners.filter(l => {
+            if (data.editor.fullPath.lastIndexOf(l.name) == data.editor.fullPath.length - l.name.length) {
+                return false;
+            }
+            return true;
+        });
     }
     }
 
 
     /**
     /**
@@ -127,11 +157,11 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
     handleWebMessage(webMessage: WebView.WebMessageEvent, messageType: string, data: any) {
     handleWebMessage(webMessage: WebView.WebMessageEvent, messageType: string, data: any) {
         switch (messageType) {
         switch (messageType) {
             case "Debugger.AddBreakpoint":
             case "Debugger.AddBreakpoint":
-                this.addBreakpoint(data);
+                this.addBreakpoint(data, webMessage.handler.webClient);
                 this.webMessageEventResponse(webMessage);
                 this.webMessageEventResponse(webMessage);
                 break;
                 break;
             case "Debugger.RemoveBreakpoint":
             case "Debugger.RemoveBreakpoint":
-                this.removeBreakpoint(data);
+                this.removeBreakpoint(data, webMessage.handler.webClient);
                 this.webMessageEventResponse(webMessage);
                 this.webMessageEventResponse(webMessage);
                 break;
                 break;
             case "Debugger.ToggleBreakpoint":
             case "Debugger.ToggleBreakpoint":
@@ -149,6 +179,10 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
                 this.registerDebuggerListener(webMessage, data);
                 this.registerDebuggerListener(webMessage, data);
                 this.webMessageEventResponse(webMessage);
                 this.webMessageEventResponse(webMessage);
                 break;
                 break;
+            case "Debugger.CurrentSourcePosition":
+                this.setCurrentSourcePosition(data);
+                this.webMessageEventResponse(webMessage);
+                break;
         }
         }
     }
     }
 
 
@@ -181,10 +215,10 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
         this.listeners = this.listeners.filter(l => l.frame);
         this.listeners = this.listeners.filter(l => l.frame);
     }
     }
 
 
-    addBreakpoint(bp: Breakpoint) {
+    addBreakpoint(bp: Breakpoint, sender: WebView.WebClient) {
         this.breakpointList.addBreakpoint(bp.fileName, bp.lineNumber);
         this.breakpointList.addBreakpoint(bp.fileName, bp.lineNumber);
         for (let listener of this.listeners) {
         for (let listener of this.listeners) {
-            if (listener.frame) {
+            if (listener.frame && listener.frame != sender) {
                 console.log(`Adding breakpoint ${bp.fileName}:${bp.lineNumber} to ${listener.name}`);
                 console.log(`Adding breakpoint ${bp.fileName}:${bp.lineNumber} to ${listener.name}`);
                 this.proxyWebClientMethod(
                 this.proxyWebClientMethod(
                     listener.frame,
                     listener.frame,
@@ -196,10 +230,10 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
         }
         }
     }
     }
 
 
-    removeBreakpoint(bp: Breakpoint) {
+    removeBreakpoint(bp: Breakpoint, sender: WebView.WebClient) {
         this.breakpointList.removeBreakpoint(bp.fileName, bp.lineNumber);
         this.breakpointList.removeBreakpoint(bp.fileName, bp.lineNumber);
         for (let listener of this.listeners) {
         for (let listener of this.listeners) {
-            if (listener.frame) {
+            if (listener.frame && listener.frame != sender) {
                 console.log(`Remove breakpoint ${bp.fileName}:${bp.lineNumber} to ${listener.name}`);
                 console.log(`Remove breakpoint ${bp.fileName}:${bp.lineNumber} to ${listener.name}`);
                 this.proxyWebClientMethod(
                 this.proxyWebClientMethod(
                     listener.frame,
                     listener.frame,
@@ -226,9 +260,48 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
         }
         }
     }
     }
 
 
+    handleResume() {
+        for (let listener of this.listeners) {
+            if (listener.frame && listener.name == DUKTAPE_DEBUGGER_NAME) {
+                console.log(`Sending Pause to ${listener.name}`);
+                this.proxyWebClientMethod(
+                    listener.frame,
+                    listener.callbacks.resume);
+            }
+        }
+    }
+
+    handlePause() {
+        for (let listener of this.listeners) {
+            if (listener.frame && listener.name == DUKTAPE_DEBUGGER_NAME) {
+                console.log(`Sending Pause to ${listener.name}`);
+                this.proxyWebClientMethod(
+                    listener.frame,
+                    listener.callbacks.pause);
+            }
+        }
+    }
 
 
-    resume() {
+    handleStep() {
+        for (let listener of this.listeners) {
+            if (listener.frame && listener.name == DUKTAPE_DEBUGGER_NAME) {
+                console.log(`Sending Pause to ${listener.name}`);
+                this.proxyWebClientMethod(
+                    listener.frame,
+                    listener.callbacks.step);
+            }
+        }
+    }
 
 
+    handleStop() {
+        for (let listener of this.listeners) {
+            if (listener.frame && listener.name == DUKTAPE_DEBUGGER_NAME) {
+                console.log(`Sending Pause to ${listener.name}`);
+                this.proxyWebClientMethod(
+                    listener.frame,
+                    listener.callbacks.stop);
+            }
+        }
     }
     }
 
 
     attach() {
     attach() {
@@ -239,6 +312,13 @@ export default class DuktapeDebuggerExtension extends Atomic.ScriptObject implem
 
 
     }
     }
 
 
+    setCurrentSourcePosition(bp: Breakpoint) {
+        console.log(`Trying to open: ${bp.fileName}:${bp.lineNumber}`);
+        this.sendEvent(Editor.EditorEditResourceEventData({
+            path: bp.fileName,
+            lineNumber: bp.lineNumber
+        }));
+    }
     /**
     /**
      * Utility function that will compose a method call to the web client and execute it
      * Utility function that will compose a method call to the web client and execute it
      * It will construct it in the form of "MethodName(....);"
      * It will construct it in the form of "MethodName(....);"

+ 1 - 2
Script/AtomicEditor/ui/frames/ResourceFrame.ts

@@ -144,12 +144,11 @@ class ResourceFrame extends ScriptWidget {
     }
     }
 
 
     /**
     /**
-     * 
      * Set the cursor to the correct line number in the editor
      * Set the cursor to the correct line number in the editor
      * @param {Editor.ResourceEditor} editor
      * @param {Editor.ResourceEditor} editor
      * @param {any} [lineNumber=-1]
      * @param {any} [lineNumber=-1]
      * @param {any} [tokenPos=-1]
      * @param {any} [tokenPos=-1]
-     * 
+     *
      * @memberOf ResourceFrame
      * @memberOf ResourceFrame
      */
      */
     setCursorPositionInEditor(editor: Editor.ResourceEditor, lineNumber = -1, tokenPos = -1) {
     setCursorPositionInEditor(editor: Editor.ResourceEditor, lineNumber = -1, tokenPos = -1) {

+ 37 - 41
Script/AtomicWebViewEditor/debugger/DuktapeDebugger.ts

@@ -134,6 +134,7 @@ export default class DuktapeDebugger {
 
 
         this.editor.revealLineInCenterIfOutsideViewport(reqLine);
         this.editor.revealLineInCenterIfOutsideViewport(reqLine);
         this.editor.setPosition(new monaco.Position(reqLine, 0));
         this.editor.setPosition(new monaco.Position(reqLine, 0));
+        debuggerProxy.notifyHostCurrentSourcePosition("Resources/" + this.loadedFileName, reqLine);
     }
     }
 
 
     /*
     /*
@@ -289,6 +290,32 @@ export default class DuktapeDebugger {
         }
         }
     }
     }
 
 
+    pause() {
+        this.socket.emit("pause", {});
+
+        // Pause may take seconds to complete so indicate it is pending.
+        $("#pause-button").addClass("pending");
+    }
+
+    resume() {
+        this.socket.emit("resume", {});
+    }
+
+    stepInto() {
+        this.socket.emit("stepinto", {});
+        setTimeout(() => this.doSourceUpdate(), 125);
+    }
+
+    stepOut() {
+        this.socket.emit("stepout", {});
+        setTimeout(() => this.doSourceUpdate(), 125);
+    }
+
+    stepOver() {
+        this.socket.emit("stepover", {});
+        setTimeout(() => this.doSourceUpdate(), 125);
+    }
+
     initSocket() {
     initSocket() {
         /*
         /*
          *  Init socket.io and add handlers
          *  Init socket.io and add handlers
@@ -532,28 +559,11 @@ export default class DuktapeDebugger {
             this.bytecodeIdxInstr = msg.idxPreformattedInstructions;
             this.bytecodeIdxInstr = msg.idxPreformattedInstructions;
         });
         });
 
 
-        $("#stepinto-button").click(() => {
-            this.socket.emit("stepinto", {});
-        });
-
-        $("#stepover-button").click(() => {
-            this.socket.emit("stepover", {});
-        });
-
-        $("#stepout-button").click(() => {
-            this.socket.emit("stepout", {});
-        });
-
-        $("#pause-button").click(() => {
-            this.socket.emit("pause", {});
-
-            // Pause may take seconds to complete so indicate it is pending.
-            $("#pause-button").addClass("pending");
-        });
-
-        $("#resume-button").click(() => {
-            this.socket.emit("resume", {});
-        });
+        $("#stepinto-button").click(() => this.stepInto());
+        $("#stepover-button").click(() => this.stepOver());
+        $("#stepout-button").click(() => this.stepOut());
+        $("#pause-button").click(() => this.pause());
+        $("#resume-button").click(() => this.resume());
 
 
         $("#attach-button").click(() => {
         $("#attach-button").click(() => {
             this.socket.emit("attach", {});
             this.socket.emit("attach", {});
@@ -619,18 +629,6 @@ export default class DuktapeDebugger {
 
 
 
 
     setSourceText(data) {
     setSourceText(data) {
-        /* TSH
-        var elem, div;
-
-        elem = $("#source-code");
-        elem.empty();
-        data.split("\n").forEach(function (line) {
-            div = $("<div></div>");
-            div.text(line);
-            elem.append(div);
-        });
-        */
-
         this.editor.deltaDecorations([], []);
         this.editor.deltaDecorations([], []);
         this.editor.getModel().setValue(data);
         this.editor.getModel().setValue(data);
         this.sourceEditedLines = [];
         this.sourceEditedLines = [];
@@ -640,12 +638,6 @@ export default class DuktapeDebugger {
      *  AJAX request handling to fetch source files
      *  AJAX request handling to fetch source files
      */
      */
     requestSourceFile(fileName: string, lineNumber: number) {
     requestSourceFile(fileName: string, lineNumber: number) {
-        // If previous update is pending, abort and start a new one.
-        if (this.sourceFetchXhr) {
-            this.sourceFetchXhr.abort();
-            this.sourceFetchXhr = null;
-        }
-
         console.log(`Retrieving File: ${fileName}`);
         console.log(`Retrieving File: ${fileName}`);
         // get the code
         // get the code
         return HostInteropType.getInstance().getFileResource("Resources/" + fileName).then((data: string) => {
         return HostInteropType.getInstance().getFileResource("Resources/" + fileName).then((data: string) => {
@@ -749,7 +741,7 @@ export default class DuktapeDebugger {
 
 
         // Source is updated periodically.  Other code can also call doSourceUpdate()
         // Source is updated periodically.  Other code can also call doSourceUpdate()
         // directly if an immediate update is needed.
         // directly if an immediate update is needed.
-        this.sourceUpdateInterval = setInterval(this.doSourceUpdate.bind(this), this.SOURCE_UPDATE_INTERVAL);
+        // this.sourceUpdateInterval = setInterval(this.doSourceUpdate.bind(this), this.SOURCE_UPDATE_INTERVAL);
         this.editor.onMouseMove((e) => {
         this.editor.onMouseMove((e) => {
             var targetZone = e.target.toString();
             var targetZone = e.target.toString();
             if (targetZone.indexOf("GUTTER_GLYPH_MARGIN") != -1) {
             if (targetZone.indexOf("GUTTER_GLYPH_MARGIN") != -1) {
@@ -856,6 +848,10 @@ export default class DuktapeDebugger {
             debuggerProxy.debuggerHostKeys.removeBreakpoint,
             debuggerProxy.debuggerHostKeys.removeBreakpoint,
             this.removeBreakpoint.bind(this));
             this.removeBreakpoint.bind(this));
 
 
+        interop.addCustomHostRoutine(
+            debuggerProxy.debuggerHostKeys.pause,
+            this.pause.bind(this));
+
         debuggerProxy.registerDebuggerListener("DuktapeDebugger");
         debuggerProxy.registerDebuggerListener("DuktapeDebugger");
     }
     }
 
 

+ 19 - 3
Script/AtomicWebViewEditor/debugger/HostDebuggerExtensionProxy.ts

@@ -9,7 +9,7 @@ export interface Breakpoint {
  * Get a list of all breakpoints that have been registered
  * Get a list of all breakpoints that have been registered
  * @return {Breakpoint[]}
  * @return {Breakpoint[]}
  */
  */
-export async function getBreakpoints() : Promise<Breakpoint[]> {
+export async function getBreakpoints(): Promise<Breakpoint[]> {
     return atomicHostRequest<Breakpoint[]>("Debugger.GetBreakpoints");
     return atomicHostRequest<Breakpoint[]>("Debugger.GetBreakpoints");
 }
 }
 
 
@@ -59,7 +59,11 @@ export async function removeAllBreakpoints() {
 export const debuggerHostKeys = {
 export const debuggerHostKeys = {
     toggleBreakpoint: "HOST_DEBUGGER_ToggleBreakpoint",
     toggleBreakpoint: "HOST_DEBUGGER_ToggleBreakpoint",
     addBreakpoint: "HOST_DEBUGGER_AddBreakpoint",
     addBreakpoint: "HOST_DEBUGGER_AddBreakpoint",
-    removeBreakpoint: "HOST_DEBUGGER_RemoveBreakpoint"
+    removeBreakpoint: "HOST_DEBUGGER_RemoveBreakpoint",
+    pause: "HOST_DEBUGGER_Pause",
+    step: "HOST_DEBUGGER_Step",
+    resume: "HOST_DEBUGGER_Resume",
+    stop: "HOST_DEBUGGER_Stop"
 };
 };
 
 
 /**
 /**
@@ -68,9 +72,21 @@ export const debuggerHostKeys = {
  * host initiated debugger messages
  * host initiated debugger messages
  * @param {string} name The name associated with the listener.  Ususally the filename.
  * @param {string} name The name associated with the listener.  Ususally the filename.
  */
  */
-export function  registerDebuggerListener(name: string) {
+export function registerDebuggerListener(name: string) {
     atomicHostEvent("Debugger.RegisterDebuggerListener", {
     atomicHostEvent("Debugger.RegisterDebuggerListener", {
         name,
         name,
         callbacks: debuggerHostKeys
         callbacks: debuggerHostKeys
     });
     });
 }
 }
+
+/**
+ * Notify the host of the current line number and source file.  Used during pause, step, etc.
+ * @param  {string} fileName
+ * @param  {number} lineNumber
+ */
+export async function notifyHostCurrentSourcePosition(fileName: string, lineNumber: number) {
+    return atomicHostEvent("Debugger.CurrentSourcePosition", {
+        fileName,
+        lineNumber
+    });
+}

+ 1 - 4
Source/AtomicEditor/Editors/JSResourceEditor.cpp

@@ -131,7 +131,6 @@ void JSResourceEditor::HandleWebMessage(StringHash eventType, VariantMap& eventD
         String message = jvalue["message"].GetString();
         String message = jvalue["message"].GetString();
         if (message == EDITOR_CHANGE) {
         if (message == EDITOR_CHANGE) {
             SetModified(true);
             SetModified(true);
-            handler->Success();
         }
         }
         else if (message == EDITOR_SAVE_CODE)
         else if (message == EDITOR_SAVE_CODE)
         {
         {
@@ -139,7 +138,6 @@ void JSResourceEditor::HandleWebMessage(StringHash eventType, VariantMap& eventD
             File file(context_, fullpath_, FILE_WRITE);
             File file(context_, fullpath_, FILE_WRITE);
             file.Write((void*) code.CString(), code.Length());
             file.Write((void*) code.CString(), code.Length());
             file.Close();
             file.Close();
-            handler->Success();
         }
         }
         else if (message == EDITOR_SAVE_FILE)
         else if (message == EDITOR_SAVE_FILE)
         {
         {
@@ -160,11 +158,10 @@ void JSResourceEditor::HandleWebMessage(StringHash eventType, VariantMap& eventD
             } else {
             } else {
                 ATOMIC_LOGWARNING("Ignoring attempt to write file: " + fn);
                 ATOMIC_LOGWARNING("Ignoring attempt to write file: " + fn);
             }
             }
-            handler->Success();
         }
         }
     }
     }
 
 
-
+    handler->Success();
 }
 }
 
 
 void JSResourceEditor::FormatCode()
 void JSResourceEditor::FormatCode()