Skip to content

Commit a0b0ead

Browse files
committed
feat: inline color preview
1 parent 0919336 commit a0b0ead

File tree

3 files changed

+101
-12
lines changed

3 files changed

+101
-12
lines changed

src/editor/Editor.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,19 +1491,41 @@ define(function (require, exports, module) {
14911491
};
14921492

14931493
/**
1494-
* Clears all mark of the given type. If nothing is given, clears all marks(Don't use this API without types!).
1494+
* Clears all marks of the given type. If a lineNumbers array is given, only clears marks on those lines.
1495+
* If no markType or lineNumbers are given, clears all marks (use cautiously).
14951496
* @param {string} [markType] - Optional, if given will only delete marks of that type. Else delete everything.
1497+
* @param {number[]} [lineNumbers] - Optional, array of line numbers where marks should be cleared.
14961498
*/
1497-
Editor.prototype.clearAllMarks = function (markType) {
1499+
Editor.prototype.clearAllMarks = function (markType, lineNumbers) {
14981500
const self = this;
1501+
14991502
self._codeMirror.operation(function () {
15001503
let marks = self.getAllMarks(markType);
1504+
1505+
if (lineNumbers && Array.isArray(lineNumbers)) {
1506+
// Filter marks to only those within the specified line numbers
1507+
marks = marks.filter(function (mark) {
1508+
const range = mark.find(); // Get the range of the mark
1509+
if (!range) {
1510+
return false;
1511+
}
1512+
1513+
const startLine = range.from.line;
1514+
const endLine = range.to.line;
1515+
1516+
// Check if the mark overlaps with any of the specified lines
1517+
return lineNumbers.some(line => line >= startLine && line <= endLine);
1518+
});
1519+
}
1520+
1521+
// Clear the filtered marks
15011522
for (let mark of marks) {
15021523
mark.clear();
15031524
}
15041525
});
15051526
};
15061527

1528+
15071529
/**
15081530
* Checks if two positions in the editor are the same.
15091531
*

src/extensionsIntegrated/CSSColorPreview/main.js

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ define(function (require, exports, module) {
4040
// Extension variables.
4141
const COLOR_REGEX = ColorUtils.COLOR_REGEX, // used to match color
4242
GUTTER_NAME = "CodeMirror-colorGutter",
43+
COLOR_MARK_NAME = "colorMarker",
4344
DUMMY_GUTTER_CLASS = "CodeMirror-colorGutter-none",
4445
SINGLE_COLOR_PREVIEW_CLASS = "ico-cssColorPreview",
4546
MULTI_COLOR_PREVIEW_CLASS = "ico-multiple-cssColorPreview",
@@ -50,12 +51,18 @@ define(function (require, exports, module) {
5051

5152
// For preferences settings, to toggle this feature on/off
5253
const PREFERENCES_CSS_COLOR_PREVIEW = "colorPreview";
53-
let enabled = true; // by default:- on
54+
const PREFERENCES_INLINE_COLOR_PREVIEW = "colorPreviewInline";
55+
let enabled = true, // by default:- on
56+
inlinePreviewEnabled = false;
5457

5558
PreferencesManager.definePreference(PREFERENCES_CSS_COLOR_PREVIEW, "boolean", enabled, {
5659
description: Strings.DESCRIPTION_CSS_COLOR_PREVIEW
5760
});
5861

62+
PreferencesManager.definePreference(PREFERENCES_INLINE_COLOR_PREVIEW, "boolean", enabled, {
63+
description: Strings.DESCRIPTION_CSS_COLOR_PREVIEW_INLINE
64+
});
65+
5966

6067
/**
6168
* Gets all the colors that are to be displayed
@@ -114,6 +121,16 @@ define(function (require, exports, module) {
114121
}, 50);
115122
}
116123

124+
function _colorMark(editor, from, to, color) {
125+
editor.markText(COLOR_MARK_NAME, from, to, {
126+
css: `
127+
--bg-color-mark: ${color};
128+
background: var(--bg-color-mark);
129+
color: lch(from var(--bg-color-mark) calc((50 - l) * infinity) 0 0);
130+
`
131+
});
132+
}
133+
117134
/**
118135
* To display the color marks on the gutter
119136
*
@@ -143,13 +160,13 @@ define(function (require, exports, module) {
143160
// Single color preview
144161
$marker = $("<i>")
145162
.addClass(SINGLE_COLOR_PREVIEW_CLASS)
146-
.css('background-color', obj.colorValues[0]);
163+
.css('background-color', obj.colorValues[0].color);
147164

148165
editor.setGutterMarker(obj.lineNumber, GUTTER_NAME, $marker[0]);
149166
$marker.click((event)=>{
150167
event.preventDefault();
151168
event.stopPropagation();
152-
_colorIconClicked(editor, obj.lineNumber, obj.colorValues[0]);
169+
_colorIconClicked(editor, obj.lineNumber, obj.colorValues[0].color);
153170
});
154171
} else {
155172
// Multiple colors preview
@@ -168,13 +185,13 @@ define(function (require, exports, module) {
168185
const $colorBox = $("<div>")
169186
.addClass("color-box")
170187
.css({
171-
'background-color': color,
188+
'background-color': color.color,
172189
...positions[index]
173190
});
174191
$colorBox.click((event)=>{
175192
event.preventDefault();
176193
event.stopPropagation();
177-
_colorIconClicked(editor, obj.lineNumber, color);
194+
_colorIconClicked(editor, obj.lineNumber, color.color);
178195
});
179196
$marker.append($colorBox);
180197
}
@@ -197,9 +214,36 @@ define(function (require, exports, module) {
197214
}
198215
}
199216

217+
function _applyInlineColor(editor, line) {
218+
editor._currentlyColorMarkedLine = line;
219+
editor.clearAllMarks(COLOR_MARK_NAME);
220+
const colors = detectValidColorsInLine(editor, line);
221+
for(let color of colors){
222+
_colorMark(editor, {line, ch: color.index}, {line, ch: color.index + color.color.length},
223+
color.color);
224+
}
225+
}
226+
200227
function _cursorActivity(_evt, editor){
201228
// this is to prevent a gutter gap in the active line if there is no color on this line.
202-
_addDummyGutterMarkerIfNotExist(editor, editor.getCursorPos().line);
229+
const line = editor.getCursorPos().line;
230+
if(enabled){
231+
_addDummyGutterMarkerIfNotExist(editor, line);
232+
}
233+
if(!inlinePreviewEnabled){
234+
return;
235+
}
236+
if(editor.hasSelection()){
237+
if(editor._currentlyColorMarkedLine === line){
238+
editor._currentlyColorMarkedLine = null;
239+
editor.clearAllMarks(COLOR_MARK_NAME);
240+
}
241+
return;
242+
}
243+
if(editor._currentlyColorMarkedLine === line) {
244+
return;
245+
}
246+
_applyInlineColor(editor, line);
203247
}
204248

205249
/**
@@ -320,8 +364,7 @@ define(function (require, exports, module) {
320364
});
321365
}
322366

323-
// Return up to 4 colors
324-
return validColors.slice(0, 4).map(item => item.color);
367+
return validColors;
325368
}
326369

327370
/**
@@ -392,10 +435,14 @@ define(function (require, exports, module) {
392435
*/
393436
function onChanged(_evt, instance, changeList) {
394437
// for insertion and deletion, update the changed lines
395-
if(!changeList || !changeList.length) {
438+
if(!changeList || !changeList.length || !enabled) {
396439
return;
397440
}
398441
const changeObj = changeList[0];
442+
instance._currentlyColorMarkedLine = null;
443+
if(inlinePreviewEnabled && changeObj.origin && changeObj.origin.startsWith("+InlineColorEditor")){
444+
_applyInlineColor(instance, instance.getCursorPos().line);
445+
}
399446
if(changeList.length === 1 && changeObj.origin === '+input' || changeObj.origin === '+delete') {
400447
// we only do the diff updates on single key type input/delete and not bulk changes
401448
// somehow the performance degrades if we do the diff logic on large blocks.
@@ -415,10 +462,29 @@ define(function (require, exports, module) {
415462
}
416463
}
417464

465+
function inlinePreferenceChanged() {
466+
inlinePreviewEnabled = PreferencesManager.get(PREFERENCES_INLINE_COLOR_PREVIEW);
467+
const allActiveEditors = MainViewManager.getAllViewedEditors();
468+
469+
allActiveEditors.forEach((activeEditor) => {
470+
const currEditor = activeEditor.editor;
471+
if(!currEditor){
472+
return;
473+
}
474+
if(!inlinePreviewEnabled) {
475+
currEditor.clearAllMarks(COLOR_MARK_NAME);
476+
} else {
477+
_applyInlineColor(currEditor, currEditor.getCursorPos().line);
478+
}
479+
});
480+
}
481+
418482
// init after appReady
419483
AppInit.appReady(function () {
420484
PreferencesManager.on("change", PREFERENCES_CSS_COLOR_PREVIEW, preferenceChanged);
485+
PreferencesManager.on("change", PREFERENCES_INLINE_COLOR_PREVIEW, inlinePreferenceChanged);
421486
preferenceChanged();
487+
inlinePreferenceChanged();
422488
registerHandlers();
423489
});
424490
});

src/nls/root/strings.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,5 +1251,6 @@ define({
12511251
// indent guides extension
12521252
"DESCRIPTION_INDENT_GUIDES_ENABLED": "true to show indent guide lines, else false.",
12531253
"DESCRIPTION_HIDE_FIRST": "true to show the first Indent Guide line else false.",
1254-
"DESCRIPTION_CSS_COLOR_PREVIEW": "true to display color previews in the gutter, else false."
1254+
"DESCRIPTION_CSS_COLOR_PREVIEW": "true to display color previews in the gutter, else false.",
1255+
"DESCRIPTION_CSS_COLOR_PREVIEW_INLINE": "When true, color codes in the editor will display a colored background behind them, making it easy to visualize colors while editing CSS, else false."
12551256
});

0 commit comments

Comments
 (0)