diff --git a/packages/tailwindcss-language-server/src/providers/completionProvider.ts b/packages/tailwindcss-language-server/src/providers/completionProvider.ts index cbd1f36..bac0cd3 100644 --- a/packages/tailwindcss-language-server/src/providers/completionProvider.ts +++ b/packages/tailwindcss-language-server/src/providers/completionProvider.ts @@ -10,8 +10,8 @@ import { const dlv = require('dlv') import removeMeta from '../util/removeMeta' import { getColor, getColorFromString } from '../util/color' -import { isHtmlDoc } from '../util/html' -import { isCssDoc } from '../util/css' +import { isHtmlContext } from '../util/html' +import { isCssContext } from '../util/css' import { findLast, findJsxStrings, arrFindLast } from '../util/find' import { stringifyConfigValue } from '../util/stringify' import isObject from '../util/isObject' @@ -171,11 +171,11 @@ function provideClassNameCompletions( ): CompletionList { let doc = state.editor.documents.get(params.textDocument.uri) - if (isHtmlDoc(doc)) { + if (isHtmlContext(doc, params.position)) { return provideClassAttributeCompletions(state, params) } - if (isCssDoc(doc)) { + if (isCssContext(doc, params.position)) { return provideAtApplyCompletions(state, params) } @@ -188,7 +188,7 @@ function provideCssHelperCompletions( ): CompletionList { let doc = state.editor.documents.get(textDocument.uri) - if (!isCssDoc(doc)) { + if (!isCssContext(doc, position)) { return null } diff --git a/packages/tailwindcss-language-server/src/util/css.ts b/packages/tailwindcss-language-server/src/util/css.ts index 88a1dcc..33b70e9 100644 --- a/packages/tailwindcss-language-server/src/util/css.ts +++ b/packages/tailwindcss-language-server/src/util/css.ts @@ -1,4 +1,5 @@ -import { TextDocument } from 'vscode-languageserver' +import { TextDocument, Position } from 'vscode-languageserver' +import { isMixedDoc, isInsideTag } from './html' export const CSS_LANGUAGES = [ 'css', @@ -7,10 +8,25 @@ export const CSS_LANGUAGES = [ 'sass', 'scss', 'stylus', - 'svelte', - 'vue' ] -export function isCssDoc(doc: TextDocument): boolean { +function isCssDoc(doc: TextDocument): boolean { return CSS_LANGUAGES.indexOf(doc.languageId) !== -1 } + +export function isCssContext(doc: TextDocument, position: Position): boolean { + if (isCssDoc(doc)) { + return true + } + + if (isMixedDoc(doc)) { + let str = doc.getText({ + start: { line: 0, character: 0 }, + end: position, + }) + + return isInsideTag(str, ['style']) + } + + return false +} diff --git a/packages/tailwindcss-language-server/src/util/html.ts b/packages/tailwindcss-language-server/src/util/html.ts index 97761ad..fee187f 100644 --- a/packages/tailwindcss-language-server/src/util/html.ts +++ b/packages/tailwindcss-language-server/src/util/html.ts @@ -1,4 +1,4 @@ -import { TextDocument } from 'vscode-languageserver' +import { TextDocument, Position } from 'vscode-languageserver' import { JS_LANGUAGES } from './js' export const HTML_LANGUAGES = [ @@ -19,12 +19,61 @@ export const HTML_LANGUAGES = [ 'php', 'razor', 'slim', - 'svelte', 'twig', - 'vue', - ...JS_LANGUAGES + ...JS_LANGUAGES, ] -export function isHtmlDoc(doc: TextDocument): boolean { +function isHtmlDoc(doc: TextDocument): boolean { return HTML_LANGUAGES.indexOf(doc.languageId) !== -1 } + +function isVueDoc(doc: TextDocument): boolean { + return doc.languageId === 'vue' +} + +function isSvelteDoc(doc: TextDocument): boolean { + return doc.languageId === 'svelte' +} + +export function isMixedDoc(doc: TextDocument): boolean { + return isVueDoc(doc) || isSvelteDoc(doc) +} + +export function isHtmlContext(doc: TextDocument, position: Position): boolean { + if (isHtmlDoc(doc)) { + return true + } + + if (isMixedDoc(doc)) { + let str = doc.getText({ + start: { line: 0, character: 0 }, + end: position, + }) + + if (isVueDoc(doc)) { + return isInsideTag(str, ['template', 'script']) + } + + if (isSvelteDoc(doc)) { + return !isInsideTag(str, ['style']) + } + } + + return false +} + +export function isInsideTag(str: string, tag: string | string[]): boolean { + let open = 0 + let close = 0 + let match: RegExpExecArray + let tags = Array.isArray(tag) ? tag : [tag] + let regex = new RegExp(`<(?/?)(?:${tags.join('|')})\\b`, 'ig') + while ((match = regex.exec(str)) !== null) { + if (match.groups.slash) { + close += 1 + } else { + open += 1 + } + } + return open > 0 && open > close +} diff --git a/packages/tailwindcss-language-server/src/util/js.ts b/packages/tailwindcss-language-server/src/util/js.ts index 6c0e484..fa2390a 100644 --- a/packages/tailwindcss-language-server/src/util/js.ts +++ b/packages/tailwindcss-language-server/src/util/js.ts @@ -4,8 +4,7 @@ export const JS_LANGUAGES = [ 'javascript', 'javascriptreact', 'reason', - 'svelte', - 'typescriptreact' + 'typescriptreact', ] export function isJsDoc(doc: TextDocument): boolean { diff --git a/packages/tailwindcss-vscode/src/extension.ts b/packages/tailwindcss-vscode/src/extension.ts index f6a4b88..81ca5e1 100755 --- a/packages/tailwindcss-vscode/src/extension.ts +++ b/packages/tailwindcss-vscode/src/extension.ts @@ -22,7 +22,7 @@ import { let defaultClient: LanguageClient let clients: Map = new Map() -const LANGS = ['css', 'javascript', 'html'] +const LANGS = ['css', 'javascript', 'html', 'vue', 'svelte'] let _sortedWorkspaceFolders: string[] | undefined function sortedWorkspaceFolders(): string[] {