Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js

Issue 2844603002: DevTools: render continue to location as execution line instead of green dots. (Closed)
Patch Set: same Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 this._popoverHelper = new UI.PopoverHelper(this._scriptsPanel.element, this. _getPopoverRequest.bind(this)); 47 this._popoverHelper = new UI.PopoverHelper(this._scriptsPanel.element, this. _getPopoverRequest.bind(this));
48 this._popoverHelper.setDisableOnClick(true); 48 this._popoverHelper.setDisableOnClick(true);
49 this._popoverHelper.setTimeout(250, 250); 49 this._popoverHelper.setTimeout(250, 250);
50 this._popoverHelper.setHasPadding(true); 50 this._popoverHelper.setHasPadding(true);
51 this._scriptsPanel.element.addEventListener( 51 this._scriptsPanel.element.addEventListener(
52 'scroll', this._popoverHelper.hidePopover.bind(this._popoverHelper), tru e); 52 'scroll', this._popoverHelper.hidePopover.bind(this._popoverHelper), tru e);
53 53
54 this.textEditor.element.addEventListener('keydown', this._onKeyDown.bind(thi s), true); 54 this.textEditor.element.addEventListener('keydown', this._onKeyDown.bind(thi s), true);
55 this.textEditor.element.addEventListener('keyup', this._onKeyUp.bind(this), true); 55 this.textEditor.element.addEventListener('keyup', this._onKeyUp.bind(this), true);
56 this.textEditor.element.addEventListener('mousemove', this._onMouseMove.bind (this), false); 56 this.textEditor.element.addEventListener('mousemove', this._onMouseMove.bind (this), false);
57 this.textEditor.element.addEventListener('mousedown', this._onMouseDown.bind (this), true);
57 if (Runtime.experiments.isEnabled('continueToLocationMarkers')) { 58 if (Runtime.experiments.isEnabled('continueToLocationMarkers')) {
58 this.textEditor.element.addEventListener('wheel', event => { 59 this.textEditor.element.addEventListener('wheel', event => {
59 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) 60 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event))
60 event.preventDefault(); 61 event.preventDefault();
61 }, true); 62 }, true);
62 } 63 }
63 64
64 this.textEditor.addEventListener( 65 this.textEditor.addEventListener(
65 SourceFrame.SourcesTextEditor.Events.GutterClick, this._handleGutterClic k.bind(this), this); 66 SourceFrame.SourcesTextEditor.Events.GutterClick, this._handleGutterClic k.bind(this), this);
66 67
(...skipping 18 matching lines...) Expand all
85 this._scriptFileForDebuggerModel = new Map(); 86 this._scriptFileForDebuggerModel = new Map();
86 87
87 Common.moduleSetting('skipStackFramesPattern').addChangeListener(this._showB lackboxInfobarIfNeeded, this); 88 Common.moduleSetting('skipStackFramesPattern').addChangeListener(this._showB lackboxInfobarIfNeeded, this);
88 Common.moduleSetting('skipContentScripts').addChangeListener(this._showBlack boxInfobarIfNeeded, this); 89 Common.moduleSetting('skipContentScripts').addChangeListener(this._showBlack boxInfobarIfNeeded, this);
89 90
90 /** @type {!Map.<number, !Element>} */ 91 /** @type {!Map.<number, !Element>} */
91 this._valueWidgets = new Map(); 92 this._valueWidgets = new Map();
92 this.onBindingChanged(); 93 this.onBindingChanged();
93 Bindings.debuggerWorkspaceBinding.addEventListener( 94 Bindings.debuggerWorkspaceBinding.addEventListener(
94 Bindings.DebuggerWorkspaceBinding.Events.SourceMappingChanged, this._onS ourceMappingChanged, this); 95 Bindings.DebuggerWorkspaceBinding.Events.SourceMappingChanged, this._onS ourceMappingChanged, this);
96 /** @type {?Map<!Object, !Function>} */
97 this._continueToLocationDecorations = null;
95 } 98 }
96 99
97 /** 100 /**
98 * @override 101 * @override
99 * @return {!Array<!UI.ToolbarItem>} 102 * @return {!Array<!UI.ToolbarItem>}
100 */ 103 */
101 syncToolbarItems() { 104 syncToolbarItems() {
102 var result = super.syncToolbarItems(); 105 var result = super.syncToolbarItems();
103 var originURL = Bindings.CompilerScriptMapping.uiSourceCodeOrigin(this._debu ggerSourceCode); 106 var originURL = Bindings.CompilerScriptMapping.uiSourceCodeOrigin(this._debu ggerSourceCode);
104 if (originURL) { 107 if (originURL) {
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 378
376 /** 379 /**
377 * @param {string} tokenType 380 * @param {string} tokenType
378 * @return {boolean} 381 * @return {boolean}
379 */ 382 */
380 _isIdentifier(tokenType) { 383 _isIdentifier(tokenType) {
381 return tokenType.startsWith('js-variable') || tokenType.startsWith('js-prope rty') || tokenType === 'js-def'; 384 return tokenType.startsWith('js-variable') || tokenType.startsWith('js-prope rty') || tokenType === 'js-def';
382 } 385 }
383 386
384 /** 387 /**
385 * @param {!Event} event 388 * @param {!MouseEvent} event
386 * @return {?UI.PopoverRequest} 389 * @return {?UI.PopoverRequest}
387 */ 390 */
388 _getPopoverRequest(event) { 391 _getPopoverRequest(event) {
392 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event))
393 return null;
389 var target = UI.context.flavor(SDK.Target); 394 var target = UI.context.flavor(SDK.Target);
390 var debuggerModel = target ? target.model(SDK.DebuggerModel) : null; 395 var debuggerModel = target ? target.model(SDK.DebuggerModel) : null;
391 if (!debuggerModel || !debuggerModel.isPaused()) 396 if (!debuggerModel || !debuggerModel.isPaused())
392 return null; 397 return null;
393 398
394 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, even t.y); 399 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, even t.y);
395 if (!textPosition) 400 if (!textPosition)
396 return null; 401 return null;
397 402
398 var mouseLine = textPosition.startLine; 403 var mouseLine = textPosition.startLine;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 */ 486 */
482 _onKeyDown(event) { 487 _onKeyDown(event) {
483 if (event.key === 'Escape') { 488 if (event.key === 'Escape') {
484 if (this._popoverHelper.isPopoverVisible()) { 489 if (this._popoverHelper.isPopoverVisible()) {
485 this._popoverHelper.hidePopover(); 490 this._popoverHelper.hidePopover();
486 event.consume(); 491 event.consume();
487 } 492 }
488 return; 493 return;
489 } 494 }
490 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event) && this._executionLocation ) { 495 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event) && this._executionLocation ) {
491 if (!this._continueToLocationShown) { 496 if (!this._continueToLocationDecorations)
492 this._showContinueToLocations(); 497 this._showContinueToLocations();
493 this._continueToLocationShown = true;
494 }
495 } 498 }
496 } 499 }
497 500
498 /** 501 /**
499 * @param {!MouseEvent} event 502 * @param {!MouseEvent} event
500 */ 503 */
501 _onMouseMove(event) { 504 _onMouseMove(event) {
502 if (this._executionLocation && UI.KeyboardShortcut.eventHasCtrlOrMeta(event) ) { 505 if (this._executionLocation && UI.KeyboardShortcut.eventHasCtrlOrMeta(event) ) {
503 if (!this._continueToLocationShown) { 506 if (!this._continueToLocationDecorations)
504 this._showContinueToLocations(); 507 this._showContinueToLocations();
505 this._continueToLocationShown = true;
506 }
507 return;
508 } 508 }
509 } 509 }
510 510
511 /**
512 * @param {!MouseEvent} event
513 */
514 _onMouseDown(event) {
515 if (!this._executionLocation || !UI.KeyboardShortcut.eventHasCtrlOrMeta(even t))
516 return;
517 if (!this._continueToLocationDecorations)
518 return;
519 event.consume();
520 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, even t.y);
521 if (!textPosition)
522 return;
523 for (var decoration of this._continueToLocationDecorations.keys()) {
524 var range = decoration.find();
525 if (range.from.line !== textPosition.startLine || range.to.line !== textPo sition.startLine)
526 continue;
527 if (range.from.ch <= textPosition.startColumn && textPosition.startColumn <= range.to.ch) {
528 this._continueToLocationDecorations.get(decoration)();
529 break;
530 }
531 }
532 }
533
511 /** 534 /**
512 * @param {!KeyboardEvent} event 535 * @param {!KeyboardEvent} event
513 */ 536 */
514 _onKeyUp(event) { 537 _onKeyUp(event) {
515 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) 538 if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event))
516 return; 539 return;
517 if (!this._continueToLocationShown)
518 return;
519 this._clearContinueToLocations(); 540 this._clearContinueToLocations();
520 this._continueToLocationShown = false;
521 } 541 }
522 542
523 /** 543 /**
524 * @param {number} lineNumber 544 * @param {number} lineNumber
525 * @param {?Bindings.BreakpointManager.Breakpoint} breakpoint 545 * @param {?Bindings.BreakpointManager.Breakpoint} breakpoint
526 * @param {?{lineNumber: number, columnNumber: number}} location 546 * @param {?{lineNumber: number, columnNumber: number}} location
527 */ 547 */
528 _editBreakpointCondition(lineNumber, breakpoint, location) { 548 _editBreakpointCondition(lineNumber, breakpoint, location) {
529 this._conditionElement = this._createConditionElement(lineNumber); 549 this._conditionElement = this._createConditionElement(lineNumber);
530 this.textEditor.addDecoration(this._conditionElement, lineNumber); 550 this.textEditor.addDecoration(this._conditionElement, lineNumber);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 this._executionLocation = uiLocation; 596 this._executionLocation = uiLocation;
577 if (!this.loaded) 597 if (!this.loaded)
578 return; 598 return;
579 599
580 this.textEditor.setExecutionLocation(uiLocation.lineNumber, uiLocation.colum nNumber); 600 this.textEditor.setExecutionLocation(uiLocation.lineNumber, uiLocation.colum nNumber);
581 if (this.isShowing()) { 601 if (this.isShowing()) {
582 // We need SourcesTextEditor to be initialized prior to this call. @see cr bug.com/506566 602 // We need SourcesTextEditor to be initialized prior to this call. @see cr bug.com/506566
583 setImmediate(() => { 603 setImmediate(() => {
584 this._generateValuesInSource(); 604 this._generateValuesInSource();
585 if (Runtime.experiments.isEnabled('continueToLocationMarkers')) { 605 if (Runtime.experiments.isEnabled('continueToLocationMarkers')) {
586 if (this._continueToLocationShown) 606 if (this._continueToLocationDecorations)
587 this._showContinueToLocations(); 607 this._showContinueToLocations();
588 } 608 }
589 }); 609 });
590 } 610 }
591 } 611 }
592 612
593 _generateValuesInSource() { 613 _generateValuesInSource() {
594 if (!Common.moduleSetting('inlineVariableValues').get()) 614 if (!Common.moduleSetting('inlineVariableValues').get())
595 return; 615 return;
596 var executionContext = UI.context.flavor(SDK.ExecutionContext); 616 var executionContext = UI.context.flavor(SDK.ExecutionContext);
(...skipping 12 matching lines...) Expand all
609 629
610 if (this._clearValueWidgetsTimer) { 630 if (this._clearValueWidgetsTimer) {
611 clearTimeout(this._clearValueWidgetsTimer); 631 clearTimeout(this._clearValueWidgetsTimer);
612 delete this._clearValueWidgetsTimer; 632 delete this._clearValueWidgetsTimer;
613 } 633 }
614 } 634 }
615 635
616 _showContinueToLocations() { 636 _showContinueToLocations() {
617 if (!Runtime.experiments.isEnabled('continueToLocationMarkers')) 637 if (!Runtime.experiments.isEnabled('continueToLocationMarkers'))
618 return; 638 return;
639 this._popoverHelper.hidePopover();
619 var executionContext = UI.context.flavor(SDK.ExecutionContext); 640 var executionContext = UI.context.flavor(SDK.ExecutionContext);
620 if (!executionContext) 641 if (!executionContext)
621 return; 642 return;
622 var callFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame); 643 var callFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
623 if (!callFrame) 644 if (!callFrame)
624 return; 645 return;
625 if (this._clearContinueToLocationsTimer) {
626 clearTimeout(this._clearContinueToLocationsTimer);
627 delete this._clearContinueToLocationsTimer;
628 }
629 var localScope = callFrame.localScope(); 646 var localScope = callFrame.localScope();
630 if (!localScope) { 647 if (!localScope) {
631 this.textEditor.operation(clearExistingLocations.bind(this)); 648 this._clearContinueToLocations();
632 return; 649 return;
633 } 650 }
634 var start = localScope.startLocation(); 651 var start = localScope.startLocation();
635 var end = localScope.endLocation(); 652 var end = localScope.endLocation();
636 var debuggerModel = callFrame.debuggerModel; 653 var debuggerModel = callFrame.debuggerModel;
637 var executionLocation = callFrame.location();
638 debuggerModel.getPossibleBreakpoints(start, end, true) 654 debuggerModel.getPossibleBreakpoints(start, end, true)
639 .then(locations => this.textEditor.operation(renderLocations.bind(this, locations))); 655 .then(locations => this.textEditor.operation(renderLocations.bind(this, locations)));
656
640 /** 657 /**
641 * @param {!Array<!SDK.DebuggerModel.BreakLocation>} locations 658 * @param {!Array<!SDK.DebuggerModel.BreakLocation>} locations
642 * @this {Sources.JavaScriptSourceFrame} 659 * @this {Sources.JavaScriptSourceFrame}
643 */ 660 */
644 function renderLocations(locations) { 661 function renderLocations(locations) {
645 clearExistingLocations.call(this); 662 this._clearContinueToLocations();
663 this._continueToLocationDecorations = new Map();
646 for (var location of locations) { 664 for (var location of locations) {
647 var icon; 665 var lineNumber = location.lineNumber;
648 var isCurrent = location.lineNumber === executionLocation.lineNumber && 666 var token = this.textEditor.tokenAtTextPosition(lineNumber, location.col umnNumber);
649 location.columnNumber === executionLocation.columnNumber; 667 if (!token || !token.type)
650 if (!isCurrent || (location.type !== SDK.DebuggerModel.BreakLocationType .Call && 668 continue;
651 location.type !== SDK.DebuggerModel.BreakLocationType .Return)) { 669 var line = this.textEditor.line(lineNumber);
652 icon = UI.Icon.create('smallicon-green-arrow'); 670 var tokenContent = line.substring(token.startColumn, token.endColumn);
653 icon.addEventListener('click', location.continueToLocation.bind(locati on)); 671 if (!this._isIdentifier(token.type) && (token.type !== 'js-keyword' || t okenContent !== 'this'))
654 } else if (location.type === SDK.DebuggerModel.BreakLocationType.Call) { 672 continue;
655 icon = UI.Icon.create('smallicon-step-in'); 673
656 icon.addEventListener('click', () => { 674 var highlightRange = new TextUtils.TextRange(lineNumber, token.startColu mn, lineNumber, token.endColumn - 1);
657 debuggerModel.scheduleStepIntoAsync(); 675 var decoration = this.textEditor.highlightRange(highlightRange, 'source- frame-continue-to-location');
658 debuggerModel.stepInto(); 676 this._continueToLocationDecorations.set(decoration, location.continueToL ocation.bind(location));
659 });
660 } else if (location.type === SDK.DebuggerModel.BreakLocationType.Return) {
661 icon = UI.Icon.create('smallicon-step-out');
662 icon.addEventListener('click', () => {
663 debuggerModel.stepOut();
664 });
665 }
666 icon.classList.add('cm-continue-to-location');
667 icon.addEventListener('mousemove', hidePopoverAndConsumeEvent.bind(this) );
668 this.textEditor.addBookmark(
669 location.lineNumber, location.columnNumber, icon,
670 Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol);
671 } 677 }
672 } 678 }
673
674 /**
675 * @this {Sources.JavaScriptSourceFrame}
676 */
677 function clearExistingLocations() {
678 var bookmarks = this.textEditor.bookmarks(
679 this.textEditor.fullRange(), Sources.JavaScriptSourceFrame.continueToL ocationDecorationSymbol);
680 bookmarks.map(bookmark => bookmark.clear());
681 }
682
683 /**
684 * @param {!Event} event
685 * @this {Sources.JavaScriptSourceFrame}
686 */
687 function hidePopoverAndConsumeEvent(event) {
688 event.consume(true);
689 this._popoverHelper.hidePopover();
690 }
691 } 679 }
692 680
693 /** 681 /**
694 * @param {!SDK.DebuggerModel.CallFrame} callFrame 682 * @param {!SDK.DebuggerModel.CallFrame} callFrame
695 * @param {?Array.<!SDK.RemoteObjectProperty>} properties 683 * @param {?Array.<!SDK.RemoteObjectProperty>} properties
696 * @param {?Array.<!SDK.RemoteObjectProperty>} internalProperties 684 * @param {?Array.<!SDK.RemoteObjectProperty>} internalProperties
697 */ 685 */
698 _prepareScopeVariables(callFrame, properties, internalProperties) { 686 _prepareScopeVariables(callFrame, properties, internalProperties) {
699 if (!properties || !properties.length || properties.length > 500 || !this.is Showing()) { 687 if (!properties || !properties.length || properties.length > 500 || !this.is Showing()) {
700 this._clearValueWidgets(); 688 this._clearValueWidgets();
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 } 815 }
828 } 816 }
829 if (widgetChanged) { 817 if (widgetChanged) {
830 this._valueWidgets.set(i, widget); 818 this._valueWidgets.set(i, widget);
831 this.textEditor.addDecoration(widget, i); 819 this.textEditor.addDecoration(widget, i);
832 } 820 }
833 } 821 }
834 } 822 }
835 823
836 clearExecutionLine() { 824 clearExecutionLine() {
837 if (this.loaded && this._executionLocation) 825 this.textEditor.operation(() => {
838 this.textEditor.clearExecutionLine(); 826 if (this.loaded && this._executionLocation)
839 delete this._executionLocation; 827 this.textEditor.clearExecutionLine();
840 this._clearValueWidgetsTimer = setTimeout(this._clearValueWidgets.bind(this) , 1000); 828 delete this._executionLocation;
841 if (Runtime.experiments.isEnabled('continueToLocationMarkers')) 829 this._clearValueWidgetsTimer = setTimeout(this._clearValueWidgets.bind(thi s), 1000);
dgozman 2017/04/26 16:04:58 I feel like we should do similar things for all de
pfeldman 2017/04/27 21:05:05 Sure. textEditor operation is a good-enough tool t
842 this._clearContinueToLocationsTimer = setTimeout(this._clearContinueToLoca tions.bind(this), 1000); 830 this._clearContinueToLocations();
dgozman 2017/04/26 16:04:58 This is a nested operation. That's ok?
pfeldman 2017/04/27 21:05:05 Yes
831 });
843 } 832 }
844 833
845 _clearValueWidgets() { 834 _clearValueWidgets() {
846 delete this._clearValueWidgetsTimer; 835 delete this._clearValueWidgetsTimer;
847 for (var line of this._valueWidgets.keys()) 836 this.textEditor.operation(() => {
848 this.textEditor.removeDecoration(this._valueWidgets.get(line), line); 837 for (var line of this._valueWidgets.keys())
849 this._valueWidgets.clear(); 838 this.textEditor.removeDecoration(this._valueWidgets.get(line), line);
839 this._valueWidgets.clear();
840 });
850 } 841 }
851 842
852 _clearContinueToLocations() { 843 _clearContinueToLocations() {
853 if (!Runtime.experiments.isEnabled('continueToLocationMarkers')) 844 if (!this._continueToLocationDecorations)
854 return; 845 return;
855 delete this._clearContinueToLocationsTimer; 846 this.textEditor.operation(() => {
856 var bookmarks = this.textEditor.bookmarks( 847 for (var decoration of this._continueToLocationDecorations.keys())
857 this.textEditor.fullRange(), Sources.JavaScriptSourceFrame.continueToLoc ationDecorationSymbol); 848 this.textEditor.removeHighlight(decoration);
858 this.textEditor.operation(() => bookmarks.map(bookmark => bookmark.clear())) ; 849 delete this._continueToLocationDecorations;
850 });
859 } 851 }
860 852
861 /** 853 /**
862 * @param {number} lineNumber 854 * @param {number} lineNumber
863 * @return {!Array<!Sources.JavaScriptSourceFrame.BreakpointDecoration>} 855 * @return {!Array<!Sources.JavaScriptSourceFrame.BreakpointDecoration>}
864 */ 856 */
865 _lineBreakpointDecorations(lineNumber) { 857 _lineBreakpointDecorations(lineNumber) {
866 return Array.from(this._breakpointDecorations) 858 return Array.from(this._breakpointDecorations)
867 .filter(decoration => (decoration.handle.resolve() || {}).lineNumber === lineNumber); 859 .filter(decoration => (decoration.handle.resolve() || {}).lineNumber === lineNumber);
868 } 860 }
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 return; 1480 return;
1489 this.bookmark.clear(); 1481 this.bookmark.clear();
1490 this.bookmark = null; 1482 this.bookmark = null;
1491 } 1483 }
1492 }; 1484 };
1493 1485
1494 Sources.JavaScriptSourceFrame.BreakpointDecoration.bookmarkSymbol = Symbol('book mark'); 1486 Sources.JavaScriptSourceFrame.BreakpointDecoration.bookmarkSymbol = Symbol('book mark');
1495 Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest = Symbo l('element'); 1487 Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest = Symbo l('element');
1496 1488
1497 Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol = Symbol('bookm ark'); 1489 Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol = Symbol('bookm ark');
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698