From 2f936d947230b1a92964c124d4d228c14cf6edc6 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 3 Jun 2025 09:50:35 -0400 Subject: [PATCH 1/4] Refactor --- .../tests/completions/completions.test.js | 34 +++++++++++-------- .../src/completionProvider.ts | 8 +++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js index f4d88622..384d4b4a 100644 --- a/packages/tailwindcss-language-server/tests/completions/completions.test.js +++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js @@ -983,7 +983,7 @@ defineTest({ }) defineTest({ - name: 'Completions for outline and border utilities have simplified details', + name: 'Completions for several utilities have simplified details', fs: { 'app.css': css` @import 'tailwindcss'; @@ -993,24 +993,30 @@ defineTest({ handle: async ({ client }) => { let document = await client.open({ lang: 'html', - text: html`
`, + text: html`
`, }) - //
- // ^ - let completionA = await document.completions({ line: 0, character: 20 }) + //
+ // ^ + let list = await document.completions({ line: 0, character: 12 }) + let items = list?.items ?? [] - //
- // ^ - let completionB = await document.completions({ line: 0, character: 30 }) + let map = { + 'border-0': 'border-width: 0px;', + 'outline-0': 'outline-width: 0px;', + } + + let requests = await Promise.all( + Object.keys(map).map(async (label) => { + let item = items.find((item) => item.label === label) + if (!item) throw new Error(`Item not found for label: ${label}`) - let border = completionA?.items.find((item) => item.label === 'border-0') - let outline = completionB?.items.find((item) => item.label === 'outline-0') + let resolved = await client.conn.sendRequest('completionItem/resolve', item) - let borderResolved = await client.conn.sendRequest('completionItem/resolve', border) - let outlineResolved = await client.conn.sendRequest('completionItem/resolve', outline) + return [label, resolved.detail] + }), + ) - expect(borderResolved).toMatchObject({ detail: 'border-width: 0px;' }) - expect(outlineResolved).toMatchObject({ detail: 'outline-width: 0px;' }) + expect(Object.fromEntries(requests)).toEqual(map) }, }) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 98f5d612..50952439 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -2306,9 +2306,13 @@ export async function resolveCompletionItem( } }) + let ignoredValues = new Set([ + 'var(--tw-border-style)', + 'var(--tw-outline-style)', + ]) + base.walkDecls((node) => { - if (node.value === 'var(--tw-border-style)') return - if (node.value === 'var(--tw-outline-style)') return + if (ignoredValues.has(node.value)) return decls.push(node) }) From b21e9ce7ea0bb5ec4af448f51191a94ec25b2ff5 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 3 Jun 2025 09:51:57 -0400 Subject: [PATCH 2/4] Hide uncnessary decls in details --- .../tests/completions/completions.test.js | 29 ++++++++++++ .../src/completionProvider.ts | 45 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js index 384d4b4a..090ec872 100644 --- a/packages/tailwindcss-language-server/tests/completions/completions.test.js +++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js @@ -1004,6 +1004,35 @@ defineTest({ let map = { 'border-0': 'border-width: 0px;', 'outline-0': 'outline-width: 0px;', + 'leading-0': 'line-height: 0rem /* 0px */;', + 'duration-1000': 'transition-duration: 1000ms;', + 'font-bold': 'font-weight: 700;', + 'ease-linear': 'transition-timing-function: linear;', + 'ease-initial': '--tw-ease: initial;', + + 'space-x-0': + 'margin-inline-start: calc(0rem /* 0px */ * var(--tw-space-x-reverse)); margin-inline-end: calc(0rem /* 0px */ * calc(1 - var(--tw-space-x-reverse)));', + 'space-y-0': + 'margin-block-start: calc(0rem /* 0px */ * var(--tw-space-y-reverse)); margin-block-end: calc(0rem /* 0px */ * calc(1 - var(--tw-space-y-reverse)));', + 'divide-x-0': + 'border-inline-start-width: calc(0px * var(--tw-divide-x-reverse)); border-inline-end-width: calc(0px * calc(1 - var(--tw-divide-x-reverse)));', + 'divide-y-0': + 'border-top-width: calc(0px * var(--tw-divide-y-reverse)); border-bottom-width: calc(0px * calc(1 - var(--tw-divide-y-reverse)));', + + 'tracking-wide': 'letter-spacing: 0.025em;', + + 'from-red-500': '--tw-gradient-from: oklch(63.7% 0.237 25.331);', + 'via-red-500': '--tw-gradient-via: oklch(63.7% 0.237 25.331);', + 'to-red-500': '--tw-gradient-to: oklch(63.7% 0.237 25.331);', + + 'scale-100': '--tw-scale-x: 100%; --tw-scale-y: 100%; --tw-scale-z: 100%;', + 'scale-z-100': '--tw-scale-z: 100%;', + + 'translate-1': '--tw-translate-x: 0.25rem /* 4px */; --tw-translate-y: 0.25rem /* 4px */;', + 'translate-z-1': '--tw-translate-z: 0.25rem /* 4px */;', + + 'bg-conic-0': + '--tw-gradient-position: from 0deg in oklab; background-image: conic-gradient(var(--tw-gradient-stops));', } let requests = await Promise.all( diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 50952439..58d33026 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -2304,11 +2304,33 @@ export async function resolveCompletionItem( if (rule.name === 'supports' && rule.params === '(-moz-orient: inline)') { rule.remove() } + + if ( + rule.name === 'supports' && + rule.params === '(background-image: linear-gradient(in lab, red, red))' + ) { + rule.remove() + } }) let ignoredValues = new Set([ 'var(--tw-border-style)', 'var(--tw-outline-style)', + 'var(--tw-translate-x) var(--tw-translate-y)', + 'var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)', + 'var(--tw-scale-x) var(--tw-scale-y)', + 'var(--tw-scale-x) var(--tw-scale-y) var(--tw-scale-z)', + + // 'var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y)', + // 'var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)', + + // 'var(--tw-border-spacing-x) var(--tw-border-spacing-y)', + // 'var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)', + // 'var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)', + + // 'linear-gradient(var(--tw-gradient-stops))', + // 'radial-gradient(var(--tw-gradient-stops))', + // 'conic-gradient(var(--tw-gradient-stops))', ]) base.walkDecls((node) => { @@ -2317,6 +2339,29 @@ export async function resolveCompletionItem( decls.push(node) }) + // TODO: Hardcoding this list is really unfortunate. We should be able + // to handle this in Tailwind CSS itself. + function isOtherDecl(node: postcss.Declaration) { + if (node.prop === '--tw-leading') return false + if (node.prop === '--tw-duration') return false + if (node.prop === '--tw-ease') return false + if (node.prop === '--tw-font-weight') return false + if (node.prop === '--tw-gradient-via-stops') return false + if (node.prop === '--tw-gradient-stops') return false + if (node.prop === '--tw-tracking') return false + if (node.prop === '--tw-space-x-reverse' && node.value === '0') return false + if (node.prop === '--tw-space-y-reverse' && node.value === '0') return false + if (node.prop === '--tw-divide-x-reverse' && node.value === '0') return false + if (node.prop === '--tw-divide-y-reverse' && node.value === '0') return false + + return true + } + + // We want to remove these decls from details *as long as they're not the only one* + if (decls.some(isOtherDecl)) { + decls = decls.filter(isOtherDecl) + } + item.detail = await jit.stringifyDecls(state, postcss.rule({ nodes: decls })) } else { item.detail = `${rules.length} rules` From a567d758244f8e2274e6bcae0f33edd919d5e7f4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 3 Jun 2025 09:52:03 -0400 Subject: [PATCH 3/4] Update changelog --- packages/vscode-tailwindcss/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index e3bfc615..7dcb4806 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -3,6 +3,7 @@ ## Prerelease - Bump bundled CSS language service ([#1395](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1395)) +- Simplify completion details for more utilities ([#1397](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1397)) ## 0.14.20 From 9575be910d89d52b9f761ab9e8c031bafe5a20a6 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 4 Jun 2025 14:32:45 -0400 Subject: [PATCH 4/4] Cleanup --- .../src/completionProvider.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 7ae81d6c..36e7676b 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -2320,17 +2320,6 @@ export async function resolveCompletionItem( 'var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)', 'var(--tw-scale-x) var(--tw-scale-y)', 'var(--tw-scale-x) var(--tw-scale-y) var(--tw-scale-z)', - - // 'var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y)', - // 'var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)', - - // 'var(--tw-border-spacing-x) var(--tw-border-spacing-y)', - // 'var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)', - // 'var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)', - - // 'linear-gradient(var(--tw-gradient-stops))', - // 'radial-gradient(var(--tw-gradient-stops))', - // 'conic-gradient(var(--tw-gradient-stops))', ]) base.walkDecls((node) => {