From 97026f2feae7fc7da0dffe8a0900ae8015bfc346 Mon Sep 17 00:00:00 2001 From: Pluto Date: Tue, 18 Feb 2025 21:14:16 +0530 Subject: [PATCH 1/4] feat: suggest previously used colors in file --- src/extensions/default/CSSCodeHints/main.js | 78 +++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index 0b17d87a7f..0438efe3f5 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -26,6 +26,7 @@ define(function (require, exports, module) { var AppInit = brackets.getModule("utils/AppInit"), CodeHintManager = brackets.getModule("editor/CodeHintManager"), + EditorManager = brackets.getModule("editor/EditorManager"), CSSUtils = brackets.getModule("language/CSSUtils"), PreferencesManager = brackets.getModule("preferences/PreferencesManager"), TokenUtils = brackets.getModule("utils/TokenUtils"), @@ -92,6 +93,62 @@ define(function (require, exports, module) { this.exclusion = null; } + function isAlphanumeric(char) { + return /^[a-z0-9-@$]$/i.test(char); + } + + function isValidColor(text, colorMatch) { + const colorIndex = colorMatch.index; + const previousChar = colorIndex === 0 ? "" : text.charAt(colorIndex - 1); + const endIndex = colorIndex + colorMatch[0].length; + const nextChar = endIndex === text.length ? "" : text.charAt(endIndex); + return !isAlphanumeric(previousChar) && !isAlphanumeric(nextChar); + } + + function updateColorList(colorList, color, lineNumber) { + const existingColor = colorList.find(item => item.color === color); + if (existingColor) { + existingColor.count++; + if (!existingColor.lines.includes(lineNumber)) { + existingColor.lines.push(lineNumber); + } + } else { + colorList.push({ + color: color, + lines: [lineNumber], + count: 1 + }); + } + } + + function getAllColorsInFile() { + const editor = EditorManager.getActiveEditor(); + const nLen = editor.lineCount(); + + const colorList = []; + + for (let i = 0; i < nLen; i++) { + const lineText = editor.getLine(i); + + if (!lineText || lineText.length > 1000) { + continue; + } + + const matches = [...lineText.matchAll(ColorUtils.COLOR_REGEX)]; + + for (const match of matches) { + if (isValidColor(lineText, match)) { + const token = editor.getToken({ line: i, ch: match.index }); + if (token && token.type !== "comment") { + updateColorList(colorList, match[0], i); + } + } + } + } + + return colorList; + } + /** * Check whether the exclusion is still the same as text after the cursor. * If not, reset it to null. @@ -298,6 +355,10 @@ define(function (require, exports, module) { result, selectInitial = false; + let previouslyUsedColors = []; + + + // Clear the exclusion if the user moves the cursor with left/right arrow key. this.updateExclusion(true); @@ -339,6 +400,22 @@ define(function (require, exports, module) { let isColorSwatch = false; if (type === "color") { isColorSwatch = true; + + + const colorList = getAllColorsInFile(); + + // Convert COLOR_LIST to previouslyUsedColors format and sort by count + previouslyUsedColors = colorList + .sort((a, b) => b.count - a.count) // Sort in descending order by count + .map(item => item.color); // Extract only the colors + + // Combine default hex, rgb colors with existing color names + valueArray = previouslyUsedColors.concat( + ColorUtils.COLOR_NAMES.map(function (color) { + return { text: color, color: color }; + }) + ); + valueArray = valueArray.concat(ColorUtils.COLOR_NAMES.map(function (color) { return { text: color, color: color }; })); @@ -351,6 +428,7 @@ define(function (require, exports, module) { result = StringMatch.codeHintsSort(valueNeedle, valueArray, { limit: MAX_CSS_HINTS, + boostPrefixList: previouslyUsedColors, // for named colors to make them appear before other color hints onlyContiguous: isColorSwatch // for color swatches, when searching for `ora` we should // only hint nge and not livedb (green shade) }); From ee9b90389bad7e2d169338b2e5800451cbc62d86 Mon Sep 17 00:00:00 2001 From: Pluto Date: Wed, 19 Feb 2025 19:07:06 +0530 Subject: [PATCH 2/4] fix: named colors appearing twice --- src/extensions/default/CSSCodeHints/main.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index 0438efe3f5..cdba7d41fe 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -416,9 +416,6 @@ define(function (require, exports, module) { }) ); - valueArray = valueArray.concat(ColorUtils.COLOR_NAMES.map(function (color) { - return { text: color, color: color }; - })); valueArray.push("transparent", "currentColor"); } From 45ae2d12f834932a1111e6660594abeacd726f02 Mon Sep 17 00:00:00 2001 From: Pluto Date: Wed, 19 Feb 2025 19:16:18 +0530 Subject: [PATCH 3/4] fix: rightly place cursor when color values are used from hints --- src/extensions/default/CSSCodeHints/main.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index cdba7d41fe..ee77a42541 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -582,7 +582,8 @@ define(function (require, exports, module) { * Checks whether the expandedAbbr has any number. * For instance: `m0` expands to `margin: 0;`, so we need to display the whole thing in the code hint * Here, we also make sure that abbreviations which has `#`, `,` should not be included, because - * `color` expands to `color: #000;` or `color: rgb(0, 0, 0)`. So this actually has numbers, but we don't want to display this. + * `color` expands to `color: #000;` or `color: rgb(0, 0, 0)`. + * So this actually has numbers, but we don't want to display this. * * @param {String} expandedAbbr the expanded abbr returned by EXPAND_ABBR emmet api * @returns {boolean} true if expandedAbbr has numbers (and doesn't include '#') otherwise false. @@ -738,12 +739,18 @@ define(function (require, exports, module) { var parenMatch = hint.match(/\(.*?\)/); if (parenMatch) { - // value has (...), so place cursor inside opening paren - // and keep hints open - adjustCursor = true; - newCursor = { line: cursor.line, - ch: start.ch + parenMatch.index + 1 }; - keepHints = true; + // Only adjust cursor for non-color values + if (!hint.startsWith('rgb') && + !hint.startsWith('rgba') && + !hint.startsWith('hsl') && + !hint.startsWith('hsla')) { + // value has (...), so place cursor inside opening paren + // and keep hints open + adjustCursor = true; + newCursor = { line: cursor.line, + ch: start.ch + parenMatch.index + 1 }; + keepHints = true; + } } } From 29e798c96dc6b0b45cdc2492d72f9409d509e44a Mon Sep 17 00:00:00 2001 From: Pluto Date: Sun, 23 Feb 2025 21:34:50 +0530 Subject: [PATCH 4/4] fix: live server tests failing issue --- src/extensions/default/CSSCodeHints/main.js | 139 +++++---- test/spec/LiveDevelopmentMultiBrowser-test.js | 267 +++++++++--------- 2 files changed, 215 insertions(+), 191 deletions(-) diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js index ee77a42541..2d4e417839 100644 --- a/src/extensions/default/CSSCodeHints/main.js +++ b/src/extensions/default/CSSCodeHints/main.js @@ -24,21 +24,21 @@ define(function (require, exports, module) { - var AppInit = brackets.getModule("utils/AppInit"), - CodeHintManager = brackets.getModule("editor/CodeHintManager"), - EditorManager = brackets.getModule("editor/EditorManager"), - CSSUtils = brackets.getModule("language/CSSUtils"), - PreferencesManager = brackets.getModule("preferences/PreferencesManager"), - TokenUtils = brackets.getModule("utils/TokenUtils"), - StringMatch = brackets.getModule("utils/StringMatch"), - ColorUtils = brackets.getModule("utils/ColorUtils"), - Strings = brackets.getModule("strings"), - KeyEvent = brackets.getModule("utils/KeyEvent"), - LiveDevelopment = brackets.getModule("LiveDevelopment/main"), - Metrics = brackets.getModule("utils/Metrics"), - AllPreferences = brackets.getModule("preferences/AllPreferences"), - CSSProperties = require("text!CSSProperties.json"), - properties = JSON.parse(CSSProperties); + var AppInit = brackets.getModule("utils/AppInit"), + CodeHintManager = brackets.getModule("editor/CodeHintManager"), + EditorManager = brackets.getModule("editor/EditorManager"), + CSSUtils = brackets.getModule("language/CSSUtils"), + PreferencesManager = brackets.getModule("preferences/PreferencesManager"), + TokenUtils = brackets.getModule("utils/TokenUtils"), + StringMatch = brackets.getModule("utils/StringMatch"), + ColorUtils = brackets.getModule("utils/ColorUtils"), + Strings = brackets.getModule("strings"), + KeyEvent = brackets.getModule("utils/KeyEvent"), + LiveDevelopment = brackets.getModule("LiveDevelopment/main"), + Metrics = brackets.getModule("utils/Metrics"), + AllPreferences = brackets.getModule("preferences/AllPreferences"), + CSSProperties = require("text!CSSProperties.json"), + properties = JSON.parse(CSSProperties); /** * Emmet API: @@ -139,7 +139,20 @@ define(function (require, exports, module) { for (const match of matches) { if (isValidColor(lineText, match)) { const token = editor.getToken({ line: i, ch: match.index }); - if (token && token.type !== "comment") { + + // this check is added to filter out non-required colors. For ex: + // the color should not be inside a commented line + // the color should not be written as a plain text (in html files) + // like

Red is bad.

, we need to ignore this Red + if ( + token && + ( + // If we're in an HTML file (token.state.htmlState exists), + // then only process if inside a