|
1 | 1 | import type * as CSS from 'vscode-css-languageservice'
|
2 | 2 | import type { TextDocument } from 'vscode-languageserver-textdocument'
|
3 |
| -import type { |
4 |
| - LanguageServicePlugin, |
5 |
| - VirtualCode, |
| 3 | +import { |
| 4 | + type Color, |
| 5 | + type LanguageServicePlugin, |
| 6 | + TextEdit, |
| 7 | + type VirtualCode, |
6 | 8 | } from '@volar/language-service'
|
7 | 9 | import { type Provide, create as baseCreate } from 'volar-service-css'
|
8 | 10 | import { URI } from 'vscode-uri'
|
9 | 11 | import { MpxVirtualCode } from '@mpxjs/language-core'
|
10 | 12 |
|
| 13 | +function parseStylusColors(document: TextDocument): CSS.ColorInformation[] { |
| 14 | + const colors: CSS.ColorInformation[] = [] |
| 15 | + const text = document.getText() |
| 16 | + |
| 17 | + const regex = /#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b/g |
| 18 | + let match: RegExpExecArray | null |
| 19 | + while ((match = regex.exec(text))) { |
| 20 | + const start = document.positionAt(match.index) |
| 21 | + const end = document.positionAt(match.index + match[0].length) |
| 22 | + const hex = match[1] |
| 23 | + let r = 0, |
| 24 | + g = 0, |
| 25 | + b = 0 |
| 26 | + if (hex.length === 3) { |
| 27 | + r = parseInt(hex[0] + hex[0], 16) |
| 28 | + g = parseInt(hex[1] + hex[1], 16) |
| 29 | + b = parseInt(hex[2] + hex[2], 16) |
| 30 | + } else { |
| 31 | + r = parseInt(hex.slice(0, 2), 16) |
| 32 | + g = parseInt(hex.slice(2, 4), 16) |
| 33 | + b = parseInt(hex.slice(4, 6), 16) |
| 34 | + } |
| 35 | + const color: Color = { |
| 36 | + red: r / 255, |
| 37 | + green: g / 255, |
| 38 | + blue: b / 255, |
| 39 | + alpha: 1, |
| 40 | + } |
| 41 | + colors.push({ range: { start, end }, color }) |
| 42 | + } |
| 43 | + |
| 44 | + return colors |
| 45 | +} |
| 46 | + |
| 47 | +function parseStylusColorPresentation( |
| 48 | + range: CSS.Range, |
| 49 | + color: CSS.Color, |
| 50 | +): CSS.ColorPresentation[] { |
| 51 | + const colors: CSS.ColorPresentation[] = [] |
| 52 | + const r = Math.round(color.red * 255) |
| 53 | + const g = Math.round(color.green * 255) |
| 54 | + const b = Math.round(color.blue * 255) |
| 55 | + const hex = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}` |
| 56 | + |
| 57 | + colors.push({ |
| 58 | + label: hex, |
| 59 | + textEdit: TextEdit.replace(range, hex), |
| 60 | + }) |
| 61 | + return colors |
| 62 | +} |
| 63 | + |
11 | 64 | export function create(): LanguageServicePlugin {
|
12 | 65 | const base = baseCreate({
|
13 | 66 | scssDocumentSelector: ['scss', 'postcss'],
|
@@ -112,6 +165,31 @@ export function create(): LanguageServicePlugin {
|
112 | 165 | return cssLs.prepareRename(document, position, stylesheet)
|
113 | 166 | })
|
114 | 167 | },
|
| 168 | + |
| 169 | + /** |
| 170 | + * support colorDecorators and colorPresentation |
| 171 | + */ |
| 172 | + provideDocumentColors(document: TextDocument) { |
| 173 | + if (document.languageId === 'stylus') { |
| 174 | + return parseStylusColors(document) |
| 175 | + } |
| 176 | + return worker(document, (stylesheet, cssLs) => { |
| 177 | + return cssLs.findDocumentColors(document, stylesheet) |
| 178 | + }) |
| 179 | + }, |
| 180 | + provideColorPresentations(document, color, range) { |
| 181 | + if (document.languageId === 'stylus') { |
| 182 | + return parseStylusColorPresentation(range, color) |
| 183 | + } |
| 184 | + return worker(document, (stylesheet, cssLs) => { |
| 185 | + return cssLs.getColorPresentations( |
| 186 | + document, |
| 187 | + stylesheet, |
| 188 | + color, |
| 189 | + range, |
| 190 | + ) |
| 191 | + }) |
| 192 | + }, |
115 | 193 | }
|
116 | 194 |
|
117 | 195 | function worker<T>(
|
|
0 commit comments