Skip to content

Conversation

@dmitrivMS
Copy link
Contributor

Fixes #180436

Most of the issues in the original bug were already fixed - so adding tests to make sure we don't regress.

Added support for CSS 4 syntax (spaces or slashes as separators) and corresponding tests.

Copilot AI review requested due to automatic review settings December 19, 2025 11:30
@dmitrivMS dmitrivMS self-assigned this Dec 19, 2025
@dmitrivMS dmitrivMS added the editor-color-picker Editor color picker widget issues label Dec 19, 2025
@dmitrivMS dmitrivMS requested a review from aiday-mar December 19, 2025 11:30
@dmitrivMS dmitrivMS enabled auto-merge December 19, 2025 11:30
@vs-code-engineering vs-code-engineering bot added this to the December / January 2026 milestone Dec 19, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds test coverage for previously fixed issues related to color parsing and implements support for CSS Level 4 syntax for color functions (space-separated values and slash separator for alpha).

  • Adds comprehensive tests for decimal hue values in HSL/HSLA functions
  • Adds tests and implementation for CSS Level 4 space-separated syntax for RGB/RGBA and HSL/HSLA
  • Updates regex patterns to support both traditional comma-separated and CSS Level 4 space/slash-separated color syntaxes

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/vs/editor/test/common/languages/defaultDocumentColorsComputer.test.ts Adds four new test suites covering decimal hue values, CSS Level 4 space-separated syntax for HSL/HSLA, and CSS Level 4 syntax for RGB/RGBA functions
src/vs/editor/common/languages/defaultDocumentColorsComputer.ts Updates regex patterns to accept CSS Level 4 syntax by allowing space or slash separators in color functions, with updated comments explaining the changes

if (colorScheme === 'rgb') {
const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\)$/gm;
// Supports both comma-separated (rgb(255, 0, 0)) and CSS Level 4 space-separated syntax (rgb(255 0 0))
const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\)$/gm;
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The character class [\s,] will match either a space OR a comma, which means it would incorrectly accept mixed separators like rgb(255, 0 0) or rgb(255 0, 0). CSS Level 4 syntax requires consistent use of either spaces or commas throughout. The pattern should enforce consistency by using alternation at the entire value level, not at each separator position.

See below for a potential fix:

				const regexParameters = /^\(\s*(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*)\)$/gm;
				colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false);
			} else if (colorScheme === 'rgba') {
				// Supports both comma-separated (rgba(255, 0, 0, 0.5)) and CSS Level 4 syntax (rgba(255 0 0 / 0.5))
				const regexParameters = /^\(\s*(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\/\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*)\)$/gm;
				colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true);
			} else if (colorScheme === 'hsl') {
				const regexParameters = /^\(\s*(?:(?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*|(?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*\)$/gm;
				colorInformation = _findHSLColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false);
			} else if (colorScheme === 'hsla') {
				// Supports both comma-separated (hsla(253, 100%, 50%, 0.5)) and CSS Level 4 syntax (hsla(253 100% 50% / 0.5))
				const regexParameters = /^\(\s*(?:(?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]0*|[01])\s*|(?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*\/\s*(0[.][0-9]+|[.][0-9]+|[01][.]0*|[01])\s*\)$/gm;

Copilot uses AI. Check for mistakes.
} else if (colorScheme === 'rgba') {
const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm;
// Supports both comma-separated (rgba(255, 0, 0, 0.5)) and CSS Level 4 syntax (rgba(255 0 0 / 0.5))
const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*(?:[\s,]|[\s]*\/)\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm;
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The character class [\s,] will match either a space OR a comma, which means it would incorrectly accept mixed separators like rgba(255, 0 0 / 0.5) or rgba(255 0, 0 / 0.5). CSS Level 4 syntax requires consistent use of either spaces or commas for the RGB components. The pattern should enforce consistency by using alternation at the entire value level, not at each separator position.

Suggested change
const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*(?:[\s,]|[\s]*\/)\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm;
const regexParameters = /^\(\s*(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(?:0[.][0-9]+|[.][0-9]+|[01][.]|[01])|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\/\s*(?:0[.][0-9]+|[.][0-9]+|[01][.]|[01]))\s*\)$/gm;

Copilot uses AI. Check for mistakes.
const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*[\s,]\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*(?:[\s,]|[\s]*\/)\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm;
colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true);
} else if (colorScheme === 'hsl') {
const regexParameters = /^\(\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*[\s,]\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*[\s,]\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*\)$/gm;
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The character class [\s,] will match either a space OR a comma, which means it would incorrectly accept mixed separators like hsl(253, 100% 50%) or hsl(253 100%, 50%). CSS Level 4 syntax requires consistent use of either spaces or commas throughout. The pattern should enforce consistency by using alternation at the entire value level, not at each separator position.

See below for a potential fix:

				const regexParameters = /^\(\s*(?:\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*|\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*)\)$/gm;
				colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false);
			} else if (colorScheme === 'rgba') {
				// Supports both comma-separated (rgba(255, 0, 0, 0.5)) and CSS Level 4 syntax (rgba(255 0 0 / 0.5))
				const regexParameters = /^\(\s*(?:\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*|\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s+(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\/\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*)\)$/gm;
				colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true);
			} else if (colorScheme === 'hsl') {
				const regexParameters = /^\(\s*(?:\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*|\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*)\)$/gm;
				colorInformation = _findHSLColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false);
			} else if (colorScheme === 'hsla') {
				// Supports both comma-separated (hsla(253, 100%, 50%, 0.5)) and CSS Level 4 syntax (hsla(253 100% 50% / 0.5))
				const regexParameters = /^\(\s*(?:\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]0*|[01])\s*|\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s+(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*\/\s*(0[.][0-9]+|[.][0-9]+|[01][.]0*|[01])\s*)\)$/gm;

Copilot uses AI. Check for mistakes.
} else if (colorScheme === 'hsla') {
const regexParameters = /^\(\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*[\s,]\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*[\s,]\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*[\s,]\s*(0[.][0-9]+|[.][0-9]+|[01][.]0*|[01])\s*\)$/gm;
// Supports both comma-separated (hsla(253, 100%, 50%, 0.5)) and CSS Level 4 syntax (hsla(253 100% 50% / 0.5))
const regexParameters = /^\(\s*((?:360(?:\.0+)?|(?:36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])(?:\.\d+)?))\s*[\s,]\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*[\s,]\s*(100(?:\.0+)?|\d{1,2}[.]\d*|\d{1,2})%\s*(?:[\s,]|[\s]*\/)\s*(0[.][0-9]+|[.][0-9]+|[01][.]0*|[01])\s*\)$/gm;
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The character class [\s,] will match either a space OR a comma, which means it would incorrectly accept mixed separators like hsla(253, 100% 50% / 0.5) or hsla(253 100%, 50% / 0.5). CSS Level 4 syntax requires consistent use of either spaces or commas for the HSL components. The pattern should enforce consistency by using alternation at the entire value level, not at each separator position.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

editor-color-picker Editor color picker widget issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test: standalone color picker: decorators with hsl values, some don't work, some hsl values do trigger the decorator

2 participants