Skip to content

Commit c9acd0d

Browse files
authored
Fix IntelliSense when separator is -- (#628)
* Fix IntelliSense when separator is `--` * Tidy up
1 parent d073bb9 commit c9acd0d

File tree

2 files changed

+27
-56
lines changed

2 files changed

+27
-56
lines changed

packages/tailwindcss-language-server/src/server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1504,7 +1504,10 @@ class TW {
15041504
resolveProvider: true,
15051505
triggerCharacters: [
15061506
...TRIGGER_CHARACTERS,
1507-
...projects.map((project) => project.state.separator).filter(Boolean),
1507+
...projects
1508+
.map((project) => project.state.separator)
1509+
.filter((sep) => typeof sep === 'string')
1510+
.map((sep) => sep.slice(-1)),
15081511
].filter(Boolean),
15091512
})
15101513

packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function getVariantsFromClassName(
66
className: string
77
): { variants: string[]; offset: number } {
88
let allVariants = Object.keys(state.variants)
9-
let parts = Array.from(splitAtTopLevelOnly(className, state.separator)).filter(Boolean)
9+
let parts = splitAtTopLevelOnly(className, state.separator).filter(Boolean)
1010
let variants = new Set<string>()
1111
let offset = 0
1212

@@ -29,66 +29,34 @@ export function getVariantsFromClassName(
2929
return { variants: Array.from(variants), offset }
3030
}
3131

32-
const REGEX_SPECIAL = /[\\^$.*+?()[\]{}|]/g
33-
const REGEX_HAS_SPECIAL = RegExp(REGEX_SPECIAL.source)
32+
// https://github.com/tailwindlabs/tailwindcss/blob/a8a2e2a7191fbd4bee044523aecbade5823a8664/src/util/splitAtTopLevelOnly.js
33+
function splitAtTopLevelOnly(input: string, separator: string): string[] {
34+
let stack: string[] = []
35+
let parts: string[] = []
36+
let lastPos = 0
3437

35-
function regexEscape(string: string): string {
36-
return string && REGEX_HAS_SPECIAL.test(string)
37-
? string.replace(REGEX_SPECIAL, '\\$&')
38-
: string || ''
39-
}
40-
41-
function* splitAtTopLevelOnly(input: string, separator: string): Generator<string> {
42-
let SPECIALS = new RegExp(`[(){}\\[\\]${regexEscape(separator)}]`, 'g')
43-
44-
let depth = 0
45-
let lastIndex = 0
46-
let found = false
47-
let separatorIndex = 0
48-
let separatorStart = 0
49-
let separatorLength = separator.length
38+
for (let idx = 0; idx < input.length; idx++) {
39+
let char = input[idx]
5040

51-
// Find all paren-like things & character
52-
// And only split on commas if they're top-level
53-
for (let match of input.matchAll(SPECIALS)) {
54-
let matchesSeparator = match[0] === separator[separatorIndex]
55-
let atEndOfSeparator = separatorIndex === separatorLength - 1
56-
let matchesFullSeparator = matchesSeparator && atEndOfSeparator
57-
58-
if (match[0] === '(') depth++
59-
if (match[0] === ')') depth--
60-
if (match[0] === '[') depth++
61-
if (match[0] === ']') depth--
62-
if (match[0] === '{') depth++
63-
if (match[0] === '}') depth--
64-
65-
if (matchesSeparator && depth === 0) {
66-
if (separatorStart === 0) {
67-
separatorStart = match.index
41+
if (stack.length === 0 && char === separator[0]) {
42+
if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) {
43+
parts.push(input.slice(lastPos, idx))
44+
lastPos = idx + separator.length
6845
}
69-
70-
separatorIndex++
7146
}
7247

73-
if (matchesFullSeparator && depth === 0) {
74-
found = true
75-
76-
yield input.substring(lastIndex, separatorStart)
77-
lastIndex = separatorStart + separatorLength
78-
}
79-
80-
if (separatorIndex === separatorLength) {
81-
separatorIndex = 0
82-
separatorStart = 0
48+
if (char === '(' || char === '[' || char === '{') {
49+
stack.push(char)
50+
} else if (
51+
(char === ')' && stack[stack.length - 1] === '(') ||
52+
(char === ']' && stack[stack.length - 1] === '[') ||
53+
(char === '}' && stack[stack.length - 1] === '{')
54+
) {
55+
stack.pop()
8356
}
8457
}
8558

86-
// Provide the last segment of the string if available
87-
// Otherwise the whole string since no `char`s were found
88-
// This mirrors the behavior of string.split()
89-
if (found) {
90-
yield input.substring(lastIndex)
91-
} else {
92-
yield input
93-
}
59+
parts.push(input.slice(lastPos))
60+
61+
return parts
9462
}

0 commit comments

Comments
 (0)