@@ -117,73 +117,74 @@ define(function (require, exports, module) {
117117 /**
118118 * To display the color marks on the gutter
119119 *
120- * @param {activeEditor } editor
120+ * @param {Editor } editor
121121 * @param {Array.<object> } _results An array of objects which stores
122122 * all the line numbers and the colors to be displayed on that line.
123123 * @param {Boolean } update marks whether this function is called when some lines
124124 * are updated or when the whole file is re-updated. Defaults to false.
125125 */
126126 function showGutters ( editor , _results , update = false ) {
127127 if ( editor && enabled ) {
128- // if the file is updated we don't need to clear the gutter
129- // as it will clear all the existing markers.
130- if ( ! update ) {
131- editor . clearGutter ( GUTTER_NAME ) ; // clear color markers
132- }
133- _addDummyGutterMarkerIfNotExist ( editor , editor . getCursorPos ( ) . line ) ;
134-
135- // Only add markers if enabled
136- if ( enabled ) {
137- const colorGutters = _ . sortBy ( _results , "lineNumber" ) ;
138-
139- colorGutters . forEach ( function ( obj ) {
140- let $marker ;
141- if ( obj . colorValues . length === 1 ) {
142- // Single color preview
143- $marker = $ ( "<i>" )
144- . addClass ( SINGLE_COLOR_PREVIEW_CLASS )
145- . css ( 'background-color' , obj . colorValues [ 0 ] ) ;
146-
147- editor . setGutterMarker ( obj . lineNumber , GUTTER_NAME , $marker [ 0 ] ) ;
148- $marker . click ( ( event ) => {
149- event . preventDefault ( ) ;
150- event . stopPropagation ( ) ;
151- _colorIconClicked ( editor , obj . lineNumber , obj . colorValues [ 0 ] ) ;
152- } ) ;
153- } else {
154- // Multiple colors preview
155- $marker = $ ( "<div>" ) . addClass ( MULTI_COLOR_PREVIEW_CLASS ) ;
156-
157- // Positions for up to 4 colors in grid
158- const positions = [
159- { top : 0 , left : 0 } ,
160- { top : 0 , right : 0 } ,
161- { bottom : 0 , right : 0 } ,
162- { bottom : 0 , left : 0 }
163- ] ;
164-
165- obj . colorValues . forEach ( ( color , index ) => {
166- if ( index < 4 ) {
167- const $colorBox = $ ( "<div>" )
168- . addClass ( "color-box" )
169- . css ( {
170- 'background-color' : color ,
171- ...positions [ index ]
128+ editor . operation ( ( ) => {
129+ // if the file is updated we don't need to clear the gutter
130+ // as it will clear all the existing markers.
131+ if ( ! update ) {
132+ editor . clearGutter ( GUTTER_NAME ) ; // clear color markers
133+ }
134+ _addDummyGutterMarkerIfNotExist ( editor , editor . getCursorPos ( ) . line ) ;
135+
136+ // Only add markers if enabled
137+ if ( enabled ) {
138+ const colorGutters = _ . sortBy ( _results , "lineNumber" ) ;
139+
140+ colorGutters . forEach ( function ( obj ) {
141+ let $marker ;
142+ if ( obj . colorValues . length === 1 ) {
143+ // Single color preview
144+ $marker = $ ( "<i>" )
145+ . addClass ( SINGLE_COLOR_PREVIEW_CLASS )
146+ . css ( 'background-color' , obj . colorValues [ 0 ] ) ;
147+
148+ editor . setGutterMarker ( obj . lineNumber , GUTTER_NAME , $marker [ 0 ] ) ;
149+ $marker . click ( ( event ) => {
150+ event . preventDefault ( ) ;
151+ event . stopPropagation ( ) ;
152+ _colorIconClicked ( editor , obj . lineNumber , obj . colorValues [ 0 ] ) ;
153+ } ) ;
154+ } else {
155+ // Multiple colors preview
156+ $marker = $ ( "<div>" ) . addClass ( MULTI_COLOR_PREVIEW_CLASS ) ;
157+
158+ // Positions for up to 4 colors in grid
159+ const positions = [
160+ { top : 0 , left : 0 } ,
161+ { top : 0 , right : 0 } ,
162+ { bottom : 0 , right : 0 } ,
163+ { bottom : 0 , left : 0 }
164+ ] ;
165+
166+ obj . colorValues . forEach ( ( color , index ) => {
167+ if ( index < 4 ) {
168+ const $colorBox = $ ( "<div>" )
169+ . addClass ( "color-box" )
170+ . css ( {
171+ 'background-color' : color ,
172+ ...positions [ index ]
173+ } ) ;
174+ $colorBox . click ( ( event ) => {
175+ event . preventDefault ( ) ;
176+ event . stopPropagation ( ) ;
177+ _colorIconClicked ( editor , obj . lineNumber , color ) ;
172178 } ) ;
173- $colorBox . click ( ( event ) => {
174- event . preventDefault ( ) ;
175- event . stopPropagation ( ) ;
176- _colorIconClicked ( editor , obj . lineNumber , color ) ;
177- } ) ;
178- $marker . append ( $colorBox ) ;
179- }
180- } ) ;
181-
182- editor . setGutterMarker ( obj . lineNumber , GUTTER_NAME , $marker [ 0 ] ) ;
183- }
184- } ) ;
185- }
179+ $marker . append ( $colorBox ) ;
180+ }
181+ } ) ;
186182
183+ editor . setGutterMarker ( obj . lineNumber , GUTTER_NAME , $marker [ 0 ] ) ;
184+ }
185+ } ) ;
186+ }
187+ } ) ;
187188 }
188189 }
189190
@@ -249,6 +250,35 @@ define(function (require, exports, module) {
249250 }
250251 }
251252
253+ const STYLE_PARSE_LANGUAGES = {
254+ php : true ,
255+ jsx : true ,
256+ tsx : true
257+ } ;
258+ function _isInStyleAttr ( editor , token ) {
259+ while ( token . type === "string" ) {
260+ const currentToken = token ;
261+ token = editor . getPreviousToken ( { line : token . line , ch : token . start } , true ) ;
262+ if ( currentToken . line === token . line &&
263+ currentToken . start === token . start && currentToken . end === token . end ) {
264+ // reached start of file
265+ break ;
266+ }
267+ }
268+ return token . type === "attribute" && token . string === "style" ;
269+ }
270+
271+ function _shouldProcessToken ( editor , token , pos ) {
272+ const languageID = editor . document . getLanguage ( ) . getId ( ) ;
273+ if ( languageID === "html" ) {
274+ return editor . getLanguageForPosition ( pos ) . getId ( ) === "css" ;
275+ } else if ( STYLE_PARSE_LANGUAGES [ languageID ] ) {
276+ // unfortunately the codemirror mode doesn't support css detection in attributes in php files right now
277+ return token . type !== "comment" && _isInStyleAttr ( editor , token ) ;
278+ }
279+ return token . type !== "comment" ;
280+ }
281+
252282 /**
253283 * Detects valid colors in a given line of text
254284 *
@@ -264,7 +294,7 @@ define(function (require, exports, module) {
264294 return [ ] ;
265295 }
266296
267- const valueRegex = / : [ ^ ; ] * ; / g;
297+ const valueRegex = / : [ ^ ; ] * ; ? / g; // the last semi colon is optional.
268298 const validColors = [ ] ;
269299
270300 // Find all property value sections in the line
@@ -281,7 +311,7 @@ define(function (require, exports, module) {
281311 const token = editor . getToken ( { line : lineNumber , ch : colorIndex } , true ) ;
282312
283313 // If the token is not a comment, add the color
284- if ( token . type !== "comment" ) {
314+ if ( _shouldProcessToken ( editor , token , { line : lineNumber , ch : colorIndex } ) ) {
285315 validColors . push ( {
286316 color : colorMatch [ 0 ] ,
287317 index : colorIndex
@@ -356,27 +386,33 @@ define(function (require, exports, module) {
356386 /**
357387 * Function that gets triggered when any change occurs on the editor
358388 *
359- * @param {Editor } instance the codemirror instance
360- * @param {Object } changeObj an object that has properties regarding the line changed and type of change
389+ * @param _evt unused event detail
390+ * @param {Editor } instance the editor instance
391+ * @param {Object } changeList an object that has properties regarding the line changed and type of change
361392 */
362- function onChanged ( instance , changeObj ) {
363-
364- const editor = EditorManager . getActiveEditor ( ) ;
365-
393+ function onChanged ( _evt , instance , changeList ) {
366394 // for insertion and deletion, update the changed lines
367- if ( changeObj . origin === '+input' || changeObj . origin === '+delete' ) {
368- // make sure that the required properties exist and in the form they are expected to be
395+ if ( ! changeList || ! changeList . length ) {
396+ return ;
397+ }
398+ const changeObj = changeList [ 0 ] ;
399+ if ( changeList . length === 1 && changeObj . origin === '+input' || changeObj . origin === '+delete' ) {
400+ // we only do the diff updates on single key type input/delete and not bulk changes
401+ // somehow the performance degrades if we do the diff logic on large blocks.
369402 if ( changeObj . from . line && changeObj . to . line && changeObj . from . line <= changeObj . to . line ) {
370- const aColors = updateColorMarks ( editor , changeObj . from . line , changeObj . to . line ) ;
371- showGutters ( editor , aColors , true ) ;
403+ let toLine = changeObj . to . line ;
404+ if ( changeObj . text && changeObj . text . length ) {
405+ toLine = changeObj . from . line + changeObj . text . length ;
406+ }
407+ const aColors = updateColorMarks ( instance , changeObj . from . line , Math . max ( changeObj . to . line , toLine ) ) ;
408+ showGutters ( instance , aColors , true ) ;
372409 } else {
373410 showColorMarks ( ) ;
374411 }
375412
376413 } else { // for any complex operation like, cut, paste etc, we re-update the whole file
377414 showColorMarks ( ) ;
378415 }
379-
380416 }
381417
382418 // init after appReady
0 commit comments