1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
/* 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,
});
};
}
|