Skip to content

Commit 439e07c

Browse files
committed
Hide CSS language completions inside import source, theme, and prefix fns
1 parent 43aad03 commit 439e07c

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

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

+51-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
CompletionItemKind,
1414
Connection,
1515
} from 'vscode-languageserver/node'
16-
import { TextDocument } from 'vscode-languageserver-textdocument'
16+
import { Position, TextDocument } from 'vscode-languageserver-textdocument'
1717
import { Utils, URI } from 'vscode-uri'
1818
import { getLanguageModelCache } from './languageModelCache'
1919
import { Stylesheet } from 'vscode-css-languageservice'
@@ -137,8 +137,58 @@ export class CssServer {
137137
})
138138
}
139139

140+
function isInImportDirective(doc: TextDocument, pos: Position) {
141+
let text = doc.getText({
142+
start: { line: pos.line, character: 0 },
143+
end: pos,
144+
})
145+
146+
// Scan backwards to see if we're inside an `@import` directive
147+
let foundImport = false
148+
let foundDirective = false
149+
150+
for (let i = text.length - 1; i >= 0; i--) {
151+
let char = text[i]
152+
if (char === '\n') break
153+
154+
if (char === '(' && !foundDirective) {
155+
if (text.startsWith(' source(', i - 7)) {
156+
foundDirective = true
157+
}
158+
159+
//
160+
else if (text.startsWith(' theme(', i - 6)) {
161+
foundDirective = true
162+
}
163+
164+
//
165+
else if (text.startsWith(' prefix(', i - 7)) {
166+
foundDirective = true
167+
}
168+
}
169+
170+
//
171+
else if (char === '@' && !foundImport) {
172+
if (text.startsWith('@import ', i)) {
173+
foundImport = true
174+
}
175+
}
176+
}
177+
178+
return foundImport && foundDirective
179+
}
180+
140181
connection.onCompletion(async ({ textDocument, position }, _token) =>
141182
withDocumentAndSettings(textDocument.uri, async ({ original, document, settings }) => {
183+
// If we're inside source(…), prefix(…), or theme(…), don't show
184+
// completions from the CSS language server
185+
if (isInImportDirective(original, position)) {
186+
return {
187+
isIncomplete: false,
188+
items: [],
189+
}
190+
}
191+
142192
let result = await cssLanguageService.doComplete2(
143193
document,
144194
position,

packages/tailwindcss-language-server/tests/css/css-server.test.ts

+46
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,49 @@ defineTest({
689689
expect(await doc.diagnostics()).toEqual([])
690690
},
691691
})
692+
693+
defineTest({
694+
name: 'completions are hidden inside @import source(…)/theme(…)/prefix(…) functions',
695+
prepare: async ({ root }) => ({
696+
client: await createClient({
697+
server: 'css',
698+
root,
699+
}),
700+
}),
701+
handle: async ({ client }) => {
702+
let doc = await client.open({
703+
lang: 'tailwindcss',
704+
name: 'file-1.css',
705+
text: css`
706+
@import './file.css' source(none);
707+
@import './file.css' theme(inline);
708+
@import './file.css' prefix(tw);
709+
@import './file.css' source(none) theme(inline) prefix(tw);
710+
`,
711+
})
712+
713+
// @import './file.css' source(none)
714+
// ^
715+
// @import './file.css' theme(inline);
716+
// ^
717+
// @import './file.css' prefix(tw);
718+
// ^
719+
let completionsA = await doc.completions({ line: 0, character: 29 })
720+
let completionsB = await doc.completions({ line: 1, character: 28 })
721+
let completionsC = await doc.completions({ line: 2, character: 29 })
722+
723+
expect(completionsA).toEqual({ isIncomplete: false, items: [] })
724+
expect(completionsB).toEqual({ isIncomplete: false, items: [] })
725+
expect(completionsC).toEqual({ isIncomplete: false, items: [] })
726+
727+
// @import './file.css' source(none) theme(inline) prefix(tw);
728+
// ^ ^ ^
729+
let completionsD = await doc.completions({ line: 3, character: 29 })
730+
let completionsE = await doc.completions({ line: 3, character: 41 })
731+
let completionsF = await doc.completions({ line: 3, character: 56 })
732+
733+
expect(completionsD).toEqual({ isIncomplete: false, items: [] })
734+
expect(completionsE).toEqual({ isIncomplete: false, items: [] })
735+
expect(completionsF).toEqual({ isIncomplete: false, items: [] })
736+
},
737+
})

0 commit comments

Comments
 (0)