1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts
index 8ac58761c1f1eb7c0b6f2cf6f38cf0eddaef183d..86f9fb70aa71b0bbb1c755fb20e3d66695fe776e 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -503,6 +503,11 @@ }
)
}
+const NUMBER_REGEX = /^(\d+\.?|\d*\.\d+)$/
+function isNumber(str: string): boolean {
+ return NUMBER_REGEX.test(str)
+}
+
async function provideClassNameCompletions(
state: State,
document: TextDocument,
@@ -537,14 +542,26 @@ })
const match = text
.substr(0, text.length - 1) // don't include that extra character from earlier
- .match(/\b(?<helper>config|theme)\(['"](?<keys>[^'"]*)$/)
+ .match(/\b(?<helper>config|theme)\(\s*['"]?(?<path>[^)'"]*)$/)
if (match === null) {
return null
}
+ let alpha: string
+ let path = match.groups.path.replace(/^['"]+/g, '')
+ let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]*))$/)
+ if (matches) {
+ path = matches[1]
+ alpha = matches[2]
+ }
+
+ if (alpha !== undefined) {
+ return null
+ }
+
let base = match.groups.helper === 'config' ? state.config : dlv(state.config, 'theme', {})
- let parts = match.groups.keys.split(/([\[\].]+)/)
+ let parts = path.split(/([\[\].]+)/)
let keys = parts.filter((_, i) => i % 2 === 0)
let separators = parts.filter((_, i) => i % 2 !== 0)
// let obj =
@@ -557,7 +574,7 @@ return arr.reduce((acc, cur) => acc + cur.length, 0)
}
let obj: any
- let offset: number = 0
+ let offset: number = keys[keys.length - 1].length
let separator: string = separators.length ? separators[separators.length - 1] : null
if (keys.length === 1) {
@@ -576,41 +593,73 @@ }
if (!obj) return null
+ let editRange = {
+ start: {
+ line: position.line,
+ character: position.character - offset,
+ },
+ end: position,
+ }
+
return {
isIncomplete: false,
- items: Object.keys(obj).map((item, index) => {
- let color = getColorFromValue(obj[item])
- const replaceDot: boolean = item.indexOf('.') !== -1 && separator && separator.endsWith('.')
- const insertClosingBrace: boolean =
- text.charAt(text.length - 1) !== ']' &&
- (replaceDot || (separator && separator.endsWith('[')))
- const detail = stringifyConfigValue(obj[item])
+ items: Object.keys(obj)
+ .sort((a, z) => {
+ let aIsNumber = isNumber(a)
+ let zIsNumber = isNumber(z)
+ if (aIsNumber && !zIsNumber) {
+ return -1
+ }
+ if (!aIsNumber && zIsNumber) {
+ return 1
+ }
+ if (aIsNumber && zIsNumber) {
+ return parseFloat(a) - parseFloat(z)
+ }
+ return 0
+ })
+ .map((item, index) => {
+ let color = getColorFromValue(obj[item])
+ const replaceDot: boolean = item.indexOf('.') !== -1 && separator && separator.endsWith('.')
+ const insertClosingBrace: boolean =
+ text.charAt(text.length - 1) !== ']' &&
+ (replaceDot || (separator && separator.endsWith('[')))
+ const detail = stringifyConfigValue(obj[item])
- return {
- label: item,
- filterText: `${replaceDot ? '.' : ''}${item}`,
- sortText: naturalExpand(index),
- kind: color ? 16 : isObject(obj[item]) ? 9 : 10,
- // VS Code bug causes some values to not display in some cases
- detail: detail === '0' || detail === 'transparent' ? `${detail} ` : detail,
- documentation:
- color && typeof color !== 'string' && (color.alpha ?? 1) !== 0
- ? culori.formatRgb(color)
- : null,
- textEdit: {
- newText: `${replaceDot ? '[' : ''}${item}${insertClosingBrace ? ']' : ''}`,
- range: {
- start: {
- line: position.line,
- character:
- position.character - keys[keys.length - 1].length - (replaceDot ? 1 : 0) - offset,
- },
- end: position,
+ return {
+ label: item,
+ sortText: naturalExpand(index),
+ commitCharacters: [!item.includes('.') && '.', !item.includes('[') && '['].filter(
+ Boolean
+ ),
+ kind: color ? 16 : isObject(obj[item]) ? 9 : 10,
+ // VS Code bug causes some values to not display in some cases
+ detail: detail === '0' || detail === 'transparent' ? `${detail} ` : detail,
+ documentation:
+ color && typeof color !== 'string' && (color.alpha ?? 1) !== 0
+ ? culori.formatRgb(color)
+ : null,
+ textEdit: {
+ newText: `${item}${insertClosingBrace ? ']' : ''}`,
+ range: editRange,
},
- },
- data: 'helper',
- }
- }),
+ additionalTextEdits: replaceDot
+ ? [
+ {
+ newText: '[',
+ range: {
+ start: {
+ ...editRange.start,
+ character: editRange.start.character - 1,
+ },
+ end: editRange.start,
+ },
+ },
+ ]
+ : [],
+ data: 'helper',
+ }
+ }),
}
}
|