11// 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" ;
33import { ValueEqualsSet } from "./utilities/hashset" ;
4- import { tokenizeDocument } from "./tokenizer/tokenizer" ;
4+ import { Tokenizer } from "./tokenizer/tokenizer" ;
55import { LiteralTokenType } from "./tokenizer/renpy-tokens" ;
66import { 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";*/
117
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+ } ) ;
2034
2135/**
2236 * Finds all colors in the given document and returns their ranges and color
2337 * @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
2539 */
26- export function getColorInformation ( document : TextDocument ) : Thenable < ColorInformation [ ] > {
27- injectCustomColorStyles ( document ) ;
40+ export async function getColorInformation ( document : TextDocument ) {
41+ await injectCustomColorStyles ( document ) ;
2842
2943 // find all colors in the document
3044 const colors : ColorInformation [ ] = [ ] ;
@@ -67,7 +81,7 @@ export function getColorInformation(document: TextDocument): Thenable<ColorInfor
6781 }
6882 }
6983 }
70- return Promise . resolve ( colors ) ;
84+ return colors ;
7185}
7286
7387/**
@@ -77,12 +91,12 @@ export function getColorInformation(document: TextDocument): Thenable<ColorInfor
7791 * @param range - The Range of the color match
7892 * @returns - ColorPresentation to replace the color in the document with the new chosen color
7993 */
80- export function getColorPresentations ( color : Color , document : TextDocument , range : Range ) : Thenable < ColorPresentation [ ] > {
94+ export function getColorPresentations ( color : Color , context : DocumentColorContext ) : ColorPresentation [ ] {
8195 // user hovered/tapped the color block/return the color they picked
8296 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 ) ;
86100
87101 const colR = Math . round ( color . red * 255 ) ;
88102 const colG = Math . round ( color . green * 255 ) ;
@@ -112,12 +126,12 @@ export function getColorPresentations(color: Color, document: TextDocument, rang
112126 colors . push ( rgbColorPres ) ;
113127 }
114128
115- return Promise . resolve ( colors ) ;
129+ return colors ;
116130}
117131
118- export function injectCustomColorStyles ( document : TextDocument ) {
132+ export async function injectCustomColorStyles ( document : TextDocument ) {
119133 // Disabled until filter is added to the tree class
120- const documentTokens = tokenizeDocument ( document ) ;
134+ const documentTokens = await Tokenizer . tokenizeDocument ( document ) ;
121135 // TODO: Should probably make sure this constant is actually part of a tag, but for now this is fine.
122136 const colorTags = documentTokens . filter ( ( x ) => x . token ?. tokenType === LiteralTokenType . Color ) ;
123137 const colorRules = new ValueEqualsSet < TextMateRule > ( ) ;
@@ -221,32 +235,55 @@ export function convertHtmlToColor(htmlHex: string): Color | null {
221235 */
222236export function convertRenpyColorToColor ( renpy : string ) : Color | null {
223237 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 ;
230246 }
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 ) ;
232253 } catch ( error ) {
233254 return null ;
234255 }
235256}
236257
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+
237271/**
238272 * 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.
241275 * @param renpyColor - Renpy `rgb` color tuple (e.g., `rgb=(r, g, b)`)
242276 * @returns The `Color` provider object
243277 */
244278export function convertRgbColorToColor ( renpyColor : string ) : Color | null {
245279 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 ( "," ) ;
248285 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 ) ;
250287 }
251288 return null ;
252289 } catch ( error ) {
0 commit comments