From dff758e4bec7650582d3505941e4cb353d43f788 Mon Sep 17 00:00:00 2001 From: WT <24277775+zam157@users.noreply.github.com> Date: Wed, 29 Jun 2022 10:28:47 +0800 Subject: [PATCH 1/8] color block --- packages/vscode/src/annotation.ts | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/packages/vscode/src/annotation.ts b/packages/vscode/src/annotation.ts index efcee91ea3..83e9972310 100644 --- a/packages/vscode/src/annotation.ts +++ b/packages/vscode/src/annotation.ts @@ -1,6 +1,9 @@ import path from 'path' import type { DecorationOptions, ExtensionContext, StatusBarItem } from 'vscode' import { DecorationRangeBehavior, MarkdownString, Range, window, workspace } from 'vscode' +import { parseColor } from '@unocss/preset-mini' +import type { Theme } from '@unocss/preset-mini' +import { hex2rgba } from '@unocss/preset-mini/utils' import { INCLUDE_COMMENT_IDE, getMatchedPositions } from './integration' import { log } from './log' import { getPrettiedMarkdown, isCssId, throttle } from './utils' @@ -47,6 +50,26 @@ export async function registerAnnotations( rangeBehavior: DecorationRangeBehavior.ClosedClosed, }) + const colorDecoration = window.createTextEditorDecorationType({ + before: { + width: '0.8em', + height: '0.8em', + contentText: ' ', + border: '0.1em solid', + margin: '0.1em 0.2em 0', + }, + dark: { + before: { + borderColor: '#eeeeee', + }, + }, + light: { + before: { + borderColor: '#000000', + }, + }, + }) + async function updateAnnotation(editor = window.activeTextEditor) { try { const doc = editor?.document @@ -67,10 +90,46 @@ export async function registerAnnotations( const result = await ctx.uno.generate(code, { id, preflights: false, minify: true }) + const theme = ctx.uno.config.theme as Theme + + const attributifyRE = /(?<=^\[.+~?=").*(?="\]$)/ + const colorsMap = new Map() + + for (const i of result.matched) { + const matchedAttr = i.match(attributifyRE) + const body = matchedAttr ? matchedAttr[0].split(':').at(-1) ?? '' : i // remove prefix e.g. `dark:` `hover:` + + // remove color body's prefix e.g. `bg-` `border-` `text-` + for (const part of body.split(/\d|-/)) { + if (theme.colors?.[part]) { + const subStart = body.indexOf(part) + const parsedResult = parseColor(body.substring(subStart), theme) + + if (parsedResult?.color) { + const rgbaValue = hex2rgba(parsedResult.color) + colorsMap.set(i.replace('~', ''), rgbaValue ? `rgba(${rgbaValue.join(',')},${parsedResult.alpha ?? 1})` : '') + } + } + } + } + + const colorRanges: DecorationOptions[] = [] + + const positionCache = new Map() + const ranges: DecorationOptions[] = ( await Promise.all( getMatchedPositions(code, Array.from(result.matched)) .map(async (i): Promise => { + // side-effect: update colorRanges + if (colorsMap.has(i[2]) && !positionCache.has(`${i[0]}:${i[1]}`)) { + positionCache.set(`${i[0]}:${i[1]}`, i[2]) + colorRanges.push({ + range: new Range(doc.positionAt(i[0]), doc.positionAt(i[1])), + renderOptions: { before: { backgroundColor: colorsMap.get(i[2]) } }, + }) + } + try { const md = await getPrettiedMarkdown(ctx!.uno, i[2]) return { @@ -89,6 +148,8 @@ export async function registerAnnotations( ) ).filter(Boolean) + editor.setDecorations(colorDecoration, colorRanges) + if (underline) { editor.setDecorations(NoneDecoration, []) editor.setDecorations(UnderlineDecoration, ranges) @@ -105,6 +166,7 @@ export async function registerAnnotations( function reset() { editor?.setDecorations(UnderlineDecoration, []) editor?.setDecorations(NoneDecoration, []) + editor?.setDecorations(colorDecoration, []) status.hide() } } From 56da50912fa372c1a55eb8cc662fa099eb764aab Mon Sep 17 00:00:00 2001 From: WT <24277775+zam157@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:52:07 +0800 Subject: [PATCH 2/8] better approach of getting matched colors --- packages/vscode/src/annotation.ts | 37 +++++-------------------------- packages/vscode/src/utils.ts | 29 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/packages/vscode/src/annotation.ts b/packages/vscode/src/annotation.ts index 83e9972310..aa48eb69ac 100644 --- a/packages/vscode/src/annotation.ts +++ b/packages/vscode/src/annotation.ts @@ -1,12 +1,9 @@ import path from 'path' import type { DecorationOptions, ExtensionContext, StatusBarItem } from 'vscode' import { DecorationRangeBehavior, MarkdownString, Range, window, workspace } from 'vscode' -import { parseColor } from '@unocss/preset-mini' -import type { Theme } from '@unocss/preset-mini' -import { hex2rgba } from '@unocss/preset-mini/utils' import { INCLUDE_COMMENT_IDE, getMatchedPositions } from './integration' import { log } from './log' -import { getPrettiedMarkdown, isCssId, throttle } from './utils' +import { getColorsMap, getPrettiedMarkdown, isCssId, throttle } from './utils' import type { ContextLoader } from './contextLoader' export async function registerAnnotations( @@ -90,40 +87,17 @@ export async function registerAnnotations( const result = await ctx.uno.generate(code, { id, preflights: false, minify: true }) - const theme = ctx.uno.config.theme as Theme - - const attributifyRE = /(?<=^\[.+~?=").*(?="\]$)/ - const colorsMap = new Map() - - for (const i of result.matched) { - const matchedAttr = i.match(attributifyRE) - const body = matchedAttr ? matchedAttr[0].split(':').at(-1) ?? '' : i // remove prefix e.g. `dark:` `hover:` - - // remove color body's prefix e.g. `bg-` `border-` `text-` - for (const part of body.split(/\d|-/)) { - if (theme.colors?.[part]) { - const subStart = body.indexOf(part) - const parsedResult = parseColor(body.substring(subStart), theme) - - if (parsedResult?.color) { - const rgbaValue = hex2rgba(parsedResult.color) - colorsMap.set(i.replace('~', ''), rgbaValue ? `rgba(${rgbaValue.join(',')},${parsedResult.alpha ?? 1})` : '') - } - } - } - } - + const colorsMap = getColorsMap(ctx.uno, result) const colorRanges: DecorationOptions[] = [] - - const positionCache = new Map() + const _colorPositionsCache = new Map() // cache for avoid duplicated color ranges const ranges: DecorationOptions[] = ( await Promise.all( getMatchedPositions(code, Array.from(result.matched)) .map(async (i): Promise => { // side-effect: update colorRanges - if (colorsMap.has(i[2]) && !positionCache.has(`${i[0]}:${i[1]}`)) { - positionCache.set(`${i[0]}:${i[1]}`, i[2]) + if (colorsMap.has(i[2]) && !_colorPositionsCache.has(`${i[0]}:${i[1]}`)) { + _colorPositionsCache.set(`${i[0]}:${i[1]}`, i[2]) colorRanges.push({ range: new Range(doc.positionAt(i[0]), doc.positionAt(i[1])), renderOptions: { before: { backgroundColor: colorsMap.get(i[2]) } }, @@ -148,6 +122,7 @@ export async function registerAnnotations( ) ).filter(Boolean) + _colorPositionsCache.clear() editor.setDecorations(colorDecoration, colorRanges) if (underline) { diff --git a/packages/vscode/src/utils.ts b/packages/vscode/src/utils.ts index 2d21151018..04ac7b4f90 100644 --- a/packages/vscode/src/utils.ts +++ b/packages/vscode/src/utils.ts @@ -1,8 +1,10 @@ import path from 'path' -import type { UnoGenerator } from '@unocss/core' +import type { GenerateResult, UnoGenerator } from '@unocss/core' import { cssIdRE } from '@unocss/core' import prettier from 'prettier/standalone' import parserCSS from 'prettier/parser-postcss' +import type { Theme } from '@unocss/preset-mini' +import { parseColor } from '@unocss/preset-mini' export function throttle any)>(func: T, timeFrame: number): T { let lastTime = 0 @@ -37,6 +39,31 @@ export async function getPrettiedMarkdown(uno: UnoGenerator, util: string) { return `\`\`\`css\n${(await getPrettiedCSS(uno, util)).prettified}\n\`\`\`` } +const matchedAttributifyRE = /(?<=^\[.+~?=").*(?="\]$)/ +export function getColorsMap(uno: UnoGenerator, result: GenerateResult) { + const theme = uno.config.theme as Theme + const colorNames = Object.keys(theme.colors ?? {}).map(colorName => colorName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()) + const colorsMap = new Map() + + for (const i of result.matched) { + const matchedAttr = i.match(matchedAttributifyRE) + const body = matchedAttr ? matchedAttr[0].split(':').at(-1) ?? '' : i // remove prefix e.g. `dark:` `hover:` + + for (const colorName of colorNames) { + const nameIndex = body.indexOf(colorName) + if (nameIndex > -1) { + const parsedResult = parseColor(body.substring(nameIndex), theme) + if (parsedResult?.color) + colorsMap.set(i.replace('~', ''), parsedResult.color) + + break + } + } + } + + return colorsMap +} + export function isCssId(id: string) { return cssIdRE.test(id) } From 98b9ac495bdd473854915d705e3b9e124a6e10cc Mon Sep 17 00:00:00 2001 From: WT <24277775+zam157@users.noreply.github.com> Date: Wed, 29 Jun 2022 22:55:23 +0800 Subject: [PATCH 3/8] show rgba instead of hex --- packages/vscode/src/utils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/vscode/src/utils.ts b/packages/vscode/src/utils.ts index 04ac7b4f90..c43cc1bafd 100644 --- a/packages/vscode/src/utils.ts +++ b/packages/vscode/src/utils.ts @@ -53,8 +53,10 @@ export function getColorsMap(uno: UnoGenerator, result: GenerateResult) { const nameIndex = body.indexOf(colorName) if (nameIndex > -1) { const parsedResult = parseColor(body.substring(nameIndex), theme) - if (parsedResult?.color) - colorsMap.set(i.replace('~', ''), parsedResult.color) + if (parsedResult?.cssColor) { + const { alpha: cssAlpha, components } = parsedResult.cssColor + colorsMap.set(i.replace('~', ''), `rgba(${components.join(',')},${parsedResult.alpha ?? cssAlpha ?? 1})`) + } break } From f6ab03efba6d594c765001e80e7efdca311ac82a Mon Sep 17 00:00:00 2001 From: WT <24277775+zam157@users.noreply.github.com> Date: Thu, 30 Jun 2022 02:56:18 +0800 Subject: [PATCH 4/8] cache colorsMap, fix matching camelCase failure --- packages/vscode/src/utils.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/vscode/src/utils.ts b/packages/vscode/src/utils.ts index c43cc1bafd..c20c8d9a4f 100644 --- a/packages/vscode/src/utils.ts +++ b/packages/vscode/src/utils.ts @@ -5,6 +5,7 @@ import prettier from 'prettier/standalone' import parserCSS from 'prettier/parser-postcss' import type { Theme } from '@unocss/preset-mini' import { parseColor } from '@unocss/preset-mini' +import { colorToString } from '@unocss/preset-mini/utils' export function throttle any)>(func: T, timeFrame: number): T { let lastTime = 0 @@ -40,12 +41,20 @@ export async function getPrettiedMarkdown(uno: UnoGenerator, util: string) { } const matchedAttributifyRE = /(?<=^\[.+~?=").*(?="\]$)/ +const _colorsMapCache = new Map() export function getColorsMap(uno: UnoGenerator, result: GenerateResult) { const theme = uno.config.theme as Theme - const colorNames = Object.keys(theme.colors ?? {}).map(colorName => colorName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()) + const themeColorNames = Object.keys(theme.colors ?? {}) + const colorNames = themeColorNames.concat(themeColorNames.map(colorName => colorName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase())) const colorsMap = new Map() for (const i of result.matched) { + const _i = i.replace('~="', '="') + if (_colorsMapCache.get(_i)) { + colorsMap.set(_i, _colorsMapCache.get(_i)!) + continue + } + const matchedAttr = i.match(matchedAttributifyRE) const body = matchedAttr ? matchedAttr[0].split(':').at(-1) ?? '' : i // remove prefix e.g. `dark:` `hover:` @@ -54,8 +63,9 @@ export function getColorsMap(uno: UnoGenerator, result: GenerateResult) { if (nameIndex > -1) { const parsedResult = parseColor(body.substring(nameIndex), theme) if (parsedResult?.cssColor) { - const { alpha: cssAlpha, components } = parsedResult.cssColor - colorsMap.set(i.replace('~', ''), `rgba(${components.join(',')},${parsedResult.alpha ?? cssAlpha ?? 1})`) + const color = colorToString(parsedResult.cssColor, parsedResult.alpha) + colorsMap.set(_i, color) + _colorsMapCache.set(_i, color) } break @@ -63,6 +73,9 @@ export function getColorsMap(uno: UnoGenerator, result: GenerateResult) { } } + if (_colorsMapCache.size > 5000) + _colorsMapCache.clear() + return colorsMap } From abb84858898b8b341b6268efc19b8eee3d4843e7 Mon Sep 17 00:00:00 2001 From: WT <24277775+zam157@users.noreply.github.com> Date: Thu, 30 Jun 2022 03:34:44 +0800 Subject: [PATCH 5/8] add option to enable/diable color preview feature --- packages/vscode/package.json | 5 +++++ packages/vscode/src/annotation.ts | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/vscode/package.json b/packages/vscode/package.json index c946898c9e..b402ecad11 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -47,6 +47,11 @@ "type": "boolean", "default": true, "description": "Enable/disable underline decoration for class names" + }, + "unocss.colorPreview": { + "type": "boolean", + "default": false, + "description": "Enable/disable color preview decorations" } } } diff --git a/packages/vscode/src/annotation.ts b/packages/vscode/src/annotation.ts index aa48eb69ac..d9783f1f50 100644 --- a/packages/vscode/src/annotation.ts +++ b/packages/vscode/src/annotation.ts @@ -13,11 +13,16 @@ export async function registerAnnotations( ext: ExtensionContext, ) { let underline: boolean = workspace.getConfiguration().get('unocss.underline') ?? true + let colorPreview: boolean = workspace.getConfiguration().get('unocss.colorPreview') ?? false ext.subscriptions.push(workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration('unocss.underline')) { underline = workspace.getConfiguration().get('unocss.underline') ?? true updateAnnotation() } + if (event.affectsConfiguration('unocss.colorPreview')) { + colorPreview = workspace.getConfiguration().get('unocss.colorPreview') ?? false + updateAnnotation() + } })) workspace.onDidSaveTextDocument(async (doc) => { @@ -96,7 +101,7 @@ export async function registerAnnotations( getMatchedPositions(code, Array.from(result.matched)) .map(async (i): Promise => { // side-effect: update colorRanges - if (colorsMap.has(i[2]) && !_colorPositionsCache.has(`${i[0]}:${i[1]}`)) { + if (colorPreview && colorsMap.has(i[2]) && !_colorPositionsCache.has(`${i[0]}:${i[1]}`)) { _colorPositionsCache.set(`${i[0]}:${i[1]}`, i[2]) colorRanges.push({ range: new Range(doc.positionAt(i[0]), doc.positionAt(i[1])), From 8c080759910f93acf8d1ff29494b8cac4130f381 Mon Sep 17 00:00:00 2001 From: WT <24277775+zam157@users.noreply.github.com> Date: Thu, 30 Jun 2022 05:08:10 +0800 Subject: [PATCH 6/8] set defualt color preview option to true --- packages/vscode/package.json | 2 +- packages/vscode/src/annotation.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vscode/package.json b/packages/vscode/package.json index b402ecad11..13b8ac0e38 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -50,7 +50,7 @@ }, "unocss.colorPreview": { "type": "boolean", - "default": false, + "default": true, "description": "Enable/disable color preview decorations" } } diff --git a/packages/vscode/src/annotation.ts b/packages/vscode/src/annotation.ts index d9783f1f50..5f92987258 100644 --- a/packages/vscode/src/annotation.ts +++ b/packages/vscode/src/annotation.ts @@ -13,14 +13,14 @@ export async function registerAnnotations( ext: ExtensionContext, ) { let underline: boolean = workspace.getConfiguration().get('unocss.underline') ?? true - let colorPreview: boolean = workspace.getConfiguration().get('unocss.colorPreview') ?? false + let colorPreview: boolean = workspace.getConfiguration().get('unocss.colorPreview') ?? true ext.subscriptions.push(workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration('unocss.underline')) { underline = workspace.getConfiguration().get('unocss.underline') ?? true updateAnnotation() } if (event.affectsConfiguration('unocss.colorPreview')) { - colorPreview = workspace.getConfiguration().get('unocss.colorPreview') ?? false + colorPreview = workspace.getConfiguration().get('unocss.colorPreview') ?? true updateAnnotation() } })) From 8d55ca273d358e8d405a295f400e85c1213764b8 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 30 Jun 2022 10:52:14 +0800 Subject: [PATCH 7/8] chore: styling --- packages/vscode/package.json | 2 +- packages/vscode/src/annotation.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/vscode/package.json b/packages/vscode/package.json index 13b8ac0e38..ece6e7013e 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -1,6 +1,6 @@ { "publisher": "antfu", - "name": "@unocss/vscode", + "name": "unocss", "displayName": "UnoCSS", "version": "0.41.2", "private": true, diff --git a/packages/vscode/src/annotation.ts b/packages/vscode/src/annotation.ts index 5f92987258..b9810ec942 100644 --- a/packages/vscode/src/annotation.ts +++ b/packages/vscode/src/annotation.ts @@ -54,20 +54,20 @@ export async function registerAnnotations( const colorDecoration = window.createTextEditorDecorationType({ before: { - width: '0.8em', - height: '0.8em', + width: '0.9em', + height: '0.9em', contentText: ' ', - border: '0.1em solid', - margin: '0.1em 0.2em 0', + border: '1px solid', + margin: 'auto 0.2em auto 0;vertical-align: middle;border-radius:50%;', }, dark: { before: { - borderColor: '#eeeeee', + borderColor: '#eeeeee50', }, }, light: { before: { - borderColor: '#000000', + borderColor: '#00000050', }, }, }) From 4a2cf43e0b0b0ea91ce6da0402951e9e73dd2050 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 30 Jun 2022 10:56:04 +0800 Subject: [PATCH 8/8] chore: update --- packages/vscode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vscode/package.json b/packages/vscode/package.json index ece6e7013e..aa445f17e9 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -1,6 +1,6 @@ { "publisher": "antfu", - "name": "unocss", + "name": "@vscode/unocss", "displayName": "UnoCSS", "version": "0.41.2", "private": true,