1
1
// Color conversion methods for Color provider
2
- import { CancellationToken , Color , ColorInformation , ColorPresentation , DocumentColorProvider , Range , TextDocument , TextEdit } from "vscode" ;
2
+ import { CancellationToken , Color , ColorInformation , ColorPresentation , ProviderResult , Range , TextDocument , TextEdit , languages } from "vscode" ;
3
3
import { ValueEqualsSet } from "./utilities/hashset" ;
4
- import { tokenizeDocument } from "./tokenizer/tokenizer" ;
4
+ import { Tokenizer } from "./tokenizer/tokenizer" ;
5
5
import { LiteralTokenType } from "./tokenizer/renpy-tokens" ;
6
6
import { TextMateRule , injectCustomTextmateTokens } from "./decorator" ;
7
- /*import { tokenizeDocument } from "./tokenizer/tokenizer";
8
- import { injectCustomTextmateTokens, TextMateRule } from "./decorator";
9
- import { LiteralTokenType } from "./tokenizer/renpy-tokens";
10
- import { ValueEqualsSet } from "./utilities/hashset";*/
11
7
12
- export class RenpyColorProvider implements DocumentColorProvider {
13
- public provideDocumentColors ( document : TextDocument , token : CancellationToken ) : Thenable < ColorInformation [ ] > {
14
- return getColorInformation ( document ) ;
15
- }
16
- public provideColorPresentations ( color : Color , context : { document : TextDocument ; range : Range } , token : CancellationToken ) : Thenable < ColorPresentation [ ] > {
17
- return getColorPresentations ( color , context . document , context . range ) ;
18
- }
19
- }
8
+ export type DocumentColorContext = {
9
+ document : TextDocument ;
10
+ range : Range ;
11
+ } ;
12
+
13
+ export const colorProvider = languages . registerColorProvider ( "renpy" , {
14
+ provideDocumentColors ( document : TextDocument , token : CancellationToken ) : ProviderResult < ColorInformation [ ] > {
15
+ if ( token . isCancellationRequested ) {
16
+ return ;
17
+ }
18
+
19
+ return new Promise ( ( resolve ) => {
20
+ resolve ( getColorInformation ( document ) ) ;
21
+ } ) ;
22
+ } ,
23
+
24
+ provideColorPresentations ( color : Color , context : DocumentColorContext , token : CancellationToken ) : ProviderResult < ColorPresentation [ ] > {
25
+ if ( token . isCancellationRequested ) {
26
+ return ;
27
+ }
28
+
29
+ return new Promise ( ( resolve ) => {
30
+ resolve ( getColorPresentations ( color , context ) ) ;
31
+ } ) ;
32
+ } ,
33
+ } ) ;
20
34
21
35
/**
22
36
* Finds all colors in the given document and returns their ranges and color
23
37
* @param document - the TextDocument to search
24
- * @returns - Thenable< ColorInformation[]> - an array that provides a range and color for each match
38
+ * @returns - ColorInformation[] - an array that provides a range and color for each match
25
39
*/
26
- export function getColorInformation ( document : TextDocument ) : Thenable < ColorInformation [ ] > {
27
- injectCustomColorStyles ( document ) ;
40
+ export async function getColorInformation ( document : TextDocument ) {
41
+ await injectCustomColorStyles ( document ) ;
28
42
29
43
// find all colors in the document
30
44
const colors : ColorInformation [ ] = [ ] ;
@@ -67,7 +81,7 @@ export function getColorInformation(document: TextDocument): Thenable<ColorInfor
67
81
}
68
82
}
69
83
}
70
- return Promise . resolve ( colors ) ;
84
+ return colors ;
71
85
}
72
86
73
87
/**
@@ -77,12 +91,12 @@ export function getColorInformation(document: TextDocument): Thenable<ColorInfor
77
91
* @param range - The Range of the color match
78
92
* @returns - ColorPresentation to replace the color in the document with the new chosen color
79
93
*/
80
- export function getColorPresentations ( color : Color , document : TextDocument , range : Range ) : Thenable < ColorPresentation [ ] > {
94
+ export function getColorPresentations ( color : Color , context : DocumentColorContext ) : ColorPresentation [ ] {
81
95
// user hovered/tapped the color block/return the color they picked
82
96
const colors : ColorPresentation [ ] = [ ] ;
83
- const line = document . lineAt ( range . start . line ) . text ;
84
- const text = line . substring ( range . start . character , range . end . character ) ;
85
- const oldRange = new Range ( range . start . line , range . start . character , range . start . line , range . start . character + text . length ) ;
97
+ const range = context . range ;
98
+ const text = context . document . getText ( range ) ;
99
+ const oldRange = new Range ( range . start , range . end ) ;
86
100
87
101
const colR = Math . round ( color . red * 255 ) ;
88
102
const colG = Math . round ( color . green * 255 ) ;
@@ -112,12 +126,12 @@ export function getColorPresentations(color: Color, document: TextDocument, rang
112
126
colors . push ( rgbColorPres ) ;
113
127
}
114
128
115
- return Promise . resolve ( colors ) ;
129
+ return colors ;
116
130
}
117
131
118
- export function injectCustomColorStyles ( document : TextDocument ) {
132
+ export async function injectCustomColorStyles ( document : TextDocument ) {
119
133
// Disabled until filter is added to the tree class
120
- const documentTokens = tokenizeDocument ( document ) ;
134
+ const documentTokens = await Tokenizer . tokenizeDocument ( document ) ;
121
135
// TODO: Should probably make sure this constant is actually part of a tag, but for now this is fine.
122
136
const colorTags = documentTokens . filter ( ( x ) => x . token ?. tokenType === LiteralTokenType . Color ) ;
123
137
const colorRules = new ValueEqualsSet < TextMateRule > ( ) ;
@@ -221,32 +235,55 @@ export function convertHtmlToColor(htmlHex: string): Color | null {
221
235
*/
222
236
export function convertRenpyColorToColor ( renpy : string ) : Color | null {
223
237
try {
224
- const colorTuple = renpy . replace ( "Color(" , "" ) . replace ( "color" , "" ) . replace ( "=" , "" ) . replace ( " " , "" ) . replace ( "(" , "[" ) . replace ( ")" , "]" ) ;
225
- const result = JSON . parse ( colorTuple ) ;
226
- if ( result . length === 3 ) {
227
- return new Color ( parseInt ( result [ 0 ] , 16 ) / 255 , parseInt ( result [ 1 ] , 16 ) / 255 , parseInt ( result [ 2 ] , 16 ) / 255 , 1.0 ) ;
228
- } else if ( result . length === 4 ) {
229
- return new Color ( parseInt ( result [ 0 ] , 16 ) / 255 , parseInt ( result [ 1 ] , 16 ) / 255 , parseInt ( result [ 2 ] , 16 ) / 255 , parseInt ( result [ 3 ] , 16 ) / 255 ) ;
238
+ const colorTuple = renpy
239
+ . replaceAll ( " " , "" )
240
+ . replace ( / [ C c ] o l o r = ? \( / g, "" )
241
+ . replace ( ")" , "" ) ;
242
+
243
+ const result = colorTuple . split ( "," ) ;
244
+ if ( result . length < 3 ) {
245
+ return null ;
230
246
}
231
- return null ;
247
+
248
+ const r = parseInt ( result [ 0 ] , 16 ) / 255 ;
249
+ const g = parseInt ( result [ 1 ] , 16 ) / 255 ;
250
+ const b = parseInt ( result [ 2 ] , 16 ) / 255 ;
251
+ const a = result . length === 4 ? parseInt ( result [ 3 ] , 16 ) / 255 : 1.0 ;
252
+ return new Color ( r , g , b , a ) ;
232
253
} catch ( error ) {
233
254
return null ;
234
255
}
235
256
}
236
257
258
+ /**
259
+ * Returns a float value based on the given Ren'Py float string value
260
+ * @remarks Values starting with a dot (e.g., `.5`) are forced to be parsed as `0.5` due to javascript's `parseFloat` behavior.
261
+ * @param value The renpy float value to parse
262
+ * @returns The parsed float value
263
+ */
264
+ function parseRenpyFloat ( value : string ) : number {
265
+ if ( value . startsWith ( "." ) ) {
266
+ return parseFloat ( "0" + value ) ;
267
+ }
268
+ return parseFloat ( value ) ;
269
+ }
270
+
237
271
/**
238
272
* Returns a Color provider object based on the given Ren'Py rgb tuple
239
- * @remarks
240
- * The rgb tuple values should be numeric values between 0.0 and 1.0 (e.g., `rgb=(1.0, 0.0, 0.0)`)
273
+ * @remarks The rgb tuple values should be numeric values between 0.0 and 1.0 (e.g., `rgb=(1.0, 0.0, 0.0)`).
274
+ * Values starting with a dot (e.g., `.5`) are forced to be parsed as `0.5` due to javascript's `parseFloat` behavior.
241
275
* @param renpyColor - Renpy `rgb` color tuple (e.g., `rgb=(r, g, b)`)
242
276
* @returns The `Color` provider object
243
277
*/
244
278
export function convertRgbColorToColor ( renpyColor : string ) : Color | null {
245
279
try {
246
- const colorTuple = renpyColor . replace ( "rgb" , "" ) . replace ( "=" , "" ) . replace ( " " , "" ) . replace ( "(" , "[" ) . replace ( ")" , "]" ) ;
247
- const result = JSON . parse ( colorTuple ) ;
280
+ const colorTuple = renpyColor
281
+ . replaceAll ( " " , "" )
282
+ . replace ( / r g b = \( / g, "" )
283
+ . replace ( ")" , "" ) ;
284
+ const result = colorTuple . split ( "," ) ;
248
285
if ( result . length === 3 ) {
249
- return new Color ( parseFloat ( result [ 0 ] ) , parseFloat ( result [ 1 ] ) , parseFloat ( result [ 2 ] ) , 1.0 ) ;
286
+ return new Color ( parseRenpyFloat ( result [ 0 ] ) , parseRenpyFloat ( result [ 1 ] ) , parseRenpyFloat ( result [ 2 ] ) , 1.0 ) ;
250
287
}
251
288
return null ;
252
289
} catch ( error ) {
0 commit comments