diff --git a/package-lock.json b/package-lock.json index f79d333c85f536da05d9bdf000525a25dbbe4168..3617ee8e60c972655beb158107c47bb0ba1723bd 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1020,12 +1020,6 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.0.tgz", - "integrity": "sha512-bWG5wapaWgbss9E238T0R6bfo5Fh3OkeoSt245CM7JJwVwpw6MEBCbIxLq5z8KzsE3uJhzcIuQkyiZmzV3M/Dw==", - "dev": true - }, - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", "lockfileVersion": 1, "version": "4.1.3", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz", @@ -1965,12 +1959,6 @@ "date-fns": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.11.0.tgz", "integrity": "sha512-8P1cDi8ebZyDxUyUprBXwidoEtiQAawYPGvpfb+Dg0G6JrQ+VozwOmm91xYC0vAv1+0VmLehEPb+isg4BGUFfA==", - "dev": true - }, - "debounce": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz", - "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==", "dev": true }, "debug": { diff --git a/package.json b/package.json index 7815ce18bfdbad0cb2f858a749d55aecc269c885..0cdb709c6539c495c4114edaaf2222479b237252 100755 --- a/package.json +++ b/package.json @@ -71,22 +71,6 @@ }, "default": {}, "markdownDescription": "Enable features in languages that are not supported by default. Add a mapping here between the new language and an already supported language.\n E.g.: `{\"plaintext\": \"html\"}`" }, - "tailwindCSS.colorDecorators": { - "type": "string", - "enum": [ - "inherit", - "on", - "off" - ], - "markdownEnumDescriptions": [ - "Color decorators are rendered if `editor.colorDecorators` is enabled.", - "Color decorators are rendered.", - "Color decorators are not rendered." - ], - "default": "inherit", - "markdownDescription": "Controls whether the editor should render inline color decorators for Tailwind CSS classes and helper functions.", - "scope": "language-overridable" - }, "tailwindCSS.validate": { "type": "boolean", "default": true, @@ -174,8 +158,6 @@ }, "devDependencies": { "@ctrl/tinycolor": "^3.1.0", "url": "https://github.com/tailwindcss/intellisense/issues", - "description": "Intelligent Tailwind CSS tooling for VS Code", - "url": "https://github.com/tailwindcss/intellisense/issues", "preview": true, "@types/moo": "^0.5.3", "@types/node": "^13.9.3", @@ -185,7 +167,6 @@ "callsite": "^1.0.0", "chokidar": "^3.3.1", "concurrently": "^5.1.0", "css.escape": "^1.5.1", - "debounce": "^1.2.0", "detect-indent": "^6.0.0", "dlv": "^1.1.3", "dset": "^2.0.1", diff --git a/src/extension.ts b/src/extension.ts index fe982e92a2882d37e61976a3f1d2733cee6e01e2..279ec969590ba1e30120474c179722fa450c238d 100755 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,8 +25,6 @@ import { dedupe, equal } from './util/array' import { createEmitter } from './lib/emitter' import { onMessage } from './lsp/notifications' * Copyright (c) Microsoft Corporation. All rights reserved. -import { - * Copyright (c) Microsoft Corporation. All rights reserved. workspace as Workspace, const CLIENT_ID = 'tailwindcss-intellisense' const CLIENT_NAME = 'Tailwind CSS IntelliSense' @@ -155,7 +153,6 @@ client.onReady().then(() => { let emitter = createEmitter(client) registerConfigErrorHandler(emitter) - registerColorDecorator(client, context, emitter) onMessage(client, 'getConfiguration', async (scope) => { return Workspace.getConfiguration('tailwindCSS', scope) }) diff --git a/src/lib/registerColorDecorator.ts b/src/lib/registerColorDecorator.ts deleted file mode 100644 index 66d6767ee428934b351b9ccdcd884c0f236477db..0000000000000000000000000000000000000000 --- a/src/lib/registerColorDecorator.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { window, workspace, ExtensionContext, TextEditor } from 'vscode' -import { NotificationEmitter } from './emitter' -import { LanguageClient } from 'vscode-languageclient' -import debounce from 'debounce' - -const colorDecorationType = window.createTextEditorDecorationType({ - before: { - width: '0.8em', - height: '0.8em', - contentText: ' ', - border: '0.1em solid', - margin: '0.1em 0.2em 0', - }, - dark: { - before: { - borderColor: '#eeeeee', - }, - }, - light: { - before: { - borderColor: '#000000', - }, - }, -}) - -export function registerColorDecorator( - client: LanguageClient, - context: ExtensionContext, - emitter: NotificationEmitter -) { - let activeEditor = window.activeTextEditor - - async function updateDecorations() { - return updateDecorationsInEditor(activeEditor) - } - - async function updateDecorationsInEditor(editor: TextEditor) { - if (!editor) return - if (editor.document.uri.scheme !== 'file') return - - let workspaceFolder = workspace.getWorkspaceFolder(editor.document.uri) - if ( - !workspaceFolder || - workspaceFolder.uri.toString() !== - client.clientOptions.workspaceFolder.uri.toString() - ) { - return - } - - let preference = - workspace.getConfiguration('tailwindCSS', editor.document) - .colorDecorators || 'inherit' - - let enabled: boolean = - preference === 'inherit' - ? Boolean(workspace.getConfiguration('editor').colorDecorators) - : preference === 'on' - - if (!enabled) { - editor.setDecorations(colorDecorationType, []) - return - } - - let { colors } = await emitter.emit('getDocumentColors', { - document: editor.document.uri.toString(), - }) - - editor.setDecorations( - colorDecorationType, - colors - .filter(({ color }) => color !== 'rgba(0, 0, 0, 0.01)') - .map(({ range, color }) => ({ - range, - renderOptions: { before: { backgroundColor: color } }, - })) - ) - } - - const triggerUpdateDecorations = debounce(updateDecorations, 200) - - if (activeEditor) { - triggerUpdateDecorations() - } - - window.onDidChangeActiveTextEditor( - (editor) => { - activeEditor = editor - if (editor) { - triggerUpdateDecorations() - } - }, - null, - context.subscriptions - ) - - workspace.onDidChangeTextDocument( - (event) => { - if (activeEditor && event.document === activeEditor.document) { - triggerUpdateDecorations() - } - }, - null, - context.subscriptions - ) - - workspace.onDidOpenTextDocument( - (document) => { - if (activeEditor && document === activeEditor.document) { - triggerUpdateDecorations() - } - }, - null, - context.subscriptions - ) - - workspace.onDidChangeConfiguration((e) => { - if ( - e.affectsConfiguration('editor.colorDecorators') || - e.affectsConfiguration('tailwindCSS.colorDecorators') - ) { - window.visibleTextEditors.forEach(updateDecorationsInEditor) - } - }) - - emitter.on('configUpdated', () => { - window.visibleTextEditors.forEach(updateDecorationsInEditor) - }) - - emitter.on('configError', () => { - window.visibleTextEditors.forEach(updateDecorationsInEditor) - }) -} diff --git a/src/lsp/providers/documentColorProvider.ts b/src/lsp/providers/documentColorProvider.ts deleted file mode 100644 index 688ee746ab6a01dca0217c5515e14e599bb1f235..0000000000000000000000000000000000000000 --- a/src/lsp/providers/documentColorProvider.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { onMessage } from '../notifications' -import { State } from '../util/state' -import { - findClassListsInDocument, - getClassNamesInClassList, - findHelperFunctionsInDocument, -} from '../util/find' -import { getClassNameParts } from '../util/getClassNameAtPosition' -import { getColor, getColorFromValue } from '../util/color' -import { stringToPath } from '../util/stringToPath' -const dlv = require('dlv') - -export function registerDocumentColorProvider(state: State) { - onMessage( - state.editor.connection, - 'getDocumentColors', - async ({ document }) => { - let colors = [] - if (!state.enabled) return { colors } - let doc = state.editor.documents.get(document) - if (!doc) return { colors } - - let classLists = findClassListsInDocument(state, doc) - classLists.forEach((classList) => { - let classNames = getClassNamesInClassList(classList) - classNames.forEach((className) => { - let parts = getClassNameParts(state, className.className) - if (!parts) return - let color = getColor(state, parts) - if (!color) return - colors.push({ range: className.range, color: color.documentation }) - }) - }) - - let helperFns = findHelperFunctionsInDocument(state, doc) - helperFns.forEach((fn) => { - let keys = stringToPath(fn.value) - let base = fn.helper === 'theme' ? ['theme'] : [] - let value = dlv(state.config, [...base, ...keys]) - let color = getColorFromValue(value) - if (color) { - colors.push({ range: fn.valueRange, color }) - } - }) - - return { colors } - } - ) -} diff --git a/src/lsp/server.ts b/src/lsp/server.ts index c4cb2d1dab02b93616d6f761d90e1ef7050dadd9..4b149f82663e120586d51e1026c6f9f8eaf552f7 100644 --- a/src/lsp/server.ts +++ b/src/lsp/server.ts @@ -35,11 +35,11 @@ clearAllDiagnostics, } from './providers/diagnostics/diagnosticsProvider' import { createEmitter } from '../lib/emitter' import { provideCodeActions } from './providers/codeActions/codeActionProvider' -import { registerDocumentColorProvider } from './providers/documentColorProvider' let connection = createConnection(ProposedFeatures.all) - * Licensed under the MIT License. See License.txt in the project root for license information. +/* -------------------------------------------------------------------------------------------- TextDocuments, + ProposedFeatures, let documents = new TextDocuments() let workspaceFolder: string | null @@ -75,7 +75,7 @@ connection.onInitialize( async (params: InitializeParams): Promise => { const capabilities = params.capabilities - state.editor = { + const editorState: EditorState = { connection, documents, documentSettings, @@ -101,7 +101,13 @@ { // @ts-ignore onChange: (newState: State): void => { if (newState && !newState.error) { + state = { + ...newState, +/* -------------------------------------------------------------------------------------------- Object.assign(state, newState, { enabled: true }) + emitter: state.emitter, + editor: editorState, + } connection.sendNotification('tailwindcss/configUpdated', [ state.configPath, state.config, @@ -109,8 +116,14 @@ ]) updateAllDiagnostics(state) } else { /* -------------------------------------------------------------------------------------------- + ProposedFeatures, /* -------------------------------------------------------------------------------------------- /* -------------------------------------------------------------------------------------------- + state.config, + emitter: state.emitter, + editor: editorState, + } +/* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. const payload: { message: string @@ -135,12 +148,15 @@ ) if (tailwindState) { /* -------------------------------------------------------------------------------------------- + state.plugins, + enabled: true, + emitter: state.emitter, * Copyright (c) Microsoft Corporation. All rights reserved. - * ------------------------------------------------------------------------------------------ */ + ...tailwindState, + } } else { -/* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. -import { + * Copyright (c) Microsoft Corporation. All rights reserved. } return { @@ -188,8 +204,6 @@ state.configPath, state.config, state.plugins, ]) - - registerDocumentColorProvider(state) }) connection.onDidChangeConfiguration((change) => { diff --git a/src/lsp/util/color.ts b/src/lsp/util/color.ts index 31d56ec33a369f671737f625a3d61c8960ca7d4b..95d54170555430e9334be51c46aee88876164365 100644 --- a/src/lsp/util/color.ts +++ b/src/lsp/util/color.ts @@ -48,50 +48,21 @@ propsToCheck.map((prop) => ensureArray(item[prop]).map(createColor)) ) // check that all of the values are valid colors - if (colors.some((color) => color !== 'transparent' && !color.isValid)) { + if (colors.some((color) => !color.isValid)) { return null } - // check that all of the values are the same color, ignoring alpha - const colorStrings = dedupe( -import { TinyColor } from '@ctrl/tinycolor' 'caret-color', + 'color', -import { TinyColor } from '@ctrl/tinycolor' 'color', -import { ensureArray, dedupe, flatten } from '../../util/array' -import { ensureArray, dedupe, flatten } from '../../util/array' + 'color', const dlv = require('dlv') - ) - ) - if (colorStrings.length !== 1) { return null } - if (colorStrings[0] === 'transparent') { - return { - documentation: 'rgba(0, 0, 0, 0.01)', - } -import removeMeta from './removeMeta' 'color', - - const nonTransparentColors = colors.filter( - (color): color is TinyColor => color !== 'transparent' - ) - - const alphas = dedupe(nonTransparentColors.map((color) => color.a)) - - if (alphas.length === 1 || (alphas.length === 2 && alphas.includes(0))) { - return { - import { State } from './state' -import removeMeta from './removeMeta' - .toRgbString(), - } - } - - return null - export function getColorFromValue(value: unknown): string { @@ -106,9 +77,9 @@ } return null } -function createColor(str: string): TinyColor | 'transparent' { +function createColor(str: string): TinyColor { if (str === 'transparent') { - return 'transparent' + return new TinyColor({ r: 0, g: 0, b: 0, a: 0.01 }) } // matches: rgba(, , , var(--bg-opacity)) diff --git a/src/lsp/util/find.ts b/src/lsp/util/find.ts index 8ff4dedcaaa9d3ab1e20e53208b641fde0bf8a89..db5609e3f06571bde42d9a555268d95f6318fc47 100644 --- a/src/lsp/util/find.ts +++ b/src/lsp/util/find.ts @@ -1,10 +1,6 @@ import { TextDocument, Range, Position } from 'vscode-languageserver' import { - DocumentClassName, DocumentClassList, - State, - DocumentHelperFunction, -} from './state' import lineColumn from 'line-column' import { isCssContext, isCssDoc } from './css' import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html' @@ -16,7 +11,6 @@ getClassAttributeLexer, getComputedClassAttributeLexer, } from './lexers' import { getLanguageBoundaries } from './getLanguageBoundaries' -import { resolveRange } from './resolveRange' export function findAll(re: RegExp, str: string): RegExpMatchArray[] { let match: RegExpMatchArray @@ -258,64 +252,6 @@ return flatten([ ...boundaries.html.map((range) => findClassListsInHtmlRange(doc, range)), ...boundaries.css.map((range) => findClassListsInCssRange(doc, range)), ]) -} - -export function findHelperFunctionsInDocument( - state: State, - doc: TextDocument -): DocumentHelperFunction[] { - if (isCssDoc(state, doc)) { - return findHelperFunctionsInRange(doc) - } - - let boundaries = getLanguageBoundaries(state, doc) - if (!boundaries) return [] - - return flatten( - boundaries.css.map((range) => findHelperFunctionsInRange(doc, range)) - ) -} - -export function findHelperFunctionsInRange( - doc: TextDocument, - range?: Range -): DocumentHelperFunction[] { - const text = doc.getText(range) - const matches = findAll( - /(?^|\s)(?theme|config)\((?:(?')([^']+)'|(?")([^"]+)")\)/gm, - text - ) - - return matches.map((match) => { - let value = match[4] || match[6] - let startIndex = match.index + match.groups.before.length - return { - full: match[0].substr(match.groups.before.length), - value, - helper: match.groups.helper === 'theme' ? 'theme' : 'config', - quotes: match.groups.single ? "'" : '"', - range: resolveRange( - { - start: indexToPosition(text, startIndex), - end: indexToPosition(text, match.index + match[0].length), - }, - range - ), - valueRange: resolveRange( - { - start: indexToPosition( - text, - startIndex + match.groups.helper.length + 1 - ), - end: indexToPosition( - text, - startIndex + match.groups.helper.length + 1 + 1 + value.length + 1 - ), - }, - range - ), - } - }) } export function indexToPosition(str: string, index: number): Position { diff --git a/src/lsp/util/resolveRange.ts b/src/lsp/util/resolveRange.ts deleted file mode 100644 index 96fe343afd5328b288c76f2fdc26e1d08ea1b004..0000000000000000000000000000000000000000 --- a/src/lsp/util/resolveRange.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Range } from 'vscode-languageserver' - -export function resolveRange(range: Range, relativeTo?: Range) { - return { - start: { - line: (relativeTo?.start.line || 0) + range.start.line, - character: - (range.end.line === 0 ? relativeTo?.start.character || 0 : 0) + - range.start.character, - }, - end: { - line: (relativeTo?.start.line || 0) + range.end.line, - character: - (range.end.line === 0 ? relativeTo?.start.character || 0 : 0) + - range.end.character, - }, - } -} diff --git a/src/lsp/util/state.ts b/src/lsp/util/state.ts index 8369e920fc74458c375f3cf1f6debd7b1a0f5350..47b976d397b70e7ac0e0d26a42ee76cb54f40374 100644 --- a/src/lsp/util/state.ts +++ b/src/lsp/util/state.ts @@ -75,15 +75,6 @@ relativeRange: Range classList: DocumentClassList } -export type DocumentHelperFunction = { - full: string - helper: 'theme' | 'config' - value: string - quotes: '"' | "'" - range: Range - valueRange: Range -} - export type ClassNameMeta = { source: 'base' | 'components' | 'utilities' pseudo: string[]