Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 5ecc4ff

Browse files
committed
Merge pull request #9964 from MarcelGerber/find-blocks-perf
Improve TokenUtils performance through caching
2 parents 2badcb5 + 792467c commit 5ecc4ff

File tree

1 file changed

+60
-7
lines changed

1 file changed

+60
-7
lines changed

src/utils/TokenUtils.js

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,73 @@
3333
define(function (require, exports, module) {
3434
"use strict";
3535

36-
var CodeMirror = require("thirdparty/CodeMirror2/lib/codemirror");
36+
var _ = require("thirdparty/lodash"),
37+
CodeMirror = require("thirdparty/CodeMirror2/lib/codemirror");
38+
39+
var cache;
40+
41+
42+
function _clearCache(cm) {
43+
cache = null;
44+
if (cm) { // event handler
45+
cm.off("changes", _clearCache);
46+
}
47+
}
48+
49+
/*
50+
* Caches the tokens for the given editor/line if needed
51+
* @param {!CodeMirror} cm
52+
* @param {!number} line
53+
* @return {Array.<Object>} (Cached) array of tokens
54+
*/
55+
function _manageCache(cm, line) {
56+
if (!cache || !cache.tokens || cache.line !== line || cache.cm !== cm) {
57+
// Cache is no longer matching -> Update
58+
var tokens = cm.getLineTokens(line, false);
59+
// Add empty beginning-of-line token for backwards compatibility
60+
tokens.unshift(cm.getTokenAt({line: line, ch: 0}, false));
61+
cache = {
62+
cm: cm,
63+
line: line,
64+
timeStamp: Date.now(),
65+
tokens: tokens,
66+
};
67+
cm.off("changes", _clearCache);
68+
cm.on("changes", _clearCache);
69+
}
70+
return cache.tokens;
71+
}
72+
73+
/*
74+
* Like cm.getTokenAt, but with caching
75+
* @param {!CodeMirror} cm
76+
* @param {!{ch:number, line:number}} pos
77+
* @param {boolean} precise If given, results in more current results. Suppresses caching.
78+
* @return {Object} Token for position
79+
*/
80+
function _getToken(cm, pos, precise) {
81+
if (precise) {
82+
_clearCache(); // reset cache
83+
return cm.getTokenAt(pos, precise);
84+
}
85+
var cachedTokens = _manageCache(cm, pos.line),
86+
tokenIndex = _.sortedIndex(cachedTokens, {end: pos.ch}, "end"), // binary search is faster for long arrays
87+
token = cachedTokens[tokenIndex];
88+
return token || cm.getTokenAt(pos, precise); // fall back to CMs getTokenAt, for example in an empty line
89+
}
3790

3891
/**
3992
* Creates a context object for the given editor and position, suitable for passing to the
4093
* move functions.
41-
* @param {!CodeMirror} editor
94+
* @param {!CodeMirror} cm
4295
* @param {!{ch:number, line:number}} pos
4396
* @return {!{editor:!CodeMirror, pos:!{ch:number, line:number}, token:Object}}
4497
*/
45-
function getInitialContext(editor, pos) {
98+
function getInitialContext(cm, pos) {
4699
return {
47-
"editor": editor,
100+
"editor": cm,
48101
"pos": pos,
49-
"token": editor.getTokenAt(pos, true)
102+
"token": cm.getTokenAt(pos, true)
50103
};
51104
}
52105

@@ -72,7 +125,7 @@ define(function (require, exports, module) {
72125
} else {
73126
ctx.pos.ch = ctx.token.start;
74127
}
75-
ctx.token = ctx.editor.getTokenAt(ctx.pos, precise);
128+
ctx.token = _getToken(ctx.editor, ctx.pos, precise);
76129
return true;
77130
}
78131

@@ -107,7 +160,7 @@ define(function (require, exports, module) {
107160
} else {
108161
ctx.pos.ch = ctx.token.end + 1;
109162
}
110-
ctx.token = ctx.editor.getTokenAt(ctx.pos, precise);
163+
ctx.token = _getToken(ctx.editor, ctx.pos, precise);
111164
return true;
112165
}
113166

0 commit comments

Comments
 (0)