visibleColumnBreakpoints.js (5342B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import { createSelector } from "devtools/client/shared/vendor/reselect"; 6 7 import { 8 getViewport, 9 getSelectedSource, 10 getSelectedSourceTextContent, 11 getBreakpointPositionsForSource, 12 } from "./index"; 13 import { getVisibleBreakpoints } from "./visibleBreakpoints"; 14 import { getSelectedLocation } from "../utils/selected-location"; 15 import { sortSelectedLocations } from "../utils/location"; 16 import { getLineText } from "../utils/source"; 17 18 function contains(location, range) { 19 // If the location is within the viewport lines or if the location is on the first or last line 20 // and the columns are within the start or end line content. 21 return ( 22 (location.line > range.start.line && location.line < range.end.line) || 23 (location.line == range.start.line && 24 location.column >= range.start.column) || 25 (location.line == range.end.line && location.column <= range.end.column) 26 ); 27 } 28 29 function convertToList(breakpointPositions) { 30 return [].concat(...Object.values(breakpointPositions)); 31 } 32 33 /** 34 * Retrieve the list of column breakpoints to be displayed. 35 * This ignores lines without any breakpoint, but also lines with a single possible breakpoint. 36 * So that we only return breakpoints where there is at least two possible breakpoint on a given line. 37 * Also, this only consider lines currently visible in CodeMirror editor. 38 * 39 * This method returns an array whose elements are objects having two attributes: 40 * - breakpoint: A breakpoint object refering to a precise column location 41 * - location: The location object in an active source where the breakpoint location matched. 42 * This location may be the generated or original source based on the currently selected source type. 43 * 44 * See `visibleColumnBreakpoints()` for the definition of arguments. 45 */ 46 export function getColumnBreakpoints( 47 positions, 48 breakpoints, 49 viewport, 50 selectedSource, 51 selectedSourceTextContent 52 ) { 53 if (!positions || !selectedSource || !breakpoints.length || !viewport) { 54 return []; 55 } 56 57 const breakpointsPerLine = new Map(); 58 for (const breakpoint of breakpoints) { 59 if (breakpoint.options.hidden) { 60 continue; 61 } 62 const location = getSelectedLocation(breakpoint, selectedSource); 63 const { line } = location; 64 let breakpointsPerColumn = breakpointsPerLine.get(line); 65 if (!breakpointsPerColumn) { 66 breakpointsPerColumn = new Map(); 67 breakpointsPerLine.set(line, breakpointsPerColumn); 68 } 69 breakpointsPerColumn.set(location.column, breakpoint); 70 } 71 72 const columnBreakpoints = []; 73 for (const keyLine in positions) { 74 const positionsPerLine = positions[keyLine]; 75 // Only consider positions where there is more than one breakable position per line. 76 // When there is only one breakpoint, this isn't a column breakpoint. 77 if (positionsPerLine.length <= 1) { 78 continue; 79 } 80 for (const breakpointPosition of positionsPerLine) { 81 // For minified sources we want to limit the amount of displayed column breakpoints 82 // This is nice to have for perf reasons 83 if (columnBreakpoints.length >= 100) { 84 continue; 85 } 86 87 const location = getSelectedLocation(breakpointPosition, selectedSource); 88 // Only consider positions visible in the current CodeMirror viewport 89 if (!contains(location, viewport)) { 90 continue; 91 } 92 93 const { line } = location; 94 // Ignore any further computation if there is no breakpoint on that line. 95 const breakpointsPerColumn = breakpointsPerLine.get(line); 96 if (!breakpointsPerColumn) { 97 continue; 98 } 99 100 // Filters out breakpoints to the right of the line. (bug 1552039) 101 // XXX Not really clear why we get such positions?? 102 const { column } = location; 103 if (column) { 104 const lineText = getLineText( 105 selectedSource.id, 106 selectedSourceTextContent, 107 line 108 ); 109 if (column > lineText.length) { 110 continue; 111 } 112 } 113 114 // Finally, return the expected format output for this selector. 115 // Location of each column breakpoint + a reference to the breakpoint object (if one is set on that column, it can be null). 116 const breakpoint = breakpointsPerColumn.get(column); 117 118 columnBreakpoints.push({ 119 location, 120 breakpoint, 121 }); 122 } 123 } 124 125 return columnBreakpoints; 126 } 127 128 function getVisibleBreakpointPositions(state) { 129 const source = getSelectedSource(state); 130 if (!source) { 131 return null; 132 } 133 return getBreakpointPositionsForSource(state, source.id); 134 } 135 136 export const visibleColumnBreakpoints = createSelector( 137 getVisibleBreakpointPositions, 138 getVisibleBreakpoints, 139 getViewport, 140 getSelectedSource, 141 getSelectedSourceTextContent, 142 getColumnBreakpoints 143 ); 144 145 export function getFirstBreakpointPosition(state, location) { 146 const positions = getBreakpointPositionsForSource(state, location.source.id); 147 if (!positions) { 148 return null; 149 } 150 151 return sortSelectedLocations(convertToList(positions), location.source).find( 152 position => 153 getSelectedLocation(position, location.source).line == location.line 154 ); 155 }