1+ /*---------------------------------------------------------------------------------------------
2+ * Copyright (c) Microsoft Corporation. All rights reserved.
3+ * Licensed under the MIT License. See License.txt in the project root for license information.
4+ *--------------------------------------------------------------------------------------------*/
5+ import { Disposable } from 'vs/base/common/lifecycle' ;
6+ import { ICommonCodeEditor , IEditorContribution } from 'vs/editor/common/editorCommon' ;
7+ import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
8+ import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions' ;
9+ import { getColors } from '../common/color' ;
10+ import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService' ;
11+ import { hash } from 'vs/base/common/hash' ;
12+ import { ColorProviderRegistry } from 'vs/editor/common/modes' ;
13+ import { RGBA } from 'vs/base/common/color' ;
14+
15+ const MAX_DECORATORS = 500 ;
16+
17+ @editorContribution
18+ export class ColorController extends Disposable implements IEditorContribution {
19+
20+ private static ID : string = 'editor.contrib.colorController' ;
21+
22+ public static get ( editor : ICommonCodeEditor ) : ColorController {
23+ return editor . getContribution < ColorController > ( ColorController . ID ) ;
24+ }
25+
26+ private _isEnabled : boolean ;
27+ private _decorations : string [ ] ;
28+ private _decorationsTypes : { [ key : string ] : boolean } ;
29+
30+ constructor (
31+ private _editor : ICodeEditor ,
32+ @ICodeEditorService private _codeEditorService : ICodeEditorService
33+ ) {
34+ super ( ) ;
35+ this . _isEnabled = this . _editor . getConfiguration ( ) . contribInfo . colorDecorator ;
36+ this . _decorations = [ ] ;
37+ this . _decorationsTypes = { } ;
38+ this . _register ( _editor . onDidChangeModel ( ( e ) => this . triggerUpdateDecorations ( ) ) ) ;
39+ this . _register ( _editor . onDidChangeModelContent ( ( e ) => {
40+ setTimeout ( ( ) => this . triggerUpdateDecorations ( ) , 0 ) ;
41+ } ) ) ;
42+ this . _register ( _editor . onDidChangeModelLanguage ( ( e ) => this . triggerUpdateDecorations ( ) ) ) ;
43+ this . _register ( _editor . onDidChangeConfiguration ( ( e ) => {
44+ let prevIsEnabled = this . _isEnabled ;
45+ this . _isEnabled = this . _editor . getConfiguration ( ) . contribInfo . colorDecorator ;
46+ if ( prevIsEnabled !== this . _isEnabled ) {
47+ this . triggerUpdateDecorations ( true ) ;
48+ }
49+ } ) ) ;
50+
51+ this . _register ( ColorProviderRegistry . onDidChange ( ( e ) => this . triggerUpdateDecorations ( ) ) ) ;
52+ this . triggerUpdateDecorations ( ) ;
53+ }
54+
55+ triggerUpdateDecorations ( settingsChanges = false ) {
56+ if ( ! this . _isEnabled ) {
57+ if ( settingsChanges ) {
58+ // Users turn it off.
59+ this . _editor . changeDecorations ( ( changeAccessor ) => {
60+ this . _decorations = changeAccessor . deltaDecorations ( this . _decorations , [ ] ) ;
61+ } ) ;
62+ for ( let subType in this . _decorationsTypes ) {
63+ this . _codeEditorService . removeDecorationType ( subType ) ;
64+ }
65+ }
66+ return ;
67+ }
68+
69+ getColors ( this . _editor . getModel ( ) ) . then ( ( colorInfos ) => {
70+ let decorations = [ ] ;
71+ let newDecorationsTypes : { [ key : string ] : boolean } = { } ;
72+
73+ for ( let i = 0 ; i < colorInfos . length && decorations . length < MAX_DECORATORS ; i ++ ) {
74+ const { red, green, blue, alpha } = colorInfos [ i ] . color ;
75+ const rgba = new RGBA ( Math . round ( red * 255 ) , Math . round ( green * 255 ) , Math . round ( blue * 255 ) , alpha ) ;
76+ let subKey = hash ( rgba ) . toString ( 16 ) ;
77+ let color = `rgba(${ rgba . r } , ${ rgba . g } , ${ rgba . b } , ${ rgba . a } )` ;
78+ let key = 'colorBox-' + subKey ;
79+
80+ if ( ! this . _decorationsTypes [ key ] && ! newDecorationsTypes [ key ] ) {
81+ this . _codeEditorService . registerDecorationType ( key , {
82+ before : {
83+ contentText : ' ' ,
84+ border : 'solid 0.1em #000' ,
85+ margin : '0.1em 0.2em 0 0.2em' ,
86+ width : '0.8em' ,
87+ height : '0.8em' ,
88+ backgroundColor : color
89+ } ,
90+ dark : {
91+ before : {
92+ border : 'solid 0.1em #eee'
93+ }
94+ }
95+ } ) ;
96+ }
97+
98+ newDecorationsTypes [ key ] = true ;
99+ decorations . push ( {
100+ range : {
101+ startLineNumber : colorInfos [ i ] . range . startLineNumber ,
102+ startColumn : colorInfos [ i ] . range . startColumn ,
103+ endLineNumber : colorInfos [ i ] . range . endLineNumber ,
104+ endColumn : colorInfos [ i ] . range . endColumn
105+ } ,
106+ options : this . _codeEditorService . resolveDecorationOptions ( key , true )
107+ } ) ;
108+ }
109+
110+ for ( let subType in this . _decorationsTypes ) {
111+ if ( ! newDecorationsTypes [ subType ] ) {
112+ this . _codeEditorService . removeDecorationType ( subType ) ;
113+ }
114+ }
115+
116+ this . _editor . changeDecorations ( ( changeAccessor ) => {
117+ this . _decorations = changeAccessor . deltaDecorations ( this . _decorations , decorations ) ;
118+ } ) ;
119+ } ) ;
120+ }
121+
122+ getId ( ) : string {
123+ return ColorController . ID ;
124+ }
125+
126+ public dispose ( ) : void {
127+ for ( let subType in this . _decorationsTypes ) {
128+ this . _codeEditorService . removeDecorationType ( subType ) ;
129+ }
130+ super . dispose ( ) ;
131+ }
132+ }
0 commit comments