Source code

Revision control

Copy as Markdown

Other Tools

/* 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 <http://mozilla.org/MPL/2.0/>. */
import {
hasInScopeLines,
getSourceTextContent,
getVisibleSelectedFrame,
} from "../../selectors/index";
import { getSourceLineCount } from "../../utils/source";
import { isFulfilled } from "../../utils/async-value";
function getOutOfScopeLines(outOfScopeLocations) {
if (!outOfScopeLocations) {
return null;
}
const uniqueLines = new Set();
for (const location of outOfScopeLocations) {
for (let i = location.start.line; i < location.end.line; i++) {
uniqueLines.add(i);
}
}
return uniqueLines;
}
async function getInScopeLines(location, sourceTextContent, { parserWorker }) {
let locations = null;
if (location.line && parserWorker.isLocationSupported(location)) {
locations = await parserWorker.findOutOfScopeLocations(location);
}
const linesOutOfScope = getOutOfScopeLines(locations);
const sourceNumLines =
!sourceTextContent || !isFulfilled(sourceTextContent)
? 0
: getSourceLineCount(sourceTextContent.value);
const noLinesOutOfScope =
linesOutOfScope == null || linesOutOfScope.size == 0;
// This operation can be very costly for large files so we sacrifice a bit of readability
// for performance sake.
// We initialize an array with a fixed size and we'll directly assign value for lines
// that are not out of scope. This is much faster than having an empty array and pushing
// into it.
const sourceLines = new Array(sourceNumLines);
for (let i = 0; i < sourceNumLines; i++) {
const line = i + 1;
if (noLinesOutOfScope || !linesOutOfScope.has(line)) {
sourceLines[i] = line;
}
}
// Finally we need to remove any undefined values, i.e. the ones that were matching
// out of scope lines.
return sourceLines.filter(i => i != undefined);
}
export function setInScopeLines() {
return async thunkArgs => {
const { getState, dispatch } = thunkArgs;
const visibleFrame = getVisibleSelectedFrame(getState());
if (!visibleFrame) {
return;
}
const { location } = visibleFrame;
const sourceTextContent = getSourceTextContent(getState(), location);
// Ignore if in scope lines have already be computed, or if the selected location
// doesn't have its content already fully fetched.
// The ParserWorker will only have the source text content once the source text content is fulfilled.
if (
hasInScopeLines(getState(), location) ||
!sourceTextContent ||
!isFulfilled(sourceTextContent)
) {
return;
}
const lines = await getInScopeLines(location, sourceTextContent, thunkArgs);
dispatch({
type: "IN_SCOPE_LINES",
location,
lines,
});
};
}