Speed up Out Of Scope lines#3184
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3184 +/- ##
==========================================
- Coverage 47.59% 47.55% -0.04%
==========================================
Files 97 98 +1
Lines 4036 4052 +16
Branches 828 832 +4
==========================================
+ Hits 1921 1927 +6
- Misses 2115 2125 +10
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #3184 +/- ##
==========================================
+ Coverage 47.59% 47.63% +0.04%
==========================================
Files 97 98 +1
Lines 4036 4062 +26
Branches 828 837 +9
==========================================
+ Hits 1921 1935 +14
- Misses 2115 2127 +12
Continue to review full report at Codecov.
|
|
|
||
| if (!linesInScope.includes(line)) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
this was the main thing that I wanted to get out of this PR. previously we were checking the parent's class which required always doing an expensive render. We should be ideally using data which is more trustworthy.
| if (this.props.outOfScopeLocations !== nextProps.outOfScopeLocations) { | ||
| clearLineClass(this.editor.codeMirror, "out-of-scope"); | ||
| if (this.props.linesInScope !== nextProps.linesInScope) { | ||
| this.editor.codeMirror.operation(() => { |
There was a problem hiding this comment.
this.editor.codeMirror.operation is a huge perf win. With that said, i'll be moving the operation inside clearLineClass soon :)
| renderInScopeLines() { | ||
| const { linesInScope } = this.props; | ||
| if ( | ||
| !isEnabled("highlightScopeLines") || |
There was a problem hiding this comment.
i'm re-adding a feature flag because i'm not happy with the cases we're missing like blocks and comments. Seeing those issues makes me think we should wait and re-launch highlighting when it's further along.
With that said, we still get the onMouseOver logic so fewer accidental popups
| @@ -0,0 +1,42 @@ | |||
| // import { linesInScope } from "../utils/scopes"; | |||
| import { getOutOfScopeLocations, getSelectedSource } from "../selectors"; | |||
There was a problem hiding this comment.
this is the first selector that spans stores (sources, ast) with that in mind I created a new selectors directory. I'm not sure if that makes sense. What do others think?
| const sourceText = getSourceText(getState(), source.id); | ||
| if (!sourceText) { | ||
| const source = sourceRecord.toJS(); | ||
| if (!source.text || hasSymbols(getState(), source)) { |
There was a problem hiding this comment.
some small sourceText => source migrations
3423f5e to
539c2ae
Compare
| "column": 21, | ||
| "line": 1, | ||
| "column": 3, | ||
| "line": 10, |
There was a problem hiding this comment.
I switched the test to read from a new fixture file :)
| 10, | ||
| 11, | ||
| 12, | ||
| ] |
There was a problem hiding this comment.
I added the ability to do line reviews
| await dispatch(actions.loadSourceText({ id: "base.js" })); | ||
| await dispatch(actions.selectSource("base.js", { line: 1 })); | ||
|
|
||
| await dispatch(actions.setOutOfScopeLocations()); |
There was a problem hiding this comment.
yeah - so this is coooool. Turns out many of the dispatches are unnecessary.
| } | ||
|
|
||
| .paused .CodeMirror-line, .paused .CodeMirror-linenumber { | ||
| opacity: 0.7; |
There was a problem hiding this comment.
we're now tracking in-scope and not out-of-scope.
some reasons:
- it's easier to get the lines in scope than all the lines that are out of scope
- it should be faster because there are fewer innies than outies.
| case "RESUMED": { | ||
| return state.set("outOfScopeLocations", null); | ||
| } | ||
|
|
codehag
left a comment
There was a problem hiding this comment.
Looks pretty good. I have a few comments. let me know if you have any questions!
| @@ -0,0 +1,41 @@ | |||
| import { getOutOfScopeLocations, getSelectedSource } from "../selectors"; | |||
|
|
|||
| import range from "lodash/range"; | |||
There was a problem hiding this comment.
would it make sense to do this?
import { range, flatMap, uniq, without } from "lodash";There was a problem hiding this comment.
sadly... no because then we pull lodash into the bundle... I suppose if we made it an external then we could exclude it from the bundle and expect it to be available in m-c... If we like this i can file a separate issue for it.
| import without from "lodash/without"; | ||
|
|
||
| function getLinesOutOfScope(outOfScopeLocations: AstLocation[]) { | ||
| if (!outOfScopeLocations) { |
There was a problem hiding this comment.
if this is an array of AstLocations, I think this will always be true... or maybe it isnt an array?
if it is an array we probably need to do
if (!outOfScopeLocations.length) {
...
}There was a problem hiding this comment.
I can do both. when it is not available it's nully.
| import uniq from "lodash/uniq"; | ||
| import without from "lodash/without"; | ||
|
|
||
| function getLinesOutOfScope(outOfScopeLocations: AstLocation[]) { |
There was a problem hiding this comment.
getLinesOutOfScope sounds like we are taking lines out of a scope, but I think this is getting the out of scope lines. maybe getOutOfScopeLines will be clearer here,
|
|
||
| return uniq( | ||
| flatMap(outOfScopeLocations, location => | ||
| range(location.start.line, location.end.line) |
| ); | ||
| } | ||
|
|
||
| export default function getLinesInScope(state: OuterState) { |
There was a problem hiding this comment.
same comment here about naming: proposing getInScopeLines
|
|
||
| function getLinesOutOfScope(outOfScopeLocations: AstLocation[]) { | ||
| if (!outOfScopeLocations) { | ||
| return null; |
There was a problem hiding this comment.
this is returning a different type; maybe it should be an empty array?
There was a problem hiding this comment.
... not sure. i kinda like having explicit empty states to distinguish between nothing and we happen to have no out of scope locs. ill think about it
| const sourceNumLines = source.get("text").split("\n").length; | ||
| const sourceLines = range(1, sourceNumLines + 1); | ||
|
|
||
| if (!linesOutOfScope) { |
There was a problem hiding this comment.
the logic here would be clearer if this was checking for an empty array
| await dispatch(actions.loadSourceText({ id: "base.js" })); | ||
| await dispatch(actions.selectSource("base.js", { line: 1 })); | ||
|
|
||
| await dispatch(actions.setOutOfScopeLocations()); |
Associated Issue: #3180
Summary of Changes
This refactors out of scope lines a bit to support getting a list of in scope lines that can be used by the editor to check if a token is in scope on hover.
Test Plan
Jest tests