Reviewed by Eric.
authorthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Jul 2006 08:20:46 +0000 (08:20 +0000)
committerthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Jul 2006 08:20:46 +0000 (08:20 +0000)
        Bug 9631: [Drosera] Add "Step Over" and "Step Out"
        http://bugzilla.opendarwin.org/show_bug.cgi?id=9631

        Adds step over and step out. Along with a little code cleanup
        that was minor enough to piggyback on this fix.

        * Drosera/DebuggerDocument.h:
        * Drosera/DebuggerDocument.m:
        (-[DebuggerDocument stepOver:]):
        (-[DebuggerDocument stepOut:]):
        (-[DebuggerDocument windowDidLoad]):
        (-[DebuggerDocument windowWillClose:]):
        (-[DebuggerDocument toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:]):
        (-[DebuggerDocument toolbarDefaultItemIdentifiers:]):
        (-[DebuggerDocument toolbarAllowedItemIdentifiers:]):
        (-[DebuggerDocument validateUserInterfaceItem:]):
        * Drosera/Drosera.xcodeproj/project.pbxproj:
        * Drosera/debugger.html:
        * Drosera/debugger.js:
        * Drosera/viewer.css:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15144 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitTools/ChangeLog
WebKitTools/Drosera/DebuggerDocument.h
WebKitTools/Drosera/DebuggerDocument.m
WebKitTools/Drosera/Drosera.xcodeproj/project.pbxproj
WebKitTools/Drosera/Images/stepOut.tif [new file with mode: 0644]
WebKitTools/Drosera/debugger.html
WebKitTools/Drosera/debugger.js
WebKitTools/Drosera/viewer.css

index 529dd16..1667cd7 100644 (file)
@@ -2,6 +2,31 @@
 
         Reviewed by Eric.
 
+        Bug 9631: [Drosera] Add "Step Over" and "Step Out"
+        http://bugzilla.opendarwin.org/show_bug.cgi?id=9631
+        
+        Adds step over and step out. Along with a little code cleanup
+        that was minor enough to piggyback on this fix.
+
+        * Drosera/DebuggerDocument.h:
+        * Drosera/DebuggerDocument.m:
+        (-[DebuggerDocument stepOver:]):
+        (-[DebuggerDocument stepOut:]):
+        (-[DebuggerDocument windowDidLoad]):
+        (-[DebuggerDocument windowWillClose:]):
+        (-[DebuggerDocument toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:]):
+        (-[DebuggerDocument toolbarDefaultItemIdentifiers:]):
+        (-[DebuggerDocument toolbarAllowedItemIdentifiers:]):
+        (-[DebuggerDocument validateUserInterfaceItem:]):
+        * Drosera/Drosera.xcodeproj/project.pbxproj:
+        * Drosera/debugger.html:
+        * Drosera/debugger.js:
+        * Drosera/viewer.css:
+
+2006-07-02  Timothy Hatcher  <timothy@apple.com>
+
+        Reviewed by Eric.
+
         Bug 9628: [Drosera] Split Views acting oddly
         http://bugzilla.opendarwin.org/show_bug.cgi?id=9628
         
index dcff74e..8ea65db 100644 (file)
@@ -41,4 +41,6 @@
 - (IBAction)pause:(id)sender;
 - (IBAction)resume:(id)sender;
 - (IBAction)stepInto:(id)sender;
+- (IBAction)stepOver:(id)sender;
+- (IBAction)stepOut:(id)sender;
 @end
index 512f823..e5721bf 100644 (file)
  */
 
 #import "DebuggerDocument.h"
+#import "DebuggerApplication.h"
 
 static NSString *DebuggerContinueToolbarItem = @"DebuggerContinueToolbarItem";
 static NSString *DebuggerPauseToolbarItem = @"DebuggerPauseToolbarItem";
 static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
+static NSString *DebuggerStepOverToolbarItem = @"DebuggerStepOverToolbarItem";
+static NSString *DebuggerStepOutToolbarItem = @"DebuggerStepOutToolbarItem";
 
 @implementation DebuggerDocument
 + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
@@ -136,6 +139,16 @@ static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
     [[webView windowScriptObject] callWebScriptMethod:@"stepInto" withArguments:nil];
 }
 
+- (IBAction)stepOver:(id)sender
+{
+    [[webView windowScriptObject] callWebScriptMethod:@"stepOver" withArguments:nil];
+}
+
+- (IBAction)stepOut:(id)sender
+{
+    [[webView windowScriptObject] callWebScriptMethod:@"stepOut" withArguments:nil];
+}
+
 #pragma mark -
 #pragma mark Window Controller Overrides
 
@@ -150,7 +163,7 @@ static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
 
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationTerminating:) name:NSApplicationWillTerminateNotification object:nil];
 
-    NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"debugger" ofType:@"html" inDirectory:nil];
+    NSString *path = [[NSBundle mainBundle] pathForResource:@"debugger" ofType:@"html" inDirectory:nil];
     [[webView mainFrame] loadRequest:[[[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]] autorelease]];
 
     NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"debugger"];
@@ -166,8 +179,6 @@ static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
     [[webView windowScriptObject] removeWebScriptKey:@"DebuggerDocument"];
 
     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:nil];
-    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:WebScriptDebugServerQueryReplyNotification object:nil];
-    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:WebScriptDebugServerWillUnloadNotification object:nil];
 
     [self switchToServerNamed:nil];
 
@@ -269,6 +280,32 @@ static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
         [item setAction:@selector(stepInto:)];
 
         return [item autorelease];
+    } else if ([itemIdentifier isEqualToString:DebuggerStepOverToolbarItem]) {
+        NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+
+        [item setLabel:@"Step Over"];
+        [item setPaletteLabel:@"Step Over"];
+
+        [item setToolTip:@"Step over function call"];
+        [item setImage:[NSImage imageNamed:@"stepOver"]];
+
+        [item setTarget:self];
+        [item setAction:@selector(stepOver:)];
+
+        return [item autorelease];
+    } else if ([itemIdentifier isEqualToString:DebuggerStepOutToolbarItem]) {
+        NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+
+        [item setLabel:@"Step Out"];
+        [item setPaletteLabel:@"Step Over"];
+
+        [item setToolTip:@"Step out of current function"];
+        [item setImage:[NSImage imageNamed:@"stepOut"]];
+
+        [item setTarget:self];
+        [item setAction:@selector(stepOut:)];
+
+        return [item autorelease];
     }
 
     return nil;
@@ -277,23 +314,26 @@ static NSString *DebuggerStepIntoToolbarItem = @"DebuggerStepIntoToolbarItem";
 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
 {
     return [NSArray arrayWithObjects:DebuggerContinueToolbarItem, DebuggerPauseToolbarItem,
-        NSToolbarSeparatorItemIdentifier, DebuggerStepIntoToolbarItem, nil];
+        NSToolbarSeparatorItemIdentifier, DebuggerStepIntoToolbarItem, DebuggerStepOutToolbarItem,
+        DebuggerStepOverToolbarItem, nil];
 }
 
 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
 {
-    return [NSArray arrayWithObjects:DebuggerContinueToolbarItem, DebuggerPauseToolbarItem, DebuggerStepIntoToolbarItem,
-        NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
-        NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
+    return [NSArray arrayWithObjects:DebuggerContinueToolbarItem, DebuggerPauseToolbarItem,
+        DebuggerStepIntoToolbarItem, DebuggerStepOutToolbarItem, DebuggerStepOverToolbarItem, NSToolbarCustomizeToolbarItemIdentifier,
+        NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
 }
 
 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)interfaceItem
 {
-    if ([interfaceItem action] == @selector(pause:))
+    SEL action = [interfaceItem action];
+    if (action == @selector(pause:))
         return ![self isPaused];
-    if ([interfaceItem action] == @selector(resume:))
-        return [self isPaused];
-    if ([interfaceItem action] == @selector(stepInto:))
+    if (action == @selector(resume:) ||
+        action == @selector(stepOver:) ||
+        action == @selector(stepOut:) ||
+        action == @selector(stepInto:))
         return [self isPaused];
     return YES;
 }
index 988a367..25c05d0 100644 (file)
@@ -21,6 +21,7 @@
                1C4FF94E0A45F5060000D05D /* popUpArrows.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C4FF94D0A45F5060000D05D /* popUpArrows.png */; };
                1C4FFE5E0A466F5D0000D05D /* programCounterBreakPoint.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1C4FFE5C0A466F5D0000D05D /* programCounterBreakPoint.tif */; };
                1C4FFE5F0A466F5D0000D05D /* programCounterBreakPointDisabled.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1C4FFE5D0A466F5D0000D05D /* programCounterBreakPointDisabled.tif */; };
+               1C6F83FF0A58E97D004FCD89 /* stepOut.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1C6F83FE0A58E97D004FCD89 /* stepOut.tif */; };
                1C74F0350A47BF8300FEC632 /* viewer.html in Resources */ = {isa = PBXBuildFile; fileRef = 1C74F0340A47BF8300FEC632 /* viewer.html */; };
                1C74F04B0A47BFE800FEC632 /* viewer.css in Resources */ = {isa = PBXBuildFile; fileRef = 1C74F03A0A47BFD600FEC632 /* viewer.css */; };
                1C74F1850A47DEE600FEC632 /* DebuggerApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C74F1840A47DEE600FEC632 /* DebuggerApplication.m */; };
                1CC059170A44A210006FE533 /* splitterBar.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E10A44A210006FE533 /* splitterBar.tif */; };
                1CC059180A44A210006FE533 /* splitterDimple.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E20A44A210006FE533 /* splitterDimple.tif */; };
                1CC0591A0A44A210006FE533 /* continue.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E40A44A210006FE533 /* continue.tif */; };
-               1CC0591C0A44A210006FE533 /* finishFunction.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E60A44A210006FE533 /* finishFunction.tif */; };
                1CC0591D0A44A210006FE533 /* pause.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E70A44A210006FE533 /* pause.tif */; };
                1CC0591E0A44A210006FE533 /* run.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E80A44A210006FE533 /* run.tif */; };
                1CC0591F0A44A210006FE533 /* step.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058E90A44A210006FE533 /* step.tif */; };
                1CC059200A44A210006FE533 /* stepOver.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058EA0A44A210006FE533 /* stepOver.tif */; };
-               1CC059210A44A210006FE533 /* stop.tif in Resources */ = {isa = PBXBuildFile; fileRef = 1CC058EB0A44A210006FE533 /* stop.tif */; };
                1CC059700A44A485006FE533 /* toolbarBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = 1CC0596F0A44A485006FE533 /* toolbarBackground.png */; };
                1CD434B20A4B86F800A007AB /* glossyHeaderPressed.png in Resources */ = {isa = PBXBuildFile; fileRef = 1CD434B10A4B86F800A007AB /* glossyHeaderPressed.png */; };
                1CD8D5690A49041C00E5677B /* launcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CD8D5680A49041C00E5677B /* launcher.m */; };
@@ -82,6 +81,7 @@
                1C4FF94D0A45F5060000D05D /* popUpArrows.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = popUpArrows.png; sourceTree = "<group>"; };
                1C4FFE5C0A466F5D0000D05D /* programCounterBreakPoint.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = programCounterBreakPoint.tif; sourceTree = "<group>"; };
                1C4FFE5D0A466F5D0000D05D /* programCounterBreakPointDisabled.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = programCounterBreakPointDisabled.tif; sourceTree = "<group>"; };
+               1C6F83FE0A58E97D004FCD89 /* stepOut.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = stepOut.tif; sourceTree = "<group>"; };
                1C74F0340A47BF8300FEC632 /* viewer.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = viewer.html; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                1C74F03A0A47BFD600FEC632 /* viewer.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = viewer.css; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                1C74F1830A47DEE600FEC632 /* DebuggerApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerApplication.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                                1CC058E70A44A210006FE533 /* pause.tif */,
                                1CC058E80A44A210006FE533 /* run.tif */,
                                1CC058E90A44A210006FE533 /* step.tif */,
+                               1C6F83FE0A58E97D004FCD89 /* stepOut.tif */,
                                1CC058EA0A44A210006FE533 /* stepOver.tif */,
                                1CC058EB0A44A210006FE533 /* stop.tif */,
                                1CC0596F0A44A485006FE533 /* toolbarBackground.png */,
                                1CC059170A44A210006FE533 /* splitterBar.tif in Resources */,
                                1CC059180A44A210006FE533 /* splitterDimple.tif in Resources */,
                                1CC0591A0A44A210006FE533 /* continue.tif in Resources */,
-                               1CC0591C0A44A210006FE533 /* finishFunction.tif in Resources */,
                                1CC0591D0A44A210006FE533 /* pause.tif in Resources */,
                                1CC0591E0A44A210006FE533 /* run.tif in Resources */,
                                1CC0591F0A44A210006FE533 /* step.tif in Resources */,
                                1CC059200A44A210006FE533 /* stepOver.tif in Resources */,
-                               1CC059210A44A210006FE533 /* stop.tif in Resources */,
                                1CC059700A44A485006FE533 /* toolbarBackground.png in Resources */,
                                1C4FF7440A44F52C0000D05D /* debugger.css in Resources */,
                                1C4FF7540A44F6320000D05D /* gutter.png in Resources */,
                                1C2632D80A4AF0B800EA7CD8 /* SourceArrowBlank.png in Resources */,
                                1C2632DA0A4AF0D200EA7CD8 /* background_stripe.png in Resources */,
                                1CD434B20A4B86F800A007AB /* glossyHeaderPressed.png in Resources */,
+                               1C6F83FF0A58E97D004FCD89 /* stepOut.tif in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/WebKitTools/Drosera/Images/stepOut.tif b/WebKitTools/Drosera/Images/stepOut.tif
new file mode 100644 (file)
index 0000000..ff9e64b
Binary files /dev/null and b/WebKitTools/Drosera/Images/stepOut.tif differ
index 45dc9dd..466f0c4 100644 (file)
@@ -29,7 +29,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-    <title>JavaScript Debugger</title>
+    <title>Debugger</title>
     <script type="text/javascript" src="debugger.js"></script> 
     <style type="text/css">
         @import "debugger.css";
index 8093d30..8025ca8 100644 (file)
@@ -36,6 +36,10 @@ var previousFiles = new Array();
 var nextFiles = new Array();
 var isResizingColumn = false;
 var draggingBreakpoint = null;
+var steppingOut = false;
+var steppingOver = false;
+var steppingStack = 0;
+var pauseOnNextStatement = false;
 
 function sleep(numberMillis) {
     var now = new Date();
@@ -196,14 +200,40 @@ function resume()
         currentStack = null;
     }
 
+    pauseOnNextStatement = false;
+    steppingOut = false;
+    steppingOver = false;
+    steppingStack = 0;
+
     DebuggerDocument.resume();
 }
 
 function stepInto()
 {
+    pauseOnNextStatement = false;
+    steppingOut = false;
+    steppingOver = false;
+    steppingStack = 0;
     DebuggerDocument.stepInto();
 }
 
+function stepOver()
+{
+    pauseOnNextStatement = false;
+    steppingOver = true;
+    steppingStack = 0;
+    DebuggerDocument.resume();
+}
+
+function stepOut()
+{
+    pauseOnNextStatement = false;
+    steppingOver = false;
+    steppingStack = 0;
+    steppingOut = true;
+    DebuggerDocument.resume();
+}
+
 function hasStyleClass(element, className)
 {
     return ( element.className.indexOf(className) != -1 );
@@ -250,14 +280,17 @@ function moveBreakPoint(event)
         var sourcesDocument = document.getElementById("sources").contentDocument;
         sourcesDocument.addEventListener("mousemove", breakpointDrag, true);
         sourcesDocument.addEventListener("mouseup", breakpointDragEnd, true);
+        sourcesDocument.body.style.cursor = "default";
     }
 }
 
 function breakpointDrag(event)
 {
+    var sourcesDocument = document.getElementById("sources").contentDocument;
     if (!draggingBreakpoint) {
         sourcesDocument.removeEventListener("mousemove", breakpointDrag, true);
         sourcesDocument.removeEventListener("mouseup", breakpointDragEnd, true);
+        sourcesDocument.body.style.cursor = null;
         return;
     }
 
@@ -272,7 +305,6 @@ function breakpointDrag(event)
             removeStyleClass(draggingBreakpoint.parentNode, "disabled");
             draggingBreakpoint.started = true;
 
-            var sourcesDocument = document.getElementById("sources").contentDocument;
             var dragImage = sourcesDocument.createElement("img");
             if (draggingBreakpoint.isDisabled)
                 dragImage.src = "breakPointDisabled.tif";
@@ -283,20 +315,20 @@ function breakpointDrag(event)
             dragImage.style.left = x - 12 + "px";
             sourcesDocument.body.appendChild(dragImage);
         } else {
-            var sourcesDocument = document.getElementById("sources").contentDocument;
             var dragImage = sourcesDocument.getElementById("breakpointDrag");
             if (!dragImage) {
                 sourcesDocument.removeEventListener("mousemove", breakpointDrag, true);
                 sourcesDocument.removeEventListener("mouseup", breakpointDragEnd, true);
+                sourcesDocument.body.style.cursor = null;
                 return;
             }
 
             dragImage.style.top = y - 8 + "px";
             dragImage.style.left = x - 12 + "px";
             if (x > 40)
-                dragImage.style.opacity = "0";
+                dragImage.style.visibility = "hidden";
             else
-                dragImage.style.opacity = null;
+                dragImage.style.visibility = null;
         }
 
         draggingBreakpoint.dragLastX = x;
@@ -306,25 +338,25 @@ function breakpointDrag(event)
 
 function breakpointDragEnd(event)
 {
-    var y = event.clientY + window.scrollY;
-    var x = event.clientX + window.scrollX;
     var sourcesDocument = document.getElementById("sources").contentDocument;
     sourcesDocument.removeEventListener("mousemove", breakpointDrag, true);
     sourcesDocument.removeEventListener("mouseup", breakpointDragEnd, true);
+    sourcesDocument.body.style.cursor = null;
 
-    var sourcesDocument = document.getElementById("sources").contentDocument;
     var dragImage = sourcesDocument.getElementById("breakpointDrag");
     if (!dragImage)
         return;
 
     dragImage.parentNode.removeChild(dragImage);
 
+    var x = event.clientX + window.scrollX;
     if (x > 40 || !draggingBreakpoint)
         return;
 
+    var y = event.clientY + window.scrollY;
     var rowHeight = draggingBreakpoint.parentNode.offsetHeight;
     var row = Math.ceil(y / rowHeight);
-    if (!row)
+    if (row <= 0)
         row = 1;
 
     var file = files[currentFile];
@@ -333,6 +365,8 @@ function breakpointDragEnd(event)
         return;
 
     var tr = table.childNodes.item(row - 1);
+    if (!tr)
+        return;
 
     if (draggingBreakpoint.isDisabled)
         addStyleClass(tr, "disabled");
@@ -345,13 +379,11 @@ function breakpointDragEnd(event)
 function totalOffsetTop(element, stop)
 {
     var currentTop = 0;
-    if (element.offsetParent) {
-        while (element.offsetParent) {
-            currentTop += element.offsetTop
-            element = element.offsetParent;
-            if (element == stop)
-                break;
-        }
+    while (element.offsetParent) {
+        currentTop += element.offsetTop
+        element = element.offsetParent;
+        if (element == stop)
+            break;
     }
     return currentTop;
 }
@@ -415,10 +447,10 @@ function syntaxHighlight(code)
             echoChar(cNext);
             for (i += 2; i < code.length; i++) {
                 c = code.charAt(i);
-                if (c == "\n" || c == "\r")
+                if (c == "\n")
                     result += "</span>";
                 echoChar(c);
-                if (c == "\n" || c == "\r")
+                if (c == "\n")
                     result += "<span class=\"comment\">";
                 if (cPrev == "*" && c == "/")
                     break;
@@ -432,7 +464,7 @@ function syntaxHighlight(code)
             echoChar(cNext);
             for (i += 2; i < code.length; i++) {
                 c = code.charAt(i);
-                if (c == "\n" || c == "\r")
+                if (c == "\n")
                     break;
                 echoChar(c);
             }
@@ -565,7 +597,7 @@ function loadFile(fileIndex, manageNavLists)
         files[currentFile].element.style.display = "none";
 
     if (!file.loaded) {
-        file.lines = file.source.split(/[\n\r]/);
+        file.source = file.source.replace(/\r\n|\r/, "\n"); // normalize line endings
 
         var sourcesDocument = document.getElementById("sources").contentDocument;
         var sourcesDiv = sourcesDocument.body;
@@ -577,7 +609,7 @@ function loadFile(fileIndex, manageNavLists)
         var table = sourcesDocument.createElement("table");
         sourceDiv.appendChild(table);
 
-        var lines = syntaxHighlight(file.source).split(/[\n\r]/);
+        var lines = syntaxHighlight(file.source).split("\n");
         for( var i = 0; i < lines.length; i++ ) {
             var tr = sourcesDocument.createElement("tr");
             var td = sourcesDocument.createElement("td");
@@ -589,7 +621,7 @@ function loadFile(fileIndex, manageNavLists)
 
             td = sourcesDocument.createElement("td");
             td.className = "source";
-            td.innerHTML = lines[i];
+            td.innerHTML = (lines[i].length ? lines[i] : "&nbsp;");
             tr.appendChild(td);
             table.appendChild(tr);
         }
@@ -631,7 +663,6 @@ function updateFileSource(source, url, force)
     if (force || file.source.length != source.length || file.source != source) {
         file.source = source;
         file.loaded = false;
-        file.lines = null;
 
         if (file.element) {
             file.element.parentNode.removeChild(file.element);
@@ -672,7 +703,6 @@ function didParseScript(source, fileSource, url, sourceId, baseLineNumber)
     }
 
     var sourceObj = new Object();
-    sourceObj.source = source;
     sourceObj.file = fileIndex;
     sourceObj.baseLineNumber = baseLineNumber;
     file.scripts.push(sourceId);
@@ -695,8 +725,10 @@ function willExecuteStatement(sourceId, line)
     if (!file)
         return;
 
-    if (file.breakpoints[line] == 1)
+    if (pauseOnNextStatement || file.breakpoints[line] == 1 || (steppingOver && !steppingStack)) {
         pause();
+        pauseOnNextStatement = false;
+    }
 
     if (isPaused()) {
         if (currentFile != script.file)
@@ -705,12 +737,15 @@ function willExecuteStatement(sourceId, line)
             removeStyleClass(currentRow, "current");
         if (!file.element)
             return;
-        if (file.element.firstChild.childNodes.length < line)
+        if (line > file.element.firstChild.childNodes.length)
             return;
 
         updateFunctionStack();
 
         currentRow = file.element.firstChild.childNodes.item(line - 1);
+        if (!currentRow)
+            return;
+
         addStyleClass(currentRow, "current");
 
         var sourcesDiv = document.getElementById("sources");
@@ -724,10 +759,22 @@ function willExecuteStatement(sourceId, line)
 
 function didEnterCallFrame(sourceId, line)
 {
+    if (steppingOver || steppingOut)
+        steppingStack++;
     willExecuteStatement(sourceId, line);
 }
 
 function willLeaveCallFrame(sourceId, line)
 {
+    if (line <= 0)
+        resume();
     willExecuteStatement(sourceId, line);
+    if (!steppingStack)
+        steppingOver = false;
+    if (steppingOut && !steppingStack) {
+        steppingOut = false;
+        pauseOnNextStatement = true;
+    }
+    if ((steppingOver || steppingOut) && steppingStack >= 1)
+        steppingStack--;
 }
index 26e3435..7e863b7 100644 (file)
@@ -29,9 +29,9 @@
 body { background-image: url(gutter.png); background-repeat: repeat-y; margin: 0; padding: 0; }
 img { padding: 0; margin: 0; }
 
-table { border-spacing: 0; padding: 0; margin: 0; }
-.gutter { -webkit-user-select: none; width: 32px; min-width: 32px; max-width: 32px; box-sizing: border-box; font-size: 9px; font-family: Helvetica; color: #888; text-align: right; padding-right: 4px; }
-.source { font-family: Monaco, monospace; white-space: pre; padding-left: 4px; padding-right: 4px; font-size: 11px }
+table { border-spacing: 0; padding: 0; margin: 0; width: 100%; }
+.gutter { -webkit-user-select: none; cursor: default; width: 32px; min-width: 32px; max-width: 32px; box-sizing: border-box; font-size: 9px; font-family: Helvetica; color: #888; text-align: right; padding-right: 4px; }
+.source { font-family: Monaco, monospace; white-space: pre; padding-left: 4px; padding-right: 4px; font-size: 11px; line-height: 14px; }
 
 .keyword { color: #8b0053 }
 .string { color: #a00000 }