3333define ( 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