/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ import { createSelector } from "devtools/client/shared/vendor/reselect"; import { getViewport, getSelectedSource, getSelectedSourceTextContent, getBreakpointPositionsForSource, } from "./index"; import { getVisibleBreakpoints } from "./visibleBreakpoints"; import { getSelectedLocation } from "../utils/selected-location"; import { sortSelectedLocations } from "../utils/location"; import { getLineText } from "../utils/source"; function contains(location, range) { return ( location.line >= range.start.line && location.line <= range.end.line && (!location.column || (location.column >= range.start.column && location.column <= range.end.column)) ); } function convertToList(breakpointPositions) { return [].concat(...Object.values(breakpointPositions)); } /** * Retrieve the list of column breakpoints to be displayed. * This ignores lines without any breakpoint, but also lines with a single possible breakpoint. * So that we only return breakpoints where there is at least two possible breakpoint on a given line. * Also, this only consider lines currently visible in CodeMirror editor. * * This method returns an array whose elements are objects having two attributes: * - breakpoint: A breakpoint object refering to a precise column location * - location: The location object in an active source where the breakpoint location matched. * This location may be the generated or original source based on the currently selected source type. * * See `visibleColumnBreakpoints()` for the definition of arguments. */ export function getColumnBreakpoints( positions, breakpoints, viewport, selectedSource, selectedSourceTextContent ) { if (!positions || !selectedSource || !breakpoints.length || !viewport) { return []; } const breakpointsPerLine = new Map(); for (const breakpoint of breakpoints) { if (breakpoint.options.hidden) { continue; } const location = getSelectedLocation(breakpoint, selectedSource); const { line } = location; let breakpointsPerColumn = breakpointsPerLine.get(line); if (!breakpointsPerColumn) { breakpointsPerColumn = new Map(); breakpointsPerLine.set(line, breakpointsPerColumn); } breakpointsPerColumn.set(location.column, breakpoint); } const columnBreakpoints = []; for (const keyLine in positions) { const positionsPerLine = positions[keyLine]; // Only consider positions where there is more than one breakable position per line. // When there is only one breakpoint, this isn't a column breakpoint. if (positionsPerLine.length <= 1) { continue; } for (const breakpointPosition of positionsPerLine) { const location = getSelectedLocation(breakpointPosition, selectedSource); const { line } = location; // Ignore any further computation if there is no breakpoint on that line. const breakpointsPerColumn = breakpointsPerLine.get(line); if (!breakpointsPerColumn) { continue; } // Only consider positions visible in the current CodeMirror viewport if (!contains(location, viewport)) { continue; } // Filters out breakpoints to the right of the line. (bug 1552039) // XXX Not really clear why we get such positions?? const { column } = location; if (column) { const lineText = getLineText( selectedSource.id, selectedSourceTextContent, line ); if (column > lineText.length) { continue; } } // Finally, return the expected format output for this selector. // Location of each column breakpoint + a reference to the breakpoint object (if one is set on that column, it can be null). const breakpoint = breakpointsPerColumn.get(column); columnBreakpoints.push({ location, breakpoint, }); } } return columnBreakpoints; } function getVisibleBreakpointPositions(state) { const source = getSelectedSource(state); if (!source) { return null; } return getBreakpointPositionsForSource(state, source.id); } export const visibleColumnBreakpoints = createSelector( getVisibleBreakpointPositions, getVisibleBreakpoints, getViewport, getSelectedSource, getSelectedSourceTextContent, getColumnBreakpoints ); export function getFirstBreakpointPosition(state, location) { const positions = getBreakpointPositionsForSource(state, location.source.id); if (!positions) { return null; } return sortSelectedLocations(convertToList(positions), location.source).find( position => getSelectedLocation(position, location.source).line == location.line ); }