diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/vue-style-lang-sass.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/vue-style-lang-sass.json
new file mode 100644
index 00000000..7e9da86b
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/vue-style-lang-sass.json
@@ -0,0 +1,116 @@
+{
+ "code": "",
+ "language": "vue",
+ "expected": [
+ {
+ "code": "cssConflict",
+ "className": {
+ "className": "uppercase",
+ "classList": {
+ "classList": "uppercase lowercase",
+ "range": {
+ "start": { "line": 2, "character": 9 },
+ "end": { "line": 2, "character": 28 }
+ },
+ "important": false
+ },
+ "relativeRange": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 9 }
+ },
+ "range": { "start": { "line": 2, "character": 9 }, "end": { "line": 2, "character": 18 } }
+ },
+ "otherClassNames": [
+ {
+ "className": "lowercase",
+ "classList": {
+ "classList": "uppercase lowercase",
+ "range": {
+ "start": { "line": 2, "character": 9 },
+ "end": { "line": 2, "character": 28 }
+ },
+ "important": false
+ },
+ "relativeRange": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 19 }
+ },
+ "range": {
+ "start": { "line": 2, "character": 19 },
+ "end": { "line": 2, "character": 28 }
+ }
+ }
+ ],
+ "range": { "start": { "line": 2, "character": 9 }, "end": { "line": 2, "character": 18 } },
+ "severity": 2,
+ "message": "'uppercase' applies the same CSS properties as 'lowercase'.",
+ "relatedInformation": [
+ {
+ "message": "lowercase",
+ "location": {
+ "uri": "{{URI}}",
+ "range": {
+ "start": { "line": 2, "character": 19 },
+ "end": { "line": 2, "character": 28 }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "code": "cssConflict",
+ "className": {
+ "className": "lowercase",
+ "classList": {
+ "classList": "uppercase lowercase",
+ "range": {
+ "start": { "line": 2, "character": 9 },
+ "end": { "line": 2, "character": 28 }
+ },
+ "important": false
+ },
+ "relativeRange": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 19 }
+ },
+ "range": { "start": { "line": 2, "character": 19 }, "end": { "line": 2, "character": 28 } }
+ },
+ "otherClassNames": [
+ {
+ "className": "uppercase",
+ "classList": {
+ "classList": "uppercase lowercase",
+ "range": {
+ "start": { "line": 2, "character": 9 },
+ "end": { "line": 2, "character": 28 }
+ },
+ "important": false
+ },
+ "relativeRange": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 9 }
+ },
+ "range": {
+ "start": { "line": 2, "character": 9 },
+ "end": { "line": 2, "character": 18 }
+ }
+ }
+ ],
+ "range": { "start": { "line": 2, "character": 19 }, "end": { "line": 2, "character": 28 } },
+ "severity": 2,
+ "message": "'lowercase' applies the same CSS properties as 'uppercase'.",
+ "relatedInformation": [
+ {
+ "message": "uppercase",
+ "location": {
+ "uri": "{{URI}}",
+ "range": {
+ "start": { "line": 2, "character": 9 },
+ "end": { "line": 2, "character": 18 }
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js b/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js
index 4da6946d..4a37ee2d 100644
--- a/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js
+++ b/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js
@@ -32,6 +32,7 @@ withFixture('basic', (c) => {
testFixture('css-conflict/css')
testFixture('css-conflict/css-multi-rule')
testFixture('css-conflict/css-multi-prop')
+ testFixture('css-conflict/vue-style-lang-sass')
testFixture('invalid-screen/simple')
testFixture('invalid-theme/simple')
})
@@ -63,6 +64,7 @@ withFixture('v4/basic', (c) => {
testFixture('css-conflict/variants-positive')
testFixture('css-conflict/jsx-concat-negative')
testFixture('css-conflict/jsx-concat-positive')
+ testFixture('css-conflict/vue-style-lang-sass')
// testFixture('css-conflict/css')
// testFixture('css-conflict/css-multi-rule')
// testFixture('css-conflict/css-multi-prop')
diff --git a/packages/tailwindcss-language-server/tests/hover/hover.test.js b/packages/tailwindcss-language-server/tests/hover/hover.test.js
index 544ea1e3..f1b847c3 100644
--- a/packages/tailwindcss-language-server/tests/hover/hover.test.js
+++ b/packages/tailwindcss-language-server/tests/hover/hover.test.js
@@ -75,6 +75,20 @@ withFixture('basic', (c) => {
end: { line: 0, character: 31 },
},
})
+
+ testHover('vue `,
+ position: { line: 2, character: 13 },
+ expected: '.underline {\n' + ' text-decoration-line: underline;\n' + '}',
+ expectedRange: {
+ start: { line: 2, character: 9 },
+ end: { line: 2, character: 18 },
+ },
+ })
})
withFixture('v4/basic', (c) => {
@@ -148,4 +162,18 @@ withFixture('v4/basic', (c) => {
end: { line: 0, character: 31 },
},
})
+
+ testHover('vue `,
+ position: { line: 2, character: 13 },
+ expected: '.underline {\n' + ' text-decoration-line: underline;\n' + '}',
+ expectedRange: {
+ start: { line: 2, character: 9 },
+ end: { line: 2, character: 18 },
+ },
+ })
})
diff --git a/packages/tailwindcss-language-service/src/util/css.ts b/packages/tailwindcss-language-service/src/util/css.ts
index 14950397..079e4221 100644
--- a/packages/tailwindcss-language-service/src/util/css.ts
+++ b/packages/tailwindcss-language-service/src/util/css.ts
@@ -6,12 +6,21 @@ import type { State } from './state'
import { cssLanguages } from './languages'
import { getLanguageBoundaries } from './getLanguageBoundaries'
-export function isCssDoc(state: State, doc: TextDocument): boolean {
- const userCssLanguages = Object.keys(state.editor.userLanguages).filter((lang) =>
- cssLanguages.includes(state.editor.userLanguages[lang]),
- )
+function getCssLanguages(state: State) {
+ const userCssLanguages = Object
+ .keys(state.editor.userLanguages)
+ .filter((lang) => cssLanguages.includes(state.editor.userLanguages[lang]))
+
+ return [...cssLanguages, ...userCssLanguages]
+}
- return [...cssLanguages, ...userCssLanguages].indexOf(doc.languageId) !== -1
+export function isCssLanguage(state: State, lang: string) {
+ return getCssLanguages(state).indexOf(lang) !== -1
+}
+
+
+export function isCssDoc(state: State, doc: TextDocument): boolean {
+ return isCssLanguage(state, doc.languageId)
}
export function isCssContext(state: State, doc: TextDocument, position: Position): boolean {
diff --git a/packages/tailwindcss-language-service/src/util/find.ts b/packages/tailwindcss-language-service/src/util/find.ts
index 94fae47d..fead1bd7 100644
--- a/packages/tailwindcss-language-service/src/util/find.ts
+++ b/packages/tailwindcss-language-service/src/util/find.ts
@@ -3,7 +3,7 @@ import type { TextDocument } from 'vscode-languageserver-textdocument'
import type { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
import lineColumn from 'line-column'
import { isCssContext, isCssDoc } from './css'
-import { isHtmlContext } from './html'
+import { isHtmlContext, isVueDoc } from './html'
import { isWithinRange } from './isWithinRange'
import { isJsxContext } from './js'
import { dedupeByRange, flatten } from './array'
@@ -97,9 +97,10 @@ export function findClassListsInCssRange(
state: State,
doc: TextDocument,
range?: Range,
+ lang?: string,
): DocumentClassList[] {
const text = getTextWithoutComments(doc, 'css', range)
- let regex = isSemicolonlessCssLanguage(doc.languageId, state.editor?.userLanguages)
+ let regex = isSemicolonlessCssLanguage(lang ?? doc.languageId, state.editor?.userLanguages)
? /(@apply\s+)(?