Skip to content

Commit

Permalink
feat: inline color preview
Browse files Browse the repository at this point in the history
  • Loading branch information
abose committed Dec 10, 2024
1 parent 0919336 commit a0b0ead
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 12 deletions.
26 changes: 24 additions & 2 deletions src/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1491,19 +1491,41 @@ define(function (require, exports, module) {
};

/**
* Clears all mark of the given type. If nothing is given, clears all marks(Don't use this API without types!).
* Clears all marks of the given type. If a lineNumbers array is given, only clears marks on those lines.
* If no markType or lineNumbers are given, clears all marks (use cautiously).
* @param {string} [markType] - Optional, if given will only delete marks of that type. Else delete everything.
* @param {number[]} [lineNumbers] - Optional, array of line numbers where marks should be cleared.
*/
Editor.prototype.clearAllMarks = function (markType) {
Editor.prototype.clearAllMarks = function (markType, lineNumbers) {
const self = this;

self._codeMirror.operation(function () {
let marks = self.getAllMarks(markType);

if (lineNumbers && Array.isArray(lineNumbers)) {
// Filter marks to only those within the specified line numbers
marks = marks.filter(function (mark) {
const range = mark.find(); // Get the range of the mark
if (!range) {
return false;
}

const startLine = range.from.line;
const endLine = range.to.line;

// Check if the mark overlaps with any of the specified lines
return lineNumbers.some(line => line >= startLine && line <= endLine);
});
}

// Clear the filtered marks
for (let mark of marks) {
mark.clear();
}
});
};


/**
* Checks if two positions in the editor are the same.
*
Expand Down
84 changes: 75 additions & 9 deletions src/extensionsIntegrated/CSSColorPreview/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ define(function (require, exports, module) {
// Extension variables.
const COLOR_REGEX = ColorUtils.COLOR_REGEX, // used to match color
GUTTER_NAME = "CodeMirror-colorGutter",
COLOR_MARK_NAME = "colorMarker",
DUMMY_GUTTER_CLASS = "CodeMirror-colorGutter-none",
SINGLE_COLOR_PREVIEW_CLASS = "ico-cssColorPreview",
MULTI_COLOR_PREVIEW_CLASS = "ico-multiple-cssColorPreview",
Expand All @@ -50,12 +51,18 @@ define(function (require, exports, module) {

// For preferences settings, to toggle this feature on/off
const PREFERENCES_CSS_COLOR_PREVIEW = "colorPreview";
let enabled = true; // by default:- on
const PREFERENCES_INLINE_COLOR_PREVIEW = "colorPreviewInline";
let enabled = true, // by default:- on
inlinePreviewEnabled = false;

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

PreferencesManager.definePreference(PREFERENCES_INLINE_COLOR_PREVIEW, "boolean", enabled, {
description: Strings.DESCRIPTION_CSS_COLOR_PREVIEW_INLINE
});


/**
* Gets all the colors that are to be displayed
Expand Down Expand Up @@ -114,6 +121,16 @@ define(function (require, exports, module) {
}, 50);
}

function _colorMark(editor, from, to, color) {
editor.markText(COLOR_MARK_NAME, from, to, {
css: `
--bg-color-mark: ${color};
background: var(--bg-color-mark);
color: lch(from var(--bg-color-mark) calc((50 - l) * infinity) 0 0);
`
});
}

/**
* To display the color marks on the gutter
*
Expand Down Expand Up @@ -143,13 +160,13 @@ define(function (require, exports, module) {
// Single color preview
$marker = $("<i>")
.addClass(SINGLE_COLOR_PREVIEW_CLASS)
.css('background-color', obj.colorValues[0]);
.css('background-color', obj.colorValues[0].color);

editor.setGutterMarker(obj.lineNumber, GUTTER_NAME, $marker[0]);
$marker.click((event)=>{
event.preventDefault();
event.stopPropagation();
_colorIconClicked(editor, obj.lineNumber, obj.colorValues[0]);
_colorIconClicked(editor, obj.lineNumber, obj.colorValues[0].color);
});
} else {
// Multiple colors preview
Expand All @@ -168,13 +185,13 @@ define(function (require, exports, module) {
const $colorBox = $("<div>")
.addClass("color-box")
.css({
'background-color': color,
'background-color': color.color,
...positions[index]
});
$colorBox.click((event)=>{
event.preventDefault();
event.stopPropagation();
_colorIconClicked(editor, obj.lineNumber, color);
_colorIconClicked(editor, obj.lineNumber, color.color);
});
$marker.append($colorBox);
}
Expand All @@ -197,9 +214,36 @@ define(function (require, exports, module) {
}
}

function _applyInlineColor(editor, line) {
editor._currentlyColorMarkedLine = line;
editor.clearAllMarks(COLOR_MARK_NAME);
const colors = detectValidColorsInLine(editor, line);
for(let color of colors){
_colorMark(editor, {line, ch: color.index}, {line, ch: color.index + color.color.length},
color.color);
}
}

function _cursorActivity(_evt, editor){
// this is to prevent a gutter gap in the active line if there is no color on this line.
_addDummyGutterMarkerIfNotExist(editor, editor.getCursorPos().line);
const line = editor.getCursorPos().line;
if(enabled){
_addDummyGutterMarkerIfNotExist(editor, line);
}
if(!inlinePreviewEnabled){
return;
}
if(editor.hasSelection()){
if(editor._currentlyColorMarkedLine === line){
editor._currentlyColorMarkedLine = null;
editor.clearAllMarks(COLOR_MARK_NAME);
}
return;
}
if(editor._currentlyColorMarkedLine === line) {
return;
}
_applyInlineColor(editor, line);
}

/**
Expand Down Expand Up @@ -320,8 +364,7 @@ define(function (require, exports, module) {
});
}

// Return up to 4 colors
return validColors.slice(0, 4).map(item => item.color);
return validColors;
}

/**
Expand Down Expand Up @@ -392,10 +435,14 @@ define(function (require, exports, module) {
*/
function onChanged(_evt, instance, changeList) {
// for insertion and deletion, update the changed lines
if(!changeList || !changeList.length) {
if(!changeList || !changeList.length || !enabled) {
return;
}
const changeObj = changeList[0];
instance._currentlyColorMarkedLine = null;
if(inlinePreviewEnabled && changeObj.origin && changeObj.origin.startsWith("+InlineColorEditor")){
_applyInlineColor(instance, instance.getCursorPos().line);
}
if(changeList.length === 1 && changeObj.origin === '+input' || changeObj.origin === '+delete') {
// we only do the diff updates on single key type input/delete and not bulk changes
// somehow the performance degrades if we do the diff logic on large blocks.
Expand All @@ -415,10 +462,29 @@ define(function (require, exports, module) {
}
}

function inlinePreferenceChanged() {
inlinePreviewEnabled = PreferencesManager.get(PREFERENCES_INLINE_COLOR_PREVIEW);
const allActiveEditors = MainViewManager.getAllViewedEditors();

allActiveEditors.forEach((activeEditor) => {
const currEditor = activeEditor.editor;
if(!currEditor){
return;
}
if(!inlinePreviewEnabled) {
currEditor.clearAllMarks(COLOR_MARK_NAME);
} else {
_applyInlineColor(currEditor, currEditor.getCursorPos().line);
}
});
}

// init after appReady
AppInit.appReady(function () {
PreferencesManager.on("change", PREFERENCES_CSS_COLOR_PREVIEW, preferenceChanged);
PreferencesManager.on("change", PREFERENCES_INLINE_COLOR_PREVIEW, inlinePreferenceChanged);
preferenceChanged();
inlinePreferenceChanged();
registerHandlers();
});
});
Expand Down
3 changes: 2 additions & 1 deletion src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1251,5 +1251,6 @@ define({
// indent guides extension
"DESCRIPTION_INDENT_GUIDES_ENABLED": "true to show indent guide lines, else false.",
"DESCRIPTION_HIDE_FIRST": "true to show the first Indent Guide line else false.",
"DESCRIPTION_CSS_COLOR_PREVIEW": "true to display color previews in the gutter, else false."
"DESCRIPTION_CSS_COLOR_PREVIEW": "true to display color previews in the gutter, else false.",
"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."
});

0 comments on commit a0b0ead

Please sign in to comment.