@master/css-language-server 2.0.0-beta.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -0
- package/src/completionProvider.ts +307 -0
- package/src/constant.ts +1170 -0
- package/src/documentColorProvider.ts +296 -0
- package/src/hoverProvider.ts +158 -0
- package/src/masterCss.ts +80 -0
- package/src/server.ts +264 -0
- package/src/utils/hex-to-rgb.ts +8 -0
- package/src/utils/regex.ts +1 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TextDocuments,
|
|
3
|
+
ColorInformation,
|
|
4
|
+
Color,
|
|
5
|
+
DocumentColorParams,
|
|
6
|
+
Position,
|
|
7
|
+
ColorPresentationParams,
|
|
8
|
+
ColorPresentation,
|
|
9
|
+
TextEdit
|
|
10
|
+
} from 'vscode-languageserver/node'
|
|
11
|
+
import { TextDocument } from 'vscode-languageserver-textdocument'
|
|
12
|
+
|
|
13
|
+
import MasterCSS from '@master/css'
|
|
14
|
+
import { hexToRgb } from './utils/hex-to-rgb'
|
|
15
|
+
import { instancePattern } from './utils/regex'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export async function GetColorRender(DocumentColor: DocumentColorParams, documents: TextDocuments<TextDocument>): Promise<ColorInformation[]> {
|
|
19
|
+
const colors: ColorInformation[] = []
|
|
20
|
+
const documentUri = DocumentColor.textDocument.uri
|
|
21
|
+
const document = documents.get(documentUri)
|
|
22
|
+
const text = document?.getText() ?? ''
|
|
23
|
+
|
|
24
|
+
if (typeof document == undefined) {
|
|
25
|
+
return []
|
|
26
|
+
}
|
|
27
|
+
let classMatch: RegExpExecArray | null
|
|
28
|
+
const hexColorPattern = /(:\s*)'#([0-9a-fA-F]{6,8})'/g
|
|
29
|
+
let colorMatch: RegExpExecArray | null
|
|
30
|
+
|
|
31
|
+
const classPattern = new RegExp('(?<=colors:\\s*{\\s*.*)([^}]*)}','g')
|
|
32
|
+
while ((classMatch = classPattern.exec(text)) !== null) {
|
|
33
|
+
//#region for rgb、hls
|
|
34
|
+
while ((colorMatch = hexColorPattern.exec(classMatch[0]))) {
|
|
35
|
+
const colorInformation: ColorInformation = {
|
|
36
|
+
range: {
|
|
37
|
+
start: document?.positionAt(classMatch.index + colorMatch.index + colorMatch[1].length ) ?? Position.create(0, 0),
|
|
38
|
+
end: document?.positionAt(classMatch.index + colorMatch.index + colorMatch[0].length -1) ?? Position.create(0, 0)
|
|
39
|
+
},
|
|
40
|
+
color: getColorValue(hexToRgb(colorMatch[2]))
|
|
41
|
+
}
|
|
42
|
+
colors.push(colorInformation)
|
|
43
|
+
}
|
|
44
|
+
//#endregion for rgb、hls
|
|
45
|
+
}
|
|
46
|
+
return colors
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function GetDocumentColors(DocumentColor: DocumentColorParams, documents: TextDocuments<TextDocument>, classAttributes: string[], masterCss: MasterCSS = new MasterCSS()
|
|
50
|
+
): Promise<ColorInformation[]> {
|
|
51
|
+
let colors: ColorInformation[] = []
|
|
52
|
+
|
|
53
|
+
const documentUri = DocumentColor.textDocument.uri
|
|
54
|
+
const document = documents.get(documentUri)
|
|
55
|
+
const text = document?.getText() ?? ''
|
|
56
|
+
|
|
57
|
+
if (typeof document == undefined) {
|
|
58
|
+
return []
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const allMasterCssColorKeys = Object.keys(masterCss.colorsThemesMap)
|
|
62
|
+
|
|
63
|
+
let instanceMatch: RegExpExecArray | null
|
|
64
|
+
while ((instanceMatch = instancePattern.exec(text)) !== null) {
|
|
65
|
+
const instanceStartIndex = instanceMatch.index
|
|
66
|
+
const theme = masterCss.themeNames.find(x => instanceMatch?.[0]?.endsWith(`@${x}`)) ?? ''
|
|
67
|
+
|
|
68
|
+
const colorPattern = /(?<=[:;|])(?:#?\w+(?:-[\d]{1,2})?(?:\/.?[\d]*)?(?:\([^\s)]+\))?)/g
|
|
69
|
+
const rgbaColorPattern = /rgba?\(([\d.]+),([\d.]+),([\d.]+)(?:,([\d.]+))?\)/g
|
|
70
|
+
const hslaColorPattern = /hsla?\(([\d.]+),([\d.]+)%,([\d.]+)%(?:,([\d.]+))?\)/g
|
|
71
|
+
const hexColorPattern = /#([0-9a-fA-F]{6,8})/g
|
|
72
|
+
let colorMatch: RegExpExecArray | null
|
|
73
|
+
let colorMatch2: RegExpExecArray | null
|
|
74
|
+
let colorName: string
|
|
75
|
+
let colorNumber: number
|
|
76
|
+
let colorAlpha: number
|
|
77
|
+
//check color
|
|
78
|
+
while ((colorMatch = colorPattern.exec(instanceMatch[0])) !== null) {
|
|
79
|
+
//#region for rgb、hls
|
|
80
|
+
if ((colorMatch2 = rgbaColorPattern.exec(colorMatch[0]))) {
|
|
81
|
+
const colorInformation: ColorInformation = {
|
|
82
|
+
range: {
|
|
83
|
+
start: document?.positionAt(instanceStartIndex + colorMatch.index) ?? Position.create(0, 0),
|
|
84
|
+
end: document?.positionAt(instanceStartIndex + colorMatch.index + colorMatch[0].length) ?? Position.create(0, 0)
|
|
85
|
+
},
|
|
86
|
+
color: getColorValue({ red: Number(colorMatch2[1]), green: Number(colorMatch2[2]), blue: Number(colorMatch2[3]), alpha: colorMatch2[4] == undefined ? 1 : Number(colorMatch2[4]) })
|
|
87
|
+
}
|
|
88
|
+
colors.push(colorInformation)
|
|
89
|
+
}
|
|
90
|
+
else if ((colorMatch2 = hslaColorPattern.exec(colorMatch[0]))) {
|
|
91
|
+
const colorInformation: ColorInformation = {
|
|
92
|
+
range: {
|
|
93
|
+
start: document?.positionAt(instanceStartIndex + colorMatch.index) ?? Position.create(0, 0),
|
|
94
|
+
end: document?.positionAt(instanceStartIndex + colorMatch.index + colorMatch[0].length) ?? Position.create(0, 0)
|
|
95
|
+
},
|
|
96
|
+
color: getColorValue(hslToRgb(Number(colorMatch2[1]), Number(colorMatch2[2]), Number(colorMatch2[3]), colorMatch2[4] == undefined ? 1 : Number(colorMatch2[4])))
|
|
97
|
+
}
|
|
98
|
+
colors.push(colorInformation)
|
|
99
|
+
}
|
|
100
|
+
else if ((colorMatch2 = hexColorPattern.exec(colorMatch[0]))) {
|
|
101
|
+
const colorInformation: ColorInformation = {
|
|
102
|
+
range: {
|
|
103
|
+
start: document?.positionAt(instanceStartIndex + colorMatch.index) ?? Position.create(0, 0),
|
|
104
|
+
end: document?.positionAt(instanceStartIndex + colorMatch.index + colorMatch[0].length) ?? Position.create(0, 0)
|
|
105
|
+
},
|
|
106
|
+
color: getColorValue(hexToRgb(colorMatch2[1]))
|
|
107
|
+
}
|
|
108
|
+
colors.push(colorInformation)
|
|
109
|
+
}
|
|
110
|
+
//#endregion for rgb、hls
|
|
111
|
+
|
|
112
|
+
//#region for mastercss color
|
|
113
|
+
colorAlpha = 1
|
|
114
|
+
if (colorMatch[0].split('/').length == 2) {
|
|
115
|
+
colorAlpha = Number('0' + colorMatch[0].split('/')[1])
|
|
116
|
+
}
|
|
117
|
+
if (colorMatch[0].split('-').length == 1)//:black black/.5
|
|
118
|
+
{
|
|
119
|
+
colorName = colorMatch[0].split('/')[0]
|
|
120
|
+
colorName = colorName.endsWith('_') ? colorName.replace('_', '') : colorName
|
|
121
|
+
if (allMasterCssColorKeys.find(x => x == colorName)) {
|
|
122
|
+
const colorInformation: ColorInformation = {
|
|
123
|
+
range: {
|
|
124
|
+
start: document?.positionAt(instanceStartIndex + colorMatch.index) ?? Position.create(0, 0),
|
|
125
|
+
end: document?.positionAt(instanceStartIndex + colorMatch.index + colorMatch[0].length) ?? Position.create(0, 0)
|
|
126
|
+
},
|
|
127
|
+
color: getColorsRGBA(colorName, '', colorAlpha, theme, masterCss)
|
|
128
|
+
}
|
|
129
|
+
colors.push(colorInformation)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
else if (colorMatch[0].split('-').length == 2) { //:red-60 red-60/.5
|
|
134
|
+
|
|
135
|
+
colorName = colorMatch[0].split('-')[0]
|
|
136
|
+
colorNumber = Number(colorMatch[0].split('-')[1].split('/')[0])
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if (allMasterCssColorKeys.find(x => x == colorName) && colorNumber > 0 && colorNumber < 100) {
|
|
140
|
+
const colorInformation: ColorInformation = {
|
|
141
|
+
range: {
|
|
142
|
+
start: document?.positionAt(instanceStartIndex + colorMatch.index) ?? Position.create(0, 0),
|
|
143
|
+
end: document?.positionAt(instanceStartIndex + colorMatch.index + colorMatch[0].length) ?? Position.create(0, 0)
|
|
144
|
+
},
|
|
145
|
+
color: getColorsRGBA(colorName, colorNumber, colorAlpha, theme, masterCss)
|
|
146
|
+
}
|
|
147
|
+
colors.push(colorInformation)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
else if (colorMatch[0].split('-').length != 2) {
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
//#endregion for mastercss color
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const set = new Set()
|
|
159
|
+
colors = colors.filter(item => {
|
|
160
|
+
if (set.has(document?.offsetAt(item.range.start))) {
|
|
161
|
+
return false
|
|
162
|
+
} else {
|
|
163
|
+
set.add(document?.offsetAt(item.range.start))
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
return colors
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getColorsRGBA(colorName: string, colorNumber: number | string, colorAlpha = 1, theme = '', masterCss: MasterCSS = new MasterCSS()): Color {
|
|
172
|
+
try {
|
|
173
|
+
const colorNumberMap = masterCss.colorsThemesMap[colorName]
|
|
174
|
+
const levelRgb = hexToRgb(colorNumberMap[colorNumber][theme] ?? colorNumberMap[colorNumber][''] ?? Object.values(colorNumberMap[colorNumber])[0])
|
|
175
|
+
|
|
176
|
+
return { red: levelRgb.red/255, green: levelRgb.green/255, blue: levelRgb.blue/255, alpha: colorAlpha }
|
|
177
|
+
} catch(ex) {
|
|
178
|
+
return { red: 0, green: 0, blue: 0, alpha: 1 }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export interface HWBA { h: number; w: number; b: number; a: number; }
|
|
182
|
+
|
|
183
|
+
export interface HSLA { h: number; s: number; l: number; a: number; }
|
|
184
|
+
|
|
185
|
+
function toTwoDigitHex(n: number): string {
|
|
186
|
+
const r = n.toString(16)
|
|
187
|
+
return r.length !== 2 ? '0' + r : r
|
|
188
|
+
}
|
|
189
|
+
export function hslFromColor(rgba: Color): HSLA {
|
|
190
|
+
const r = rgba.red
|
|
191
|
+
const g = rgba.green
|
|
192
|
+
const b = rgba.blue
|
|
193
|
+
const a = rgba.alpha
|
|
194
|
+
|
|
195
|
+
const max = Math.max(r, g, b)
|
|
196
|
+
const min = Math.min(r, g, b)
|
|
197
|
+
let h = 0
|
|
198
|
+
let s = 0
|
|
199
|
+
const l = (min + max) / 2
|
|
200
|
+
const chroma = max - min
|
|
201
|
+
|
|
202
|
+
if (chroma > 0) {
|
|
203
|
+
s = Math.min((l <= 0.5 ? chroma / (2 * l) : chroma / (2 - (2 * l))), 1)
|
|
204
|
+
|
|
205
|
+
switch (max) {
|
|
206
|
+
case r: h = (g - b) / chroma + (g < b ? 6 : 0); break
|
|
207
|
+
case g: h = (b - r) / chroma + 2; break
|
|
208
|
+
case b: h = (r - g) / chroma + 4; break
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
h *= 60
|
|
212
|
+
h = Math.round(h)
|
|
213
|
+
}
|
|
214
|
+
return { h, s, l, a }
|
|
215
|
+
}
|
|
216
|
+
export function hwbFromColor(rgba: Color): HWBA {
|
|
217
|
+
const hsl = hslFromColor(rgba)
|
|
218
|
+
const white = Math.min(rgba.red, rgba.green, rgba.blue)
|
|
219
|
+
const black = 1 - Math.max(rgba.red, rgba.green, rgba.blue)
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
h: hsl.h,
|
|
223
|
+
w: white,
|
|
224
|
+
b: black,
|
|
225
|
+
a: hsl.a
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
export function hslToRgb(h: number, s: number, l: number, alpha?: number): Color {
|
|
231
|
+
l /= 100
|
|
232
|
+
const k = (n: number) => (n + h / 30) % 12
|
|
233
|
+
const a = (s / 100) * Math.min(l, 1 - l)
|
|
234
|
+
const f = (n: number) =>
|
|
235
|
+
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))
|
|
236
|
+
|
|
237
|
+
return { red: 255 * f(0), green: 255 * f(8), blue: 255 * f(4), alpha: alpha ?? 1 }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function getColorValue(color: Color): Color {
|
|
241
|
+
return { red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0, alpha: color.alpha }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function GetColorPresentation(params: ColorPresentationParams, isColorRender = false) {
|
|
245
|
+
const result: ColorPresentation[] = []
|
|
246
|
+
const color = params.color
|
|
247
|
+
const range = params.range
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
const red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255)
|
|
251
|
+
|
|
252
|
+
let label
|
|
253
|
+
|
|
254
|
+
if(isColorRender)
|
|
255
|
+
{
|
|
256
|
+
if (color.alpha === 1) {
|
|
257
|
+
label = `'#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}`
|
|
258
|
+
} else {
|
|
259
|
+
label = `'#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}${toTwoDigitHex(Math.round(color.alpha * 255))}`
|
|
260
|
+
}
|
|
261
|
+
result.push({ label: label, textEdit: TextEdit.replace(range, label) })
|
|
262
|
+
return result
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (color.alpha === 1) {
|
|
266
|
+
label = `rgb(${red256},${green256},${blue256})`
|
|
267
|
+
} else {
|
|
268
|
+
label = `rgba(${red256},${green256},${blue256},${color.alpha})`
|
|
269
|
+
}
|
|
270
|
+
result.push({ label: label, textEdit: TextEdit.replace(range, label) })
|
|
271
|
+
|
|
272
|
+
if (color.alpha === 1) {
|
|
273
|
+
label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}`
|
|
274
|
+
} else {
|
|
275
|
+
label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}${toTwoDigitHex(Math.round(color.alpha * 255))}`
|
|
276
|
+
}
|
|
277
|
+
result.push({ label: label, textEdit: TextEdit.replace(range, label) })
|
|
278
|
+
|
|
279
|
+
const hsl = hslFromColor(color)
|
|
280
|
+
if (hsl.a === 1) {
|
|
281
|
+
label = `hsl(${hsl.h},${Math.round(hsl.s * 100)}%,${Math.round(hsl.l * 100)}%)`
|
|
282
|
+
} else {
|
|
283
|
+
label = `hsla(${hsl.h},${Math.round(hsl.s * 100)}%,${Math.round(hsl.l * 100)}%,${hsl.a})`
|
|
284
|
+
}
|
|
285
|
+
result.push({ label: label, textEdit: TextEdit.replace(range, label) })
|
|
286
|
+
|
|
287
|
+
// const hwb = hwbFromColor(color);
|
|
288
|
+
// if (hwb.a === 1) {
|
|
289
|
+
// label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}%)`;
|
|
290
|
+
// } else {
|
|
291
|
+
// label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}% / ${hwb.a})`;
|
|
292
|
+
// }
|
|
293
|
+
// result.push({ label: label, textEdit: TextEdit.replace(range, label) });
|
|
294
|
+
|
|
295
|
+
return result
|
|
296
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TextDocuments,
|
|
3
|
+
TextDocumentPositionParams,
|
|
4
|
+
Hover
|
|
5
|
+
} from 'vscode-languageserver/node'
|
|
6
|
+
import { Range, TextDocument } from 'vscode-languageserver-textdocument'
|
|
7
|
+
import MasterCSS, { render } from '@master/css'
|
|
8
|
+
import { css_beautify } from 'js-beautify'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export function GetHoverInstance(textDocumentPosition: TextDocumentPositionParams, documents: TextDocuments<TextDocument>) {
|
|
12
|
+
const documentUri = textDocumentPosition.textDocument.uri
|
|
13
|
+
const language = documentUri.substring(documentUri.lastIndexOf('.') + 1)
|
|
14
|
+
const position = textDocumentPosition.position
|
|
15
|
+
|
|
16
|
+
const classPattern = /(?:[^"{'\s])+(?=>\s|\b)/g
|
|
17
|
+
let classMatch: RegExpExecArray | null
|
|
18
|
+
|
|
19
|
+
const document = documents.get(documentUri)
|
|
20
|
+
|
|
21
|
+
let instanceRange =
|
|
22
|
+
{
|
|
23
|
+
start: { line: 0, character: 0 },
|
|
24
|
+
end: { line: 0, character: 0 },
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const line = document?.getText({
|
|
28
|
+
start: { line: position.line, character: 0 },
|
|
29
|
+
end: { line: position.line + 1, character: 0 },
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
let lineText: string = line == null ? '' : line
|
|
33
|
+
|
|
34
|
+
const text = document?.getText({
|
|
35
|
+
start: { line: 0, character: 0 },
|
|
36
|
+
end: { line: position.line, character: position.character },
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
//#region is in class
|
|
40
|
+
const lastClass = text?.lastIndexOf('class') ?? -1
|
|
41
|
+
const lastclassName = text?.lastIndexOf('className') ?? -1
|
|
42
|
+
const tsxclassName = text?.lastIndexOf('className={') ?? -1
|
|
43
|
+
|
|
44
|
+
if (lastClass + lastclassName + tsxclassName == -1) {
|
|
45
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const tsxclassNameMode = tsxclassName >= (lastClass > lastclassName ? lastClass : lastclassName)
|
|
49
|
+
let textSub = text?.substring(lastClass > lastclassName ? lastClass : lastclassName)
|
|
50
|
+
textSub = textSub == null ? '' : textSub
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
let classQuoted = '', classIndexAddOne = '', classIndexAddTwo = ''
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if (tsxclassNameMode) {
|
|
57
|
+
textSub = text?.substring(tsxclassName) == null ? '' : textSub
|
|
58
|
+
if (InCurlyBrackets(textSub) == false) {
|
|
59
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
if (lastClass > lastclassName) {
|
|
64
|
+
classIndexAddOne = textSub.substring(5).trimStart().charAt(0)
|
|
65
|
+
classIndexAddTwo = textSub.substring(5).trimStart().substring(1).trimStart().charAt(0)
|
|
66
|
+
}
|
|
67
|
+
else if (lastClass <= lastclassName) {
|
|
68
|
+
classIndexAddOne = textSub.substring(9).trimStart().charAt(0)
|
|
69
|
+
classIndexAddTwo = textSub.substring(9).trimStart().substring(1).trimStart().charAt(0)
|
|
70
|
+
}
|
|
71
|
+
classQuoted = classIndexAddOne + classIndexAddTwo
|
|
72
|
+
if (classQuoted != '=\'' && classQuoted != '=`' && classQuoted != '="') {
|
|
73
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const quotedSingle = textSub.split('\'').length - 1
|
|
78
|
+
const quotedDouble = textSub.split('"').length - 1
|
|
79
|
+
const quotedTemplate = textSub.split('`').length - 1
|
|
80
|
+
if (!tsxclassNameMode) {
|
|
81
|
+
if (classQuoted == '=\'' && quotedSingle >= 2) {
|
|
82
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
83
|
+
}
|
|
84
|
+
else if (classQuoted == '="' && quotedDouble >= 2) {
|
|
85
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
86
|
+
}
|
|
87
|
+
else if (classQuoted == '=`' && quotedTemplate >= 2) {
|
|
88
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!((quotedSingle > 0 || quotedDouble > 0 || quotedTemplate > 0) && (quotedSingle % 2 != 0 || quotedDouble % 2 != 0 || quotedTemplate % 2 != 0))) {
|
|
93
|
+
return { isInstance: false, instance: '', range: instanceRange, language: language }
|
|
94
|
+
}
|
|
95
|
+
//#endregion is in class
|
|
96
|
+
lineText = lineText.replace('[^\\S\\r\\n]+', ' ')
|
|
97
|
+
|
|
98
|
+
let instanceStart = lineText.substring(0, position.character).lastIndexOf(' ')
|
|
99
|
+
let instanceEnd = lineText.indexOf(' ', position.character)
|
|
100
|
+
instanceEnd = instanceEnd == -1 ? lineText.length - 1 : instanceEnd
|
|
101
|
+
|
|
102
|
+
if (tsxclassNameMode) {
|
|
103
|
+
instanceStart = instanceStart > lineText.substring(0, position.character).lastIndexOf('{') ? instanceStart : lineText.substring(0, position.character).lastIndexOf('{')
|
|
104
|
+
instanceEnd = instanceEnd < lineText.indexOf('}', position.character) ? instanceEnd : (lineText.indexOf('}', position.character)==-1?instanceEnd:lineText.indexOf('}', position.character))
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
instanceStart = instanceStart > lineText.substring(0, position.character).lastIndexOf(classIndexAddTwo) ? instanceStart : lineText.substring(0, position.character).lastIndexOf(classIndexAddTwo)
|
|
108
|
+
instanceEnd = instanceEnd > lineText.indexOf(classIndexAddTwo, position.character)
|
|
109
|
+
&& lineText.indexOf(classIndexAddTwo, position.character) != -1
|
|
110
|
+
? lineText.indexOf(classIndexAddTwo, position.character)
|
|
111
|
+
: instanceEnd
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
instanceRange = {
|
|
116
|
+
start: { line: position.line, character: instanceStart + 1 },
|
|
117
|
+
end: { line: position.line, character: instanceEnd },
|
|
118
|
+
}
|
|
119
|
+
const instance = document?.getText(instanceRange) ?? ''
|
|
120
|
+
|
|
121
|
+
return { isInstance: true, instance: instance, range: instanceRange, language: language }
|
|
122
|
+
}
|
|
123
|
+
function InCurlyBrackets(text: string): boolean {
|
|
124
|
+
let curlybrackets = 0
|
|
125
|
+
for (let i = 0; i < text.length; i++) {
|
|
126
|
+
if (text.charAt(i) == '{') {
|
|
127
|
+
curlybrackets += 1
|
|
128
|
+
}
|
|
129
|
+
else if (text.charAt(i) == '}') {
|
|
130
|
+
curlybrackets -= 1
|
|
131
|
+
if (curlybrackets <= 0) {
|
|
132
|
+
return false
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (curlybrackets <= 0) {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
return true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function doHover(instance: string, range: Range, masterCss: MasterCSS = new MasterCSS()): Hover | null {
|
|
143
|
+
const renderText = render(instance.split(' '), masterCss)
|
|
144
|
+
if (!renderText || renderText == ' ') {
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
contents: {
|
|
150
|
+
language: 'css',
|
|
151
|
+
value: css_beautify(renderText, {
|
|
152
|
+
newline_between_rules: true,
|
|
153
|
+
end_with_newline: true
|
|
154
|
+
})
|
|
155
|
+
},
|
|
156
|
+
range: range
|
|
157
|
+
}
|
|
158
|
+
}
|
package/src/masterCss.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TextDocuments,
|
|
3
|
+
Position,
|
|
4
|
+
} from 'vscode-languageserver/node'
|
|
5
|
+
import { Range, TextDocument } from 'vscode-languageserver-textdocument'
|
|
6
|
+
import { instancePattern } from './utils/regex'
|
|
7
|
+
|
|
8
|
+
export function PositionCheck(documentUri: string, position: Position, documents: TextDocuments<TextDocument>, RegExpList: string[]) {
|
|
9
|
+
const result: {
|
|
10
|
+
IsMatch: boolean,
|
|
11
|
+
PositionIndex: number,
|
|
12
|
+
classStartIndex: number,
|
|
13
|
+
classEndIndex: number,
|
|
14
|
+
classString: string,
|
|
15
|
+
instance: { range: Range, instanceString: string },
|
|
16
|
+
instanceList: { range: Range, instanceString: string }[],
|
|
17
|
+
} = {
|
|
18
|
+
IsMatch: false,
|
|
19
|
+
PositionIndex: 0,
|
|
20
|
+
classStartIndex: 0,
|
|
21
|
+
classEndIndex: 0,
|
|
22
|
+
classString: '',
|
|
23
|
+
instance: { range: { start: Position.create(0, 0), end: Position.create(0, 0) }, instanceString: '' },
|
|
24
|
+
instanceList: [],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const document = documents.get(documentUri)
|
|
28
|
+
let text = document?.getText() ?? ''
|
|
29
|
+
const positionIndex = document?.offsetAt(position) ?? 0
|
|
30
|
+
|
|
31
|
+
const startIndex = document?.offsetAt({ line: position.line - 100, character: 0}) ?? 0
|
|
32
|
+
const endIndex = document?.offsetAt({ line: position.line + 100, character: 0 }) ?? undefined
|
|
33
|
+
text = text.substring(startIndex, endIndex)
|
|
34
|
+
|
|
35
|
+
let instanceMatch: RegExpExecArray | null
|
|
36
|
+
let classMatch: RegExpExecArray | null
|
|
37
|
+
|
|
38
|
+
result.PositionIndex = positionIndex
|
|
39
|
+
|
|
40
|
+
RegExpList.forEach(x => {
|
|
41
|
+
const classPattern = new RegExp(x, 'g')
|
|
42
|
+
|
|
43
|
+
while ((classMatch = classPattern.exec(text)) !== null) {
|
|
44
|
+
if ((classMatch.index <= positionIndex && classMatch.index + classMatch[0].length - 1 >= positionIndex) == true) {
|
|
45
|
+
result.IsMatch = true
|
|
46
|
+
result.PositionIndex = positionIndex
|
|
47
|
+
result.classStartIndex = classMatch.index
|
|
48
|
+
result.classEndIndex = classMatch.index + classMatch[0].length - 1
|
|
49
|
+
result.classString = classMatch[0]
|
|
50
|
+
|
|
51
|
+
while ((instanceMatch = instancePattern.exec(classMatch[2])) !== null) {
|
|
52
|
+
result.instanceList.push(
|
|
53
|
+
{
|
|
54
|
+
range: {
|
|
55
|
+
start: document?.positionAt(classMatch.index + classMatch[1].length + instanceMatch.index) ?? Position.create(0, 0),
|
|
56
|
+
end: document?.positionAt(classMatch.index + classMatch[1].length + instanceMatch.index + instanceMatch[0].length) ?? Position.create(0, 0)
|
|
57
|
+
},
|
|
58
|
+
instanceString: instanceMatch[0]
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
if ((classMatch.index + classMatch[1].length + instanceMatch.index <= positionIndex && classMatch.index + classMatch[1].length + instanceMatch.index + instanceMatch[0].length >= positionIndex) == true) {
|
|
62
|
+
result.instance = {
|
|
63
|
+
range: {
|
|
64
|
+
start: document?.positionAt(classMatch.index + classMatch[1].length + instanceMatch.index) ?? Position.create(0, 0),
|
|
65
|
+
end: document?.positionAt(classMatch.index + classMatch[1].length + instanceMatch.index + instanceMatch[0].length) ?? Position.create(0, 0)
|
|
66
|
+
},
|
|
67
|
+
instanceString: instanceMatch[0]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return result
|
|
73
|
+
}
|
|
74
|
+
else if (classMatch.index > positionIndex) {
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
return result
|
|
80
|
+
}
|