diff --git a/.github/autocomplete.png b/.github/autocomplete.png
deleted file mode 100644
index 7857187025e47936aa933cb2cfefc187ac4ef10d..0000000000000000000000000000000000000000
Binary files a/.github/autocomplete.png and /dev/null differ
diff --git a/.github/banner.png b/.github/banner.png
deleted file mode 100644
index 1f927163a27fffb33f9be3bb52928f69bf020242..0000000000000000000000000000000000000000
Binary files a/.github/banner.png and /dev/null differ
diff --git a/.github/hover.png b/.github/hover.png
deleted file mode 100644
index e46a8efaa5dfdd9aeb52facc08a3a7687b6634b3..0000000000000000000000000000000000000000
Binary files a/.github/hover.png and /dev/null differ
diff --git a/.github/linting.png b/.github/linting.png
deleted file mode 100644
index 0c118825152d9335690fc59702cb4b842663e652..0000000000000000000000000000000000000000
Binary files a/.github/linting.png and /dev/null differ
diff --git a/.vscodeignore b/.vscodeignore
index 591602a20e25e0f55f0c73215f8494ca8a21fd2a..23a60828e8f0b03542bc2d6c396023fd6f92343e 100755
--- a/.vscodeignore
+++ b/.vscodeignore
@@ -9,4 +9,4 @@ node_modules/**
src/**
tests/**
.vscode/**
-.vscode/**
+**/*.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b3f32a981d6b114a3a3fb93fc044ce328c95b90..f8bf3f3ba96f9cb15680ba52eb982625599c7293 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,22 +1,5 @@
# Changelog
-## 0.4.0
-
-- Added linting and quick fixes for both CSS and markup
-- Updated module resolution for compatibility with pnpm (#128)
-- The extension now ignores the `purge` option when extracting class names (#131)
-- Fixed hover offsets for class names which appear after interpolations
-
-## 0.3.1
-
-- Fixed class attribute completions not showing when using the following Pug syntax (#125):
- ```
- div(class="")
- ```
-- Fixed hover previews not showing when using a computed class attribute in Vue templates
-- Restore missing readme images
-- Update settings descriptions to use markdown
-
## 0.3.0
### General
diff --git a/README.md b/README.md
index da341e65e5e2eb36d7069a87e9958b35a632318b..27cc6e8c480bc703fa2c9a987bd60aac0b73250a 100644
--- a/README.md
+++ b/README.md
@@ -1,129 +1,115 @@
-
-
-Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
## Installation
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
## Features
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
### Autocomplete
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
Intelligent suggestions for class names, as well as [CSS functions and directives](https://tailwindcss.com/docs/functions-and-directives/).
-
+- a `tailwind.config.js` file to be [present in your project folder](https://github.com/bradlc/vscode-tailwindcss/blob/master/package.json#L38). You can create it with `npx tailwind init`.
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
-### Linting
+## Features
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
## Installation
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
-
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
-
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
## Features
-
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
### Autocomplete
-
+In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
Intelligent suggestions for class names, as well as [CSS functions and directives](https://tailwindcss.com/docs/functions-and-directives/).
-
+## Features
-
-
+## Features
+## Features
-```json
+- [Improves syntax highlighting when using `@apply` and config helpers](#improves-syntax-highlighting-when-using-apply-and-config-helpers)
-Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-
+## Features
## Installation
+## Features
**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
-In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
-
+**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
## Features
-### Autocomplete
-
+#### CSS preview when hovering over class names
-Intelligent suggestions for class names, as well as [CSS functions and directives](https://tailwindcss.com/docs/functions-and-directives/).
-
-Enable completions when using [Emmet](https://emmet.io/)-style syntax, for example `div.bg-red-500.uppercase`. **Default: `false`**
+
-```json
+#### Suggestions when using `@apply` and config helpers
-Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
- "tailwindCSS.emmetCompletions": true
+
-## Features
-
### Autocomplete
-### `tailwindCSS.validate`
+Before:
-Enable linting. Rules can be configured individually using the `tailwindcss.lint` settings:
+### Autocomplete
-- `ignore`: disable lint rule entirely
-- `warning`: rule violations will be considered "warnings," typically represented by a yellow underline
-- `error`: rule violations will be considered "errors," typically represented by a red underline
+### Autocomplete
Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-## Features
-Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
### Autocomplete
+## Installation
-Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
+
Intelligent suggestions for class names, as well as [CSS functions and directives](https://tailwindcss.com/docs/functions-and-directives/).
-## Installation
+
-## Installation
+
-## Installation
+
-## Installation
Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-## Installation
## Installation
-## Installation
**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
-## Installation
In order for the extension to activate you must have [`tailwindcss` installed](https://tailwindcss.com/docs/installation/#1-install-tailwind-via-npm) and a [Tailwind config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional) named `tailwind.config.js` or `tailwind.js` in your workspace.
-## Installation
## Features
-## Installation
### Autocomplete
-## Troubleshooting
+### `tailwindcss.emmetCompletions`
-**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
+Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-- Ensure that you have a Tailwind config file in your workspace and that this is named `tailwind.config.js` or `tailwind.js`. Check out the Tailwind documentation for details on [creating a config file](https://tailwindcss.com/docs/installation/#3-create-your-tailwind-config-file-optional).
+```json
-**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
+Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
-**[Install via the Visual Studio Code Marketplace →](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**
Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
+
+}
+```
diff --git a/img/css-highlighting-after.png b/img/css-highlighting-after.png
new file mode 100755
index 0000000000000000000000000000000000000000..86a12fb8596e001e2c68d171733cb7950d66335c
Binary files /dev/null and b/img/css-highlighting-after.png differ
diff --git a/img/css-highlighting-before.png b/img/css-highlighting-before.png
new file mode 100755
index 0000000000000000000000000000000000000000..2eeffdc19d7293136e52f9426eb66456d0c1abb4
Binary files /dev/null and b/img/css-highlighting-before.png differ
diff --git a/img/css.gif b/img/css.gif
new file mode 100755
index 0000000000000000000000000000000000000000..e81904e7863349207daf4e368aae489a2f9374d8
Binary files /dev/null and b/img/css.gif differ
diff --git a/img/html-hover.gif b/img/html-hover.gif
new file mode 100755
index 0000000000000000000000000000000000000000..94540b86a062f0274f9ae1d3d755898f749fed43
Binary files /dev/null and b/img/html-hover.gif differ
diff --git a/img/html.gif b/img/html.gif
new file mode 100755
index 0000000000000000000000000000000000000000..8ffc7ffa9962333d28c60136b1f7ad50edf09883
Binary files /dev/null and b/img/html.gif differ
diff --git a/package-lock.json b/package-lock.json
index 9184c0f6d4d60cb918f95cc528656182719d94a9..91c1aca81ac946c1fd36e4fd59904914710f8008 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -2027,13 +2027,6 @@ "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=",
"dev": true
},
"@babel/helper-split-export-declaration": "^7.8.3",
- "dependencies": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz",
- "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==",
- "dev": true
- },
- "@babel/helper-split-export-declaration": "^7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -6091,12 +6084,6 @@ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
"dev": true,
"optional": true
- },
- "sift-string": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/sift-string/-/sift-string-0.0.2.tgz",
- "integrity": "sha1-G7ArEhslu4sHRwQr+afh2s+PuJw=",
- "dev": true
},
"signal-exit": {
"version": "3.0.3",
diff --git a/package.json b/package.json
index c209d4be4eee26ae6b6a3744e74f540a95d5624b..e234600cea927baa23013a2664e31a4b32f7e355 100755
--- a/package.json
+++ b/package.json
@@ -1,21 +1,23 @@
{
"name": "vscode-tailwindcss",
"displayName": "Tailwind CSS IntelliSense",
+{
"description": "Intelligent Tailwind CSS tooling for VS Code",
+ "preview": true,
"preview": true,
"author": "Brad Cornes ",
"license": "MIT",
"version": "0.3.1",
- "homepage": "https://github.com/tailwindcss/intellisense",
+ "homepage": "https://github.com/bradlc/vscode-tailwindcss",
"bugs": {
{
-{
+ "source.vue",
"email": "hello@bradley.dev"
},
"repository": {
"type": "git",
{
- "author": "Brad Cornes ",
+ "source.svelte",
},
"publisher": "bradlc",
"keywords": [
@@ -30,11 +32,10 @@ "engines": {
"vscode": "^1.33.0"
},
"categories": [
- "Linters",
"Other"
],
"galleryBanner": {
- "color": "#f9fafb"
+ "color": "#f1f5f8"
},
"icon": "media/icon.png",
"activationEvents": [
@@ -72,78 +73,6 @@ "type": "string"
},
"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.validate": {
- "type": "boolean",
- "default": true,
- "markdownDescription": "Enable linting",
- "scope": "language-overridable"
- },
- "tailwindCSS.lint.cssConflict": {
- "type": "string",
- "enum": [
- "ignore",
- "warning",
- "error"
- ],
- "default": "warning",
- "markdownDescription": "Class names on the same HTML element which apply the same CSS property or properties",
- "scope": "language-overridable"
- },
- "tailwindCSS.lint.invalidApply": {
- "type": "string",
- "enum": [
- "ignore",
- "warning",
- "error"
- ],
- "default": "error",
- "markdownDescription": "Unsupported use of the [`@apply` directive](https://tailwindcss.com/docs/functions-and-directives/#apply)",
- "scope": "language-overridable"
- },
- "tailwindCSS.lint.invalidScreen": {
- "type": "string",
- "enum": [
- "ignore",
- "warning",
- "error"
- ],
- "default": "error",
- "markdownDescription": "Unknown screen name used with the [`@screen` directive](https://tailwindcss.com/docs/functions-and-directives/#screen)",
- "scope": "language-overridable"
- },
- "tailwindCSS.lint.invalidVariant": {
- "type": "string",
- "enum": [
- "ignore",
- "warning",
- "error"
- ],
- "default": "error",
- "markdownDescription": "Unknown variant name used with the [`@variants` directive](https://tailwindcss.com/docs/functions-and-directives/#variants)",
- "scope": "language-overridable"
- },
- "tailwindCSS.lint.invalidConfigPath": {
- "type": "string",
- "enum": [
- "ignore",
- "warning",
- "error"
- ],
- "default": "error",
- "markdownDescription": "Unknown or invalid path used with the [`theme` helper](https://tailwindcss.com/docs/functions-and-directives/#theme)",
- "scope": "language-overridable"
- },
- "tailwindCSS.lint.invalidTailwindDirective": {
- "type": "string",
- "enum": [
- "ignore",
- "warning",
- "error"
- ],
- "default": "error",
- "markdownDescription": "Unknown value used with the [`@tailwind` directive](https://tailwindcss.com/docs/functions-and-directives/#tailwind)",
- "scope": "language-overridable"
}
}
}
@@ -169,8 +98,6 @@ "chokidar": "^3.3.1",
"concurrently": "^5.1.0",
"css.escape": "^1.5.1",
"url": "https://github.com/tailwindcss/intellisense/issues",
- "displayName": "Tailwind CSS IntelliSense",
- "url": "https://github.com/tailwindcss/intellisense/issues",
"description": "Intelligent Tailwind CSS tooling for VS Code",
"dset": "^2.0.1",
"esm": "^3.2.25",
@@ -189,7 +116,6 @@ "postcss-selector-parser": "^6.0.2",
"resolve-from": "^5.0.0",
"rimraf": "^3.0.2",
"semver": "^7.3.2",
- "sift-string": "0.0.2",
"stack-trace": "0.0.10",
"terser": "^4.6.12",
"tiny-invariant": "^1.1.0",
diff --git a/src/class-names/index.js b/src/class-names/index.js
index 0ddd81c9b9ed00ff1a357129203ce973b23911c1..ca8ddec1e8696085fcb79738f7bdb42fe08beb72 100644
--- a/src/class-names/index.js
+++ b/src/class-names/index.js
@@ -141,10 +141,6 @@ resolvedConfig,
postcss,
browserslist,
}),
- modules: {
- tailwindcss,
- postcss,
- },
}
}
diff --git a/src/extension.ts b/src/extension.ts
index 279ec969590ba1e30120474c179722fa450c238d..be1fe479cac88456c5893e28a533d1c3c2ec81ca 100755
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -12,8 +12,6 @@ OutputChannel,
WorkspaceFolder,
Uri,
/* --------------------------------------------------------------------------------------------
- * ------------------------------------------------------------------------------------------ */
-/* --------------------------------------------------------------------------------------------
import * as path from 'path'
import {
LanguageClient,
@@ -25,7 +23,6 @@ import { DEFAULT_LANGUAGES } from './lib/languages'
import isObject from './util/isObject'
import { dedupe, equal } from './util/array'
import { createEmitter } from './lib/emitter'
-import { onMessage } from './lsp/notifications'
const CLIENT_ID = 'tailwindcss-intellisense'
const CLIENT_NAME = 'Tailwind CSS IntelliSense'
@@ -154,9 +151,6 @@
client.onReady().then(() => {
let emitter = createEmitter(client)
registerConfigErrorHandler(emitter)
- onMessage(client, 'getConfiguration', async (scope) => {
- return Workspace.getConfiguration('tailwindCSS', scope)
- })
})
client.start()
diff --git a/src/lib/emitter.ts b/src/lib/emitter.ts
index 3ad6f05f010872359a4d0a2ef289456f37d74490..d177c2cf355a60b5c265fb5df12b01e0feb0ffb6 100644
--- a/src/lib/emitter.ts
+++ b/src/lib/emitter.ts
@@ -1,7 +1,6 @@
import mitt from 'mitt'
import { LanguageClient } from 'vscode-languageclient'
import crypto from 'crypto'
-import { Connection } from 'vscode-languageserver'
export interface NotificationEmitter {
on: (name: string, handler: (args: any) => void) => void
@@ -9,9 +8,7 @@ off: (name: string, handler: (args: any) => void) => void
emit: (name: string, args: any) => Promise
}
-export function createEmitter(
- client: LanguageClient | Connection
-): NotificationEmitter {
+export function createEmitter(client: LanguageClient): NotificationEmitter {
const emitter = mitt()
const registered: string[] = []
@@ -29,7 +26,7 @@ const off = (name: string, handler: (args: any) => void) => {
emitter.off(name, handler)
}
- const emit = (name: string, params: Record = {}) => {
+ const emit = (name: string, params: any) => {
return new Promise((resolve, _reject) => {
const id = crypto.randomBytes(16).toString('hex')
on(`${name}Response`, (result) => {
diff --git a/src/lsp/notifications.ts b/src/lsp/notifications.ts
index e8f4ab856ac0c1a8e4809e78761fb53640488742..bb4e60dc496922fe1221147ff41a690e5f60d344 100644
--- a/src/lsp/notifications.ts
+++ b/src/lsp/notifications.ts
@@ -1,10 +1,9 @@
import { Connection } from 'vscode-languageserver'
-import { LanguageClient } from 'vscode-languageclient'
export function onMessage(
- connection: LanguageClient | Connection,
+ connection: Connection,
name: string,
- handler: (params: any) => Thenable>
+ handler: (params: any) => any
): void {
connection.onNotification(`tailwindcss/${name}`, async (params: any) => {
const { _id, ...rest } = params
diff --git a/src/lsp/providers/codeActions/codeActionProvider.ts b/src/lsp/providers/codeActions/codeActionProvider.ts
deleted file mode 100644
index 19420f68ca37f549bac335634c81d8b5d3119af1..0000000000000000000000000000000000000000
--- a/src/lsp/providers/codeActions/codeActionProvider.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { CodeAction, CodeActionParams } from 'vscode-languageserver'
-import { State } from '../../util/state'
-import { getDiagnostics } from '../diagnostics/diagnosticsProvider'
-import { rangesEqual } from '../../util/rangesEqual'
-import {
- DiagnosticKind,
- isInvalidApplyDiagnostic,
- AugmentedDiagnostic,
- isCssConflictDiagnostic,
- isInvalidConfigPathDiagnostic,
- isInvalidTailwindDirectiveDiagnostic,
- isInvalidScreenDiagnostic,
- isInvalidVariantDiagnostic,
-} from '../diagnostics/types'
-import { flatten, dedupeBy } from '../../../util/array'
-import { provideCssConflictCodeActions } from './provideCssConflictCodeActions'
-import { provideInvalidApplyCodeActions } from './provideInvalidApplyCodeActions'
-import { provideSuggestionCodeActions } from './provideSuggestionCodeActions'
-
-async function getDiagnosticsFromCodeActionParams(
- state: State,
- params: CodeActionParams,
- only?: DiagnosticKind[]
-): Promise {
- let document = state.editor.documents.get(params.textDocument.uri)
- let diagnostics = await getDiagnostics(state, document, only)
-
- return params.context.diagnostics
- .map((diagnostic) => {
- return diagnostics.find((d) => {
- return (
- d.code === diagnostic.code &&
- d.message === diagnostic.message &&
- rangesEqual(d.range, diagnostic.range)
- )
- })
- })
- .filter(Boolean)
-}
-
-export async function provideCodeActions(
- state: State,
- params: CodeActionParams
-): Promise {
- let diagnostics = await getDiagnosticsFromCodeActionParams(
- state,
- params,
- params.context.diagnostics
- .map((diagnostic) => diagnostic.code)
- .filter(Boolean) as DiagnosticKind[]
- )
-
- return Promise.all(
- diagnostics.map((diagnostic) => {
- if (isInvalidApplyDiagnostic(diagnostic)) {
- return provideInvalidApplyCodeActions(state, params, diagnostic)
- }
-
- if (isCssConflictDiagnostic(diagnostic)) {
- return provideCssConflictCodeActions(state, params, diagnostic)
- }
-
- if (
- isInvalidConfigPathDiagnostic(diagnostic) ||
- isInvalidTailwindDirectiveDiagnostic(diagnostic) ||
- isInvalidScreenDiagnostic(diagnostic) ||
- isInvalidVariantDiagnostic(diagnostic)
- ) {
- return provideSuggestionCodeActions(state, params, diagnostic)
- }
-
- return []
- })
- )
- .then(flatten)
- .then((x) => dedupeBy(x, (item) => JSON.stringify(item.edit)))
-}
diff --git a/src/lsp/providers/codeActions/provideCssConflictCodeActions.ts b/src/lsp/providers/codeActions/provideCssConflictCodeActions.ts
deleted file mode 100644
index f6a6edb159000f7e53aae3c88e6b7fef94d08b70..0000000000000000000000000000000000000000
--- a/src/lsp/providers/codeActions/provideCssConflictCodeActions.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { State } from '../../util/state'
-import {
- CodeActionParams,
- CodeAction,
- CodeActionKind,
-} from 'vscode-languageserver'
-import { CssConflictDiagnostic } from '../diagnostics/types'
-import { joinWithAnd } from '../../util/joinWithAnd'
-import { removeRangesFromString } from '../../util/removeRangesFromString'
-
-export async function provideCssConflictCodeActions(
- _state: State,
- params: CodeActionParams,
- diagnostic: CssConflictDiagnostic
-): Promise {
- return [
- {
- title: `Delete ${joinWithAnd(
- diagnostic.otherClassNames.map(
- (otherClassName) => `'${otherClassName.className}'`
- )
- )}`,
- kind: CodeActionKind.QuickFix,
- diagnostics: [diagnostic],
- edit: {
- changes: {
- [params.textDocument.uri]: [
- {
- range: diagnostic.className.classList.range,
- newText: removeRangesFromString(
- diagnostic.className.classList.classList,
- diagnostic.otherClassNames.map(
- (otherClassName) => otherClassName.relativeRange
- )
- ),
- },
- ],
- },
- },
- },
- ]
-}
diff --git a/src/lsp/providers/codeActions/provideInvalidApplyCodeActions.ts b/src/lsp/providers/codeActions/provideInvalidApplyCodeActions.ts
deleted file mode 100644
index ec3d483b6234cb1508465dfbdaabf9154173ff2a..0000000000000000000000000000000000000000
--- a/src/lsp/providers/codeActions/provideInvalidApplyCodeActions.ts
+++ /dev/null
@@ -1,266 +0,0 @@
-import {
- CodeAction,
- CodeActionParams,
- CodeActionKind,
- TextEdit,
- Range,
-} from 'vscode-languageserver'
-import { State } from '../../util/state'
-import { InvalidApplyDiagnostic } from '../diagnostics/types'
-import { getClassNameParts } from '../../util/getClassNameAtPosition'
-import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
-import { isCssDoc } from '../../util/css'
-import { isWithinRange } from '../../util/isWithinRange'
-const dlv = require('dlv')
-import type { Root, NodeSource } from 'postcss'
-import { absoluteRange } from '../../util/absoluteRange'
-import { removeRangesFromString } from '../../util/removeRangesFromString'
-import detectIndent from 'detect-indent'
-import isObject from '../../../util/isObject'
-import { cssObjToAst } from '../../util/cssObjToAst'
-import dset from 'dset'
-import selectorParser from 'postcss-selector-parser'
-import { flatten } from '../../../util/array'
-import { getClassNameMeta } from '../../util/getClassNameMeta'
-import { validateApply } from '../../util/validateApply'
-
-export async function provideInvalidApplyCodeActions(
- state: State,
- params: CodeActionParams,
- diagnostic: InvalidApplyDiagnostic
-): Promise {
- let document = state.editor.documents.get(params.textDocument.uri)
- let documentText = document.getText()
- let cssRange: Range
- let cssText = documentText
- const { postcss } = state.modules
- let changes: TextEdit[] = []
-
- let totalClassNamesInClassList = diagnostic.className.classList.classList.split(
- /\s+/
- ).length
-
- let className = diagnostic.className.className
- let classNameParts = getClassNameParts(state, className)
- let classNameInfo = dlv(state.classNames.classNames, classNameParts)
-
- if (Array.isArray(classNameInfo)) {
- return []
- }
-
- if (!isCssDoc(state, document)) {
- let languageBoundaries = getLanguageBoundaries(state, document)
- if (!languageBoundaries) return []
- cssRange = languageBoundaries.css.find((range) =>
- isWithinRange(diagnostic.range.start, range)
- )
- if (!cssRange) return []
- cssText = document.getText(cssRange)
- }
-
- try {
- await postcss([
- postcss.plugin('', (_options = {}) => {
- return (root: Root) => {
- root.walkRules((rule) => {
- if (changes.length) return false
-
- rule.walkAtRules('apply', (atRule) => {
- let atRuleRange = postcssSourceToRange(atRule.source)
- if (cssRange) {
- atRuleRange = absoluteRange(atRuleRange, cssRange)
- }
-
- if (!isWithinRange(diagnostic.range.start, atRuleRange))
- return true
-
- let ast = classNameToAst(
- state,
- classNameParts,
- rule.selector,
- diagnostic.className.classList.important
- )
-
- if (!ast) return false
-
- rule.after(ast.nodes)
- let insertedRule = rule.next()
- if (!insertedRule) return false
-
- if (totalClassNamesInClassList === 1) {
- atRule.remove()
- } else {
- changes.push({
- range: diagnostic.className.classList.range,
- newText: removeRangesFromString(
- diagnostic.className.classList.classList,
- diagnostic.className.relativeRange
- ),
- })
- }
-
- let ruleRange = postcssSourceToRange(rule.source)
- if (cssRange) {
- ruleRange = absoluteRange(ruleRange, cssRange)
- }
-
- let outputIndent: string
- let documentIndent = detectIndent(cssText)
-
- changes.push({
- range: ruleRange,
- newText:
- rule.toString() +
- (insertedRule.raws.before || '\n\n') +
- insertedRule
- .toString()
- .replace(/\n\s*\n/g, '\n')
- .replace(/(@apply [^;\n]+)$/gm, '$1;')
- .replace(/([^\s^]){$/gm, '$1 {')
- .replace(/^\s+/gm, (m: string) => {
- if (typeof outputIndent === 'undefined') outputIndent = m
- return m.replace(
- new RegExp(outputIndent, 'g'),
- documentIndent.indent
- )
- })
- .replace(/^(\s+)(.*?[^{}]\n)([^\s}])/gm, '$1$2$1$3'),
- })
-
- return false
- })
- })
- }
- }),
- ]).process(cssText, { from: undefined })
- } catch (_) {
- return []
- }
-
- if (!changes.length) {
- return []
- }
-
- return [
- {
- title: 'Extract to new rule',
- kind: CodeActionKind.QuickFix,
- diagnostics: [diagnostic],
- edit: {
- changes: {
- [params.textDocument.uri]: changes,
- },
- },
- },
- ]
-}
-
-function postcssSourceToRange(source: NodeSource): Range {
- return {
- start: {
- line: source.start.line - 1,
- character: source.start.column - 1,
- },
- end: {
- line: source.end.line - 1,
- character: source.end.column,
- },
- }
-}
-
-function classNameToAst(
- state: State,
- classNameParts: string[],
- selector: string,
- important: boolean = false
-) {
- const baseClassName = classNameParts[classNameParts.length - 1]
- const validatedBaseClassName = validateApply(state, [baseClassName])
- if (
- validatedBaseClassName === null ||
- validatedBaseClassName.isApplyable === false
- ) {
- return null
- }
- const meta = getClassNameMeta(state, classNameParts)
- if (Array.isArray(meta)) return null
- let context = meta.context
- let pseudo = meta.pseudo
- const globalContexts = state.classNames.context
- let screens = dlv(
- state.config,
- 'theme.screens',
- dlv(state.config, 'screens', {})
- )
- if (!isObject(screens)) screens = {}
- screens = Object.keys(screens)
- const path = []
-
- for (let i = 0; i < classNameParts.length - 1; i++) {
- let part = classNameParts[i]
- let common = globalContexts[part]
- if (!common) return null
- if (screens.includes(part)) {
- path.push(`@screen ${part}`)
- context = context.filter((con) => !common.includes(con))
- }
- }
-
- path.push(...context)
-
- let obj = {}
- for (let i = 1; i <= path.length; i++) {
- dset(obj, path.slice(0, i), {})
- }
-
- selector = appendPseudosToSelector(selector, pseudo)
- if (selector === null) return null
-
- let rule = {
- [selector]: {
- [`@apply ${baseClassName}${important ? ' !important' : ''}`]: '',
- },
- }
- if (path.length) {
- dset(obj, path, rule)
- } else {
- obj = rule
- }
-
- return cssObjToAst(obj, state.modules.postcss)
-}
-
-function appendPseudosToSelector(
- selector: string,
- pseudos: string[]
-): string | null {
- if (pseudos.length === 0) return selector
-
- let canTransform = true
-
- let transformedSelector = selectorParser((selectors) => {
- flatten(selectors.split((_) => true)).forEach((sel) => {
- // @ts-ignore
- for (let i = sel.nodes.length - 1; i >= 0; i--) {
- // @ts-ignore
- if (sel.nodes[i].type !== 'pseudo') {
- break
- // @ts-ignore
- } else if (pseudos.includes(sel.nodes[i].value)) {
- canTransform = false
- break
- }
- }
- if (canTransform) {
- pseudos.forEach((p) => {
- // @ts-ignore
- sel.append(selectorParser.pseudo({ value: p }))
- })
- }
- })
- }).processSync(selector)
-
- if (!canTransform) return null
-
- return transformedSelector
-}
diff --git a/src/lsp/providers/codeActions/provideSuggestionCodeActions.ts b/src/lsp/providers/codeActions/provideSuggestionCodeActions.ts
deleted file mode 100644
index 9da5fcb58f4863d4f6edc2643319263f95c22aa6..0000000000000000000000000000000000000000
--- a/src/lsp/providers/codeActions/provideSuggestionCodeActions.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { State } from '../../util/state'
-import {
- CodeActionParams,
- CodeAction,
- CodeActionKind,
-} from 'vscode-languageserver'
-import {
- InvalidConfigPathDiagnostic,
- InvalidTailwindDirectiveDiagnostic,
- InvalidScreenDiagnostic,
- InvalidVariantDiagnostic,
-} from '../diagnostics/types'
-
-export function provideSuggestionCodeActions(
- _state: State,
- params: CodeActionParams,
- diagnostic:
- | InvalidConfigPathDiagnostic
- | InvalidTailwindDirectiveDiagnostic
- | InvalidScreenDiagnostic
- | InvalidVariantDiagnostic
-): CodeAction[] {
- return diagnostic.suggestions.map((suggestion) => ({
- title: `Replace with '${suggestion}'`,
- kind: CodeActionKind.QuickFix,
- diagnostics: [diagnostic],
- edit: {
- changes: {
- [params.textDocument.uri]: [
- {
- range: diagnostic.range,
- newText: suggestion,
- },
- ],
- },
- },
- }))
-}
diff --git a/src/lsp/providers/completionProvider.ts b/src/lsp/providers/completionProvider.ts
index ec93d4449fe796128d72d2e9397e2cbd82ee828b..6dbb1e7a8de391c327c00dee9b74fb0b1fe08c87 100644
--- a/src/lsp/providers/completionProvider.ts
+++ b/src/lsp/providers/completionProvider.ts
@@ -618,14 +618,13 @@ async function provideEmmetCompletions(
state: State,
{ position, textDocument }: CompletionParams
): Promise {
-const dlv = require('dlv')
+ let subsetKey: string[] = []
} from 'vscode-languageserver'
CompletionItem,
- CompletionItem,
CompletionItemKind,
- CompletionItem,
+ CompletionItemKind,
CompletionItem,
- let replacementRange = {
+ let doc = state.editor.documents.get(textDocument.uri)
const syntax = isHtmlContext(state, doc, position)
? 'html'
diff --git a/src/lsp/providers/diagnostics/diagnosticsProvider.ts b/src/lsp/providers/diagnostics/diagnosticsProvider.ts
deleted file mode 100644
index a22f8460e8c1eef13c3db52052b37d051a58797a..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/diagnosticsProvider.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { TextDocument } from 'vscode-languageserver'
-import { State } from '../../util/state'
-import { getDocumentSettings } from '../../util/getDocumentSettings'
-import { DiagnosticKind, AugmentedDiagnostic } from './types'
-import { getCssConflictDiagnostics } from './getCssConflictDiagnostics'
-import { getInvalidApplyDiagnostics } from './getInvalidApplyDiagnostics'
-import { getInvalidScreenDiagnostics } from './getInvalidScreenDiagnostics'
-import { getInvalidVariantDiagnostics } from './getInvalidVariantDiagnostics'
-import { getInvalidConfigPathDiagnostics } from './getInvalidConfigPathDiagnostics'
-import { getInvalidTailwindDirectiveDiagnostics } from './getInvalidTailwindDirectiveDiagnostics'
-
-export async function getDiagnostics(
- state: State,
- document: TextDocument,
- only: DiagnosticKind[] = [
- DiagnosticKind.CssConflict,
- DiagnosticKind.InvalidApply,
- DiagnosticKind.InvalidScreen,
- DiagnosticKind.InvalidVariant,
- DiagnosticKind.InvalidConfigPath,
- DiagnosticKind.InvalidTailwindDirective,
- ]
-): Promise {
- const settings = await getDocumentSettings(state, document)
-
- return settings.validate
- ? [
- ...(only.includes(DiagnosticKind.CssConflict)
- ? getCssConflictDiagnostics(state, document, settings)
- : []),
- ...(only.includes(DiagnosticKind.InvalidApply)
- ? getInvalidApplyDiagnostics(state, document, settings)
- : []),
- ...(only.includes(DiagnosticKind.InvalidScreen)
- ? getInvalidScreenDiagnostics(state, document, settings)
- : []),
- ...(only.includes(DiagnosticKind.InvalidVariant)
- ? getInvalidVariantDiagnostics(state, document, settings)
- : []),
- ...(only.includes(DiagnosticKind.InvalidConfigPath)
- ? getInvalidConfigPathDiagnostics(state, document, settings)
- : []),
- ...(only.includes(DiagnosticKind.InvalidTailwindDirective)
- ? getInvalidTailwindDirectiveDiagnostics(state, document, settings)
- : []),
- ]
- : []
-}
-
-export async function provideDiagnostics(state: State, document: TextDocument) {
- state.editor.connection.sendDiagnostics({
- uri: document.uri,
- diagnostics: await getDiagnostics(state, document),
- })
-}
-
-export function clearDiagnostics(state: State, document: TextDocument): void {
- state.editor.connection.sendDiagnostics({
- uri: document.uri,
- diagnostics: [],
- })
-}
-
-export function clearAllDiagnostics(state: State): void {
- state.editor.documents.all().forEach((document) => {
- clearDiagnostics(state, document)
- })
-}
-
-export function updateAllDiagnostics(state: State): void {
- state.editor.documents.all().forEach((document) => {
- provideDiagnostics(state, document)
- })
-}
diff --git a/src/lsp/providers/diagnostics/getCssConflictDiagnostics.ts b/src/lsp/providers/diagnostics/getCssConflictDiagnostics.ts
deleted file mode 100644
index 73da4869da22efd201be30ab434b9f61a0a5b3b6..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/getCssConflictDiagnostics.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import { joinWithAnd } from '../../util/joinWithAnd'
-import { State, Settings } from '../../util/state'
-import { TextDocument, DiagnosticSeverity } from 'vscode-languageserver'
-import { CssConflictDiagnostic, DiagnosticKind } from './types'
-import {
- findClassListsInDocument,
- getClassNamesInClassList,
-} from '../../util/find'
-import { getClassNameDecls } from '../../util/getClassNameDecls'
-import { getClassNameMeta } from '../../util/getClassNameMeta'
-import { equal } from '../../../util/array'
-
-export function getCssConflictDiagnostics(
- state: State,
- document: TextDocument,
- settings: Settings
-): CssConflictDiagnostic[] {
- let severity = settings.lint.cssConflict
- if (severity === 'ignore') return []
-
- let diagnostics: CssConflictDiagnostic[] = []
- const classLists = findClassListsInDocument(state, document)
-
- classLists.forEach((classList) => {
- const classNames = getClassNamesInClassList(classList)
-
- classNames.forEach((className, index) => {
- let decls = getClassNameDecls(state, className.className)
- if (!decls) return
-
- let properties = Object.keys(decls)
- let meta = getClassNameMeta(state, className.className)
-
- let otherClassNames = classNames.filter((_className, i) => i !== index)
-
- let conflictingClassNames = otherClassNames.filter((otherClassName) => {
- let otherDecls = getClassNameDecls(state, otherClassName.className)
- if (!otherDecls) return false
-
- let otherMeta = getClassNameMeta(state, otherClassName.className)
-
- return (
- equal(properties, Object.keys(otherDecls)) &&
- !Array.isArray(meta) &&
- !Array.isArray(otherMeta) &&
- equal(meta.context, otherMeta.context) &&
- equal(meta.pseudo, otherMeta.pseudo)
- )
- })
-
- if (conflictingClassNames.length === 0) return
-
- diagnostics.push({
- code: DiagnosticKind.CssConflict,
- className,
- otherClassNames: conflictingClassNames,
- range: className.range,
- severity:
- severity === 'error'
- ? DiagnosticSeverity.Error
- : DiagnosticSeverity.Warning,
- message: `'${className.className}' applies the same CSS ${
- properties.length === 1 ? 'property' : 'properties'
- } as ${joinWithAnd(
- conflictingClassNames.map(
- (conflictingClassName) => `'${conflictingClassName.className}'`
- )
- )}.`,
- relatedInformation: conflictingClassNames.map(
- (conflictingClassName) => {
- return {
- message: conflictingClassName.className,
- location: {
- uri: document.uri,
- range: conflictingClassName.range,
- },
- }
- }
- ),
- })
- })
- })
-
- return diagnostics
-}
diff --git a/src/lsp/providers/diagnostics/getInvalidApplyDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidApplyDiagnostics.ts
deleted file mode 100644
index e829b5735e74900f08d5d7161c5d561eebd7b89f..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/getInvalidApplyDiagnostics.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { findClassNamesInRange } from '../../util/find'
-import { InvalidApplyDiagnostic, DiagnosticKind } from './types'
-import { Settings, State } from '../../util/state'
-import { TextDocument, DiagnosticSeverity } from 'vscode-languageserver'
-import { validateApply } from '../../util/validateApply'
-
-export function getInvalidApplyDiagnostics(
- state: State,
- document: TextDocument,
- settings: Settings
-): InvalidApplyDiagnostic[] {
- let severity = settings.lint.invalidApply
- if (severity === 'ignore') return []
-
- const classNames = findClassNamesInRange(document, undefined, 'css')
-
- let diagnostics: InvalidApplyDiagnostic[] = classNames.map((className) => {
- let result = validateApply(state, className.className)
-
- if (result === null || result.isApplyable === true) {
- return null
- }
-
- return {
- code: DiagnosticKind.InvalidApply,
- severity:
- severity === 'error'
- ? DiagnosticSeverity.Error
- : DiagnosticSeverity.Warning,
- range: className.range,
- message: result.reason,
- className,
- }
- })
-
- return diagnostics.filter(Boolean)
-}
diff --git a/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts
deleted file mode 100644
index ccf52fcb1aa3b88bd1b73aa9963e0e7729b29cca..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/getInvalidConfigPathDiagnostics.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
-import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
-import { isCssDoc } from '../../util/css'
-import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
-import { findAll, indexToPosition } from '../../util/find'
-import { stringToPath } from '../../util/stringToPath'
-import isObject from '../../../util/isObject'
-import { closest } from '../../util/closest'
-import { absoluteRange } from '../../util/absoluteRange'
-import { combinations } from '../../util/combinations'
-const dlv = require('dlv')
-
-function pathToString(path: string | string[]): string {
- if (typeof path === 'string') return path
- return path.reduce((acc, cur, i) => {
- if (i === 0) return cur
- if (cur.includes('.')) return `${acc}[${cur}]`
- return `${acc}.${cur}`
- }, '')
-}
-
-function validateConfigPath(
- state: State,
- path: string | string[],
- base: string[] = []
-):
- | { isValid: true; value: any }
- | { isValid: false; reason: string; suggestions: string[] } {
- let keys = Array.isArray(path) ? path : stringToPath(path)
- let value = dlv(state.config, [...base, ...keys])
- let suggestions: string[] = []
-
- function findAlternativePath(): string[] {
- let points = combinations('123456789'.substr(0, keys.length - 1)).map((x) =>
- x.split('').map((x) => parseInt(x, 10))
- )
-
- let possibilities: string[][] = points
- .map((p) => {
- let result = []
- let i = 0
- p.forEach((x) => {
- result.push(keys.slice(i, x).join('.'))
- i = x
- })
- result.push(keys.slice(i).join('.'))
- return result
- })
- .slice(1) // skip original path
-
- return possibilities.find(
- (possibility) => validateConfigPath(state, possibility, base).isValid
- )
- }
-
- if (typeof value === 'undefined') {
- let reason = `'${pathToString(path)}' does not exist in your theme config.`
- let parentPath = [...base, ...keys.slice(0, keys.length - 1)]
- let parentValue = dlv(state.config, parentPath)
-
- if (isObject(parentValue)) {
- let closestValidKey = closest(
- keys[keys.length - 1],
- Object.keys(parentValue).filter(
- (key) => validateConfigPath(state, [...parentPath, key]).isValid
- )
- )
- if (closestValidKey) {
- suggestions.push(
- pathToString([...keys.slice(0, keys.length - 1), closestValidKey])
- )
- reason += ` Did you mean '${suggestions[0]}'?`
- }
- } else {
- let altPath = findAlternativePath()
- if (altPath) {
- return {
- isValid: false,
- reason: `${reason} Did you mean '${pathToString(altPath)}'?`,
- suggestions: [pathToString(altPath)],
- }
- }
- }
-
- return {
- isValid: false,
- reason,
- suggestions,
- }
- }
-
- if (
- !(
- typeof value === 'string' ||
- typeof value === 'number' ||
- value instanceof String ||
- value instanceof Number ||
- Array.isArray(value)
- )
- ) {
- let reason = `'${pathToString(
- path
- )}' was found but does not resolve to a string.`
-
- if (isObject(value)) {
- let validKeys = Object.keys(value).filter(
- (key) => validateConfigPath(state, [...keys, key], base).isValid
- )
- if (validKeys.length) {
- suggestions.push(
- ...validKeys.map((validKey) => pathToString([...keys, validKey]))
- )
- reason += ` Did you mean something like '${suggestions[0]}'?`
- }
- }
- return {
- isValid: false,
- reason,
- suggestions,
- }
- }
-
- // The value resolves successfully, but we need to check that there
- // wasn't any funny business. If you have a theme object:
- // { msg: 'hello' } and do theme('msg.0')
- // this will resolve to 'h', which is probably not intentional, so we
- // check that all of the keys are object or array keys (i.e. not string
- // indexes)
- let isValid = true
- for (let i = keys.length - 1; i >= 0; i--) {
- let key = keys[i]
- let parentValue = dlv(state.config, [...base, ...keys.slice(0, i)])
- if (/^[0-9]+$/.test(key)) {
- if (!isObject(parentValue) && !Array.isArray(parentValue)) {
- isValid = false
- break
- }
- } else if (!isObject(parentValue)) {
- isValid = false
- break
- }
- }
- if (!isValid) {
- let reason = `'${pathToString(path)}' does not exist in your theme config.`
-
- let altPath = findAlternativePath()
- if (altPath) {
- return {
- isValid: false,
- reason: `${reason} Did you mean '${pathToString(altPath)}'?`,
- suggestions: [pathToString(altPath)],
- }
- }
-
- return {
- isValid: false,
- reason,
- suggestions: [],
- }
- }
-
- return {
- isValid: true,
- value,
- }
-}
-
-export function getInvalidConfigPathDiagnostics(
- state: State,
- document: TextDocument,
- settings: Settings
-): InvalidConfigPathDiagnostic[] {
- let severity = settings.lint.invalidConfigPath
- if (severity === 'ignore') return []
-
- let diagnostics: InvalidConfigPathDiagnostic[] = []
- let ranges: Range[] = []
-
- if (isCssDoc(state, document)) {
- ranges.push(undefined)
- } else {
- let boundaries = getLanguageBoundaries(state, document)
- if (!boundaries) return []
- ranges.push(...boundaries.css)
- }
-
- ranges.forEach((range) => {
- let text = document.getText(range)
- let matches = findAll(
- /(?\s|^)(?config|theme)\((?['"])(?[^)]+)\k\)/g,
- text
- )
-
- matches.forEach((match) => {
- let base = match.groups.helper === 'theme' ? ['theme'] : []
- let result = validateConfigPath(state, match.groups.key, base)
-
- if (result.isValid === true) {
- return null
- }
-
- let startIndex =
- match.index +
- match.groups.prefix.length +
- match.groups.helper.length +
- 1 + // open paren
- match.groups.quote.length
-
- diagnostics.push({
- code: DiagnosticKind.InvalidConfigPath,
- range: absoluteRange(
- {
- start: indexToPosition(text, startIndex),
- end: indexToPosition(text, startIndex + match.groups.key.length),
- },
- range
- ),
- severity:
- severity === 'error'
- ? DiagnosticSeverity.Error
- : DiagnosticSeverity.Warning,
- message: result.reason,
- suggestions: result.suggestions,
- })
- })
- })
-
- return diagnostics
-}
diff --git a/src/lsp/providers/diagnostics/getInvalidScreenDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidScreenDiagnostics.ts
deleted file mode 100644
index b0e4252438ea6bb7dd47071189c3881aae219225..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/getInvalidScreenDiagnostics.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
-import { InvalidScreenDiagnostic, DiagnosticKind } from './types'
-import { isCssDoc } from '../../util/css'
-import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
-import { findAll, indexToPosition } from '../../util/find'
-import { closest } from '../../util/closest'
-import { absoluteRange } from '../../util/absoluteRange'
-const dlv = require('dlv')
-
-export function getInvalidScreenDiagnostics(
- state: State,
- document: TextDocument,
- settings: Settings
-): InvalidScreenDiagnostic[] {
- let severity = settings.lint.invalidScreen
- if (severity === 'ignore') return []
-
- let diagnostics: InvalidScreenDiagnostic[] = []
- let ranges: Range[] = []
-
- if (isCssDoc(state, document)) {
- ranges.push(undefined)
- } else {
- let boundaries = getLanguageBoundaries(state, document)
- if (!boundaries) return []
- ranges.push(...boundaries.css)
- }
-
- ranges.forEach((range) => {
- let text = document.getText(range)
- let matches = findAll(/(?:\s|^)@screen\s+(?[^\s{]+)/g, text)
-
- let screens = Object.keys(
- dlv(state.config, 'theme.screens', dlv(state.config, 'screens', {}))
- )
-
- matches.forEach((match) => {
- if (screens.includes(match.groups.screen)) {
- return null
- }
-
- let message = `The screen '${match.groups.screen}' does not exist in your theme config.`
- let suggestions: string[] = []
- let suggestion = closest(match.groups.screen, screens)
-
- if (suggestion) {
- suggestions.push(suggestion)
- message += ` Did you mean '${suggestion}'?`
- }
-
- diagnostics.push({
- code: DiagnosticKind.InvalidScreen,
- range: absoluteRange(
- {
- start: indexToPosition(
- text,
- match.index + match[0].length - match.groups.screen.length
- ),
- end: indexToPosition(text, match.index + match[0].length),
- },
- range
- ),
- severity:
- severity === 'error'
- ? DiagnosticSeverity.Error
- : DiagnosticSeverity.Warning,
- message,
- suggestions,
- })
- })
- })
-
- return diagnostics
-}
diff --git a/src/lsp/providers/diagnostics/getInvalidTailwindDirectiveDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidTailwindDirectiveDiagnostics.ts
deleted file mode 100644
index 9b88bdb06e0e5c3754c6c5eecbf23af7c342a21d..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/getInvalidTailwindDirectiveDiagnostics.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
-import { InvalidTailwindDirectiveDiagnostic, DiagnosticKind } from './types'
-import { isCssDoc } from '../../util/css'
-import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
-import { findAll, indexToPosition } from '../../util/find'
-import semver from 'semver'
-import { closest } from '../../util/closest'
-import { absoluteRange } from '../../util/absoluteRange'
-
-export function getInvalidTailwindDirectiveDiagnostics(
- state: State,
- document: TextDocument,
- settings: Settings
-): InvalidTailwindDirectiveDiagnostic[] {
- let severity = settings.lint.invalidTailwindDirective
- if (severity === 'ignore') return []
-
- let diagnostics: InvalidTailwindDirectiveDiagnostic[] = []
- let ranges: Range[] = []
-
- if (isCssDoc(state, document)) {
- ranges.push(undefined)
- } else {
- let boundaries = getLanguageBoundaries(state, document)
- if (!boundaries) return []
- ranges.push(...boundaries.css)
- }
-
- ranges.forEach((range) => {
- let text = document.getText(range)
- let matches = findAll(/(?:\s|^)@tailwind\s+(?[^;]+)/g, text)
-
- let valid = [
- 'utilities',
- 'components',
- 'screens',
- semver.gte(state.version, '1.0.0-beta.1') ? 'base' : 'preflight',
- ]
-
- matches.forEach((match) => {
- if (valid.includes(match.groups.value)) {
- return null
- }
-
- let message = `'${match.groups.value}' is not a valid group.`
- let suggestions: string[] = []
-
- if (match.groups.value === 'preflight') {
- suggestions.push('base')
- message += ` Did you mean 'base'?`
- } else {
- let suggestion = closest(match.groups.value, valid)
- if (suggestion) {
- suggestions.push(suggestion)
- message += ` Did you mean '${suggestion}'?`
- }
- }
-
- diagnostics.push({
- code: DiagnosticKind.InvalidTailwindDirective,
- range: absoluteRange(
- {
- start: indexToPosition(
- text,
- match.index + match[0].length - match.groups.value.length
- ),
- end: indexToPosition(text, match.index + match[0].length),
- },
- range
- ),
- severity:
- severity === 'error'
- ? DiagnosticSeverity.Error
- : DiagnosticSeverity.Warning,
- message,
- suggestions,
- })
- })
- })
-
- return diagnostics
-}
diff --git a/src/lsp/providers/diagnostics/getInvalidVariantDiagnostics.ts b/src/lsp/providers/diagnostics/getInvalidVariantDiagnostics.ts
deleted file mode 100644
index 006740103c2776d4d68d6452dd5f808b8100a5d2..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/getInvalidVariantDiagnostics.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { State, Settings } from '../../util/state'
-import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
-import { InvalidVariantDiagnostic, DiagnosticKind } from './types'
-import { isCssDoc } from '../../util/css'
-import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
-import { findAll, indexToPosition } from '../../util/find'
-import { closest } from '../../util/closest'
-import { absoluteRange } from '../../util/absoluteRange'
-
-export function getInvalidVariantDiagnostics(
- state: State,
- document: TextDocument,
- settings: Settings
-): InvalidVariantDiagnostic[] {
- let severity = settings.lint.invalidVariant
- if (severity === 'ignore') return []
-
- let diagnostics: InvalidVariantDiagnostic[] = []
- let ranges: Range[] = []
-
- if (isCssDoc(state, document)) {
- ranges.push(undefined)
- } else {
- let boundaries = getLanguageBoundaries(state, document)
- if (!boundaries) return []
- ranges.push(...boundaries.css)
- }
-
- ranges.forEach((range) => {
- let text = document.getText(range)
- let matches = findAll(/(?:\s|^)@variants\s+(?[^{]+)/g, text)
-
- matches.forEach((match) => {
- let variants = match.groups.variants.split(/(\s*,\s*)/)
- let listStartIndex =
- match.index + match[0].length - match.groups.variants.length
-
- for (let i = 0; i < variants.length; i += 2) {
- let variant = variants[i].trim()
- if (state.variants.includes(variant)) {
- continue
- }
-
- let message = `The variant '${variant}' does not exist.`
- let suggestions: string[] = []
- let suggestion = closest(variant, state.variants)
-
- if (suggestion) {
- suggestions.push(suggestion)
- message += ` Did you mean '${suggestion}'?`
- }
-
- let variantStartIndex =
- listStartIndex + variants.slice(0, i).join('').length
-
- diagnostics.push({
- code: DiagnosticKind.InvalidVariant,
- range: absoluteRange(
- {
- start: indexToPosition(text, variantStartIndex),
- end: indexToPosition(text, variantStartIndex + variant.length),
- },
- range
- ),
- severity:
- severity === 'error'
- ? DiagnosticSeverity.Error
- : DiagnosticSeverity.Warning,
- message,
- suggestions,
- })
- }
- })
- })
-
- return diagnostics
-}
diff --git a/src/lsp/providers/diagnostics/types.ts b/src/lsp/providers/diagnostics/types.ts
deleted file mode 100644
index 1cfd0e2b4d4b26b543776be2c4810661b799f6c2..0000000000000000000000000000000000000000
--- a/src/lsp/providers/diagnostics/types.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { Diagnostic } from 'vscode-languageserver'
-import { DocumentClassName, DocumentClassList } from '../../util/state'
-
-export enum DiagnosticKind {
- CssConflict = 'cssConflict',
- InvalidApply = 'invalidApply',
- InvalidScreen = 'invalidScreen',
- InvalidVariant = 'invalidVariant',
- InvalidConfigPath = 'invalidConfigPath',
- InvalidTailwindDirective = 'invalidTailwindDirective',
-}
-
-export type CssConflictDiagnostic = Diagnostic & {
- code: DiagnosticKind.CssConflict
- className: DocumentClassName
- otherClassNames: DocumentClassName[]
-}
-
-export function isCssConflictDiagnostic(
- diagnostic: AugmentedDiagnostic
-): diagnostic is CssConflictDiagnostic {
- return diagnostic.code === DiagnosticKind.CssConflict
-}
-
-export type InvalidApplyDiagnostic = Diagnostic & {
- code: DiagnosticKind.InvalidApply
- className: DocumentClassName
-}
-
-export function isInvalidApplyDiagnostic(
- diagnostic: AugmentedDiagnostic
-): diagnostic is InvalidApplyDiagnostic {
- return diagnostic.code === DiagnosticKind.InvalidApply
-}
-
-export type InvalidScreenDiagnostic = Diagnostic & {
- code: DiagnosticKind.InvalidScreen
- suggestions: string[]
-}
-
-export function isInvalidScreenDiagnostic(
- diagnostic: AugmentedDiagnostic
-): diagnostic is InvalidScreenDiagnostic {
- return diagnostic.code === DiagnosticKind.InvalidScreen
-}
-
-export type InvalidVariantDiagnostic = Diagnostic & {
- code: DiagnosticKind.InvalidVariant
- suggestions: string[]
-}
-
-export function isInvalidVariantDiagnostic(
- diagnostic: AugmentedDiagnostic
-): diagnostic is InvalidVariantDiagnostic {
- return diagnostic.code === DiagnosticKind.InvalidVariant
-}
-
-export type InvalidConfigPathDiagnostic = Diagnostic & {
- code: DiagnosticKind.InvalidConfigPath
- suggestions: string[]
-}
-
-export function isInvalidConfigPathDiagnostic(
- diagnostic: AugmentedDiagnostic
-): diagnostic is InvalidConfigPathDiagnostic {
- return diagnostic.code === DiagnosticKind.InvalidConfigPath
-}
-
-export type InvalidTailwindDirectiveDiagnostic = Diagnostic & {
- code: DiagnosticKind.InvalidTailwindDirective
- suggestions: string[]
-}
-
-export function isInvalidTailwindDirectiveDiagnostic(
- diagnostic: AugmentedDiagnostic
-): diagnostic is InvalidTailwindDirectiveDiagnostic {
- return diagnostic.code === DiagnosticKind.InvalidTailwindDirective
-}
-
-export type AugmentedDiagnostic =
- | CssConflictDiagnostic
- | InvalidApplyDiagnostic
- | InvalidScreenDiagnostic
- | InvalidVariantDiagnostic
- | InvalidConfigPathDiagnostic
- | InvalidTailwindDirectiveDiagnostic
diff --git a/src/lsp/providers/hoverProvider.ts b/src/lsp/providers/hoverProvider.ts
index 2084ec42933cbf2cfc02ead3b476698727a2d89e..a9010a3142cb4e9700f63e3bd06426a144b9afa0 100644
--- a/src/lsp/providers/hoverProvider.ts
+++ b/src/lsp/providers/hoverProvider.ts
@@ -1,11 +1,10 @@
import { State } from '../util/state'
import { Hover, TextDocumentPositionParams } from 'vscode-languageserver'
+import { getClassNameParts } from '../util/getClassNameAtPosition'
import { stringifyCss, stringifyConfigValue } from '../util/stringify'
const dlv = require('dlv')
import { isCssContext } from '../util/css'
import { findClassNameAtPosition } from '../util/find'
-import { validateApply } from '../util/validateApply'
-import { getClassNameParts } from '../util/getClassNameAtPosition'
export function provideHover(
state: State,
@@ -81,13 +80,6 @@ if (className === null) return null
const parts = getClassNameParts(state, className.className)
if (!parts) return null
-
- if (isCssContext(state, doc, position)) {
- let validated = validateApply(state, parts)
- if (validated === null || validated.isApplyable === false) {
- return null
- }
- }
return {
contents: {
diff --git a/src/lsp/server.ts b/src/lsp/server.ts
index cc85ae4662a1e6cbc4a8af47df121dd7acdb8f31..b28b1bad9d226222f5d9e24472c9d8d698df6187 100644
--- a/src/lsp/server.ts
+++ b/src/lsp/server.ts
@@ -16,8 +16,6 @@ CompletionList,
Hover,
TextDocumentPositionParams,
DidChangeConfigurationNotification,
- CodeActionParams,
- CodeAction,
} from 'vscode-languageserver'
import getTailwindState from '../class-names/index'
import { State, Settings, EditorState } from './util/state'
@@ -28,48 +26,28 @@ } from './providers/completionProvider'
import { provideHover } from './providers/hoverProvider'
import { URI } from 'vscode-uri'
import { getDocumentSettings } from './util/getDocumentSettings'
-import {
- provideDiagnostics,
+
- * Licensed under the MIT License. See License.txt in the project root for license information.
/* --------------------------------------------------------------------------------------------
- clearAllDiagnostics,
-} from './providers/diagnostics/diagnosticsProvider'
- * Licensed under the MIT License. See License.txt in the project root for license information.
+ ProposedFeatures,
* ------------------------------------------------------------------------------------------ */
* Licensed under the MIT License. See License.txt in the project root for license information.
-
-
- * Licensed under the MIT License. See License.txt in the project root for license information.
import {
-let state: State = { enabled: false, emitter: createEmitter(connection) }
let documents = new TextDocuments()
let workspaceFolder: string | null
const defaultSettings: Settings = {
emmetCompletions: false,
includeLanguages: {},
- validate: true,
- lint: {
- cssConflict: 'warning',
- invalidApply: 'error',
- invalidScreen: 'error',
- invalidVariant: 'error',
- invalidConfigPath: 'error',
- invalidTailwindDirective: 'error',
- },
}
let globalSettings: Settings = defaultSettings
let documentSettings: Map = new Map()
documents.onDidOpen((event) => {
+ CodeActionParams,
-import {
})
documents.onDidClose((event) => {
documentSettings.delete(event.document.uri)
-})
-documents.onDidChangeContent((change) => {
- provideDiagnostics(state, change.document)
})
documents.listen(connection)
@@ -90,10 +68,6 @@ : {},
capabilities: {
configuration:
capabilities.workspace && !!capabilities.workspace.configuration,
- diagnosticRelatedInformation:
- capabilities.textDocument &&
- capabilities.textDocument.publishDiagnostics &&
- capabilities.textDocument.publishDiagnostics.relatedInformation,
},
}
@@ -103,12 +77,7 @@ {
// @ts-ignore
onChange: (newState: State): void => {
if (newState && !newState.error) {
- ProposedFeatures,
/* --------------------------------------------------------------------------------------------
- ...newState,
- enabled: true,
- emitter: state.emitter,
- editor: editorState,
}
connection.sendNotification('tailwindcss/configUpdated', [
state.configPath,
@@ -116,16 +85,10 @@ state.config,
state.plugins,
])
TextDocumentSyncKind,
- * Copyright (c) Microsoft Corporation. All rights reserved.
- TextDocumentSyncKind,
* Licensed under the MIT License. See License.txt in the project root for license information.
- ProposedFeatures,
/* --------------------------------------------------------------------------------------------
- enabled: false,
- emitter: state.emitter,
ProposedFeatures,
-
- }
+ createConnection,
if (newState && newState.error) {
const payload: {
message: string
@@ -141,8 +104,6 @@ }
connection.sendNotification('tailwindcss/configError', [payload])
}
CompletionItem,
- TextDocuments,
- CompletionItem,
ProposedFeatures,
// connection.sendNotification('tailwindcss/configUpdated', [null])
}
@@ -152,16 +113,11 @@ )
if (tailwindState) {
/* --------------------------------------------------------------------------------------------
-} from './providers/completionProvider'
- enabled: true,
- emitter: state.emitter,
- InitializeParams,
ProposedFeatures,
- ...tailwindState,
- }
+ TextDocuments,
} else {
/* --------------------------------------------------------------------------------------------
- clearAllDiagnostics,
+ state.config,
}
return {
@@ -189,7 +145,6 @@ typeof state.separator === 'undefined' ? ':' : state.separator,
],
},
hoverProvider: true,
- codeActionProvider: true,
},
}
}
@@ -221,8 +176,10 @@ (change.settings.tailwindCSS || defaultSettings)
)
}
+ state.editor.documents
+ CodeAction,
/* --------------------------------------------------------------------------------------------
- diagnosticRelatedInformation:
+ .forEach((doc) => getDocumentSettings(state, doc.uri))
})
connection.onCompletion(
@@ -243,13 +200,6 @@ connection.onHover(
(params: TextDocumentPositionParams): Hover => {
if (!state.enabled) return null
return provideHover(state, params)
- }
-)
-
-connection.onCodeAction(
- (params: CodeActionParams): Promise => {
- if (!state.enabled) return null
- return provideCodeActions(state, params)
}
)
diff --git a/src/lsp/util/absoluteRange.ts b/src/lsp/util/absoluteRange.ts
deleted file mode 100644
index 9250e4fb9ec9b13ff3124072808f2013ef5009a0..0000000000000000000000000000000000000000
--- a/src/lsp/util/absoluteRange.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Range } from 'vscode-languageserver'
-
-export function absoluteRange(range: Range, reference?: Range) {
- return {
- start: {
- line: (reference?.start.line || 0) + range.start.line,
- character:
- (range.end.line === 0 ? reference?.start.character || 0 : 0) +
- range.start.character,
- },
- end: {
- line: (reference?.start.line || 0) + range.end.line,
- character:
- (range.end.line === 0 ? reference?.start.character || 0 : 0) +
- range.end.character,
- },
- }
-}
diff --git a/src/lsp/util/closest.ts b/src/lsp/util/closest.ts
deleted file mode 100644
index ebdfacc270c2c5467d501b4ff4642aef04f6277e..0000000000000000000000000000000000000000
--- a/src/lsp/util/closest.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import sift from 'sift-string'
-
-export function closest(input: string, options: string[]): string | undefined {
- return options.concat([]).sort((a, b) => sift(input, a) - sift(input, b))[0]
-}
diff --git a/src/lsp/util/combinations.ts b/src/lsp/util/combinations.ts
deleted file mode 100644
index 2c9868b207b01b60cc0789b800058285257e187a..0000000000000000000000000000000000000000
--- a/src/lsp/util/combinations.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export function combinations(str: string): string[] {
- let fn = function (active: string, rest: string, a: string[]) {
- if (!active && !rest) return
- if (!rest) {
- a.push(active)
- } else {
- fn(active + rest[0], rest.slice(1), a)
- fn(active, rest.slice(1), a)
- }
- return a
- }
- return fn('', str, [])
-}
diff --git a/src/lsp/util/cssObjToAst.ts b/src/lsp/util/cssObjToAst.ts
deleted file mode 100644
index 42826f7526c514588519a63a8d2e6723a9ebfdd2..0000000000000000000000000000000000000000
--- a/src/lsp/util/cssObjToAst.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-This is a modified version of the postcss-js 'parse' function which accepts the
-postcss module as an argument. License below:
-
-The MIT License (MIT)
-
-Copyright 2015 Andrey Sitnik
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-var IMPORTANT = /\s*!important\s*$/i
-
-var unitless = {
- 'box-flex': true,
- 'box-flex-group': true,
- 'column-count': true,
- flex: true,
- 'flex-grow': true,
- 'flex-positive': true,
- 'flex-shrink': true,
- 'flex-negative': true,
- 'font-weight': true,
- 'line-clamp': true,
- 'line-height': true,
- opacity: true,
- order: true,
- orphans: true,
- 'tab-size': true,
- widows: true,
- 'z-index': true,
- zoom: true,
- 'fill-opacity': true,
- 'stroke-dashoffset': true,
- 'stroke-opacity': true,
- 'stroke-width': true,
-}
-
-function dashify(str) {
- return str
- .replace(/([A-Z])/g, '-$1')
- .replace(/^ms-/, '-ms-')
- .toLowerCase()
-}
-
-function decl(parent, name, value, postcss) {
- if (value === false || value === null) return
-
- name = dashify(name)
- if (typeof value === 'number') {
- if (value === 0 || unitless[name]) {
- value = value.toString()
- } else {
- value = value.toString() + 'px'
- }
- }
-
- if (name === 'css-float') name = 'float'
-
- if (IMPORTANT.test(value)) {
- value = value.replace(IMPORTANT, '')
- parent.push(postcss.decl({ prop: name, value: value, important: true }))
- } else {
- parent.push(postcss.decl({ prop: name, value: value }))
- }
-}
-
-function atRule(parent, parts, value, postcss) {
- var node = postcss.atRule({ name: parts[1], params: parts[3] || '' })
- if (typeof value === 'object') {
- node.nodes = []
- parse(value, node, postcss)
- }
- parent.push(node)
-}
-
-function parse(obj, parent, postcss) {
- var name, value, node, i
- for (name in obj) {
- if (obj.hasOwnProperty(name)) {
- value = obj[name]
- if (value === null || typeof value === 'undefined') {
- continue
- } else if (name[0] === '@') {
- var parts = name.match(/@([^\s]+)(\s+([\w\W]*)\s*)?/)
- if (Array.isArray(value)) {
- for (i = 0; i < value.length; i++) {
- atRule(parent, parts, value[i], postcss)
- }
- } else {
- atRule(parent, parts, value, postcss)
- }
- } else if (Array.isArray(value)) {
- for (i = 0; i < value.length; i++) {
- decl(parent, name, value[i], postcss)
- }
- } else if (typeof value === 'object') {
- node = postcss.rule({ selector: name })
- parse(value, node, postcss)
- parent.push(node)
- } else {
- decl(parent, name, value, postcss)
- }
- }
- }
-}
-
-export function cssObjToAst(obj, postcss) {
- var root = postcss.root()
- parse(obj, root, postcss)
- return root
-}
diff --git a/src/lsp/util/find.ts b/src/lsp/util/find.ts
index b642534d012dc3816516f0284de71b1ecbf31954..5eaef42ef1b5c41b8eeef529d00fb4109cd481bd 100644
--- a/src/lsp/util/find.ts
+++ b/src/lsp/util/find.ts
@@ -5,12 +5,10 @@ import { isCssContext, isCssDoc } from './css'
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
import { isWithinRange } from './isWithinRange'
import { isJsContext, isJsDoc } from './js'
-import { flatten } from '../../util/array'
import {
getClassAttributeLexer,
getComputedClassAttributeLexer,
} from './lexers'
-import { getLanguageBoundaries } from './getLanguageBoundaries'
export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
let match: RegExpMatchArray
@@ -29,87 +27,78 @@ }
return matches[matches.length - 1]
}
-export function getClassNamesInClassList({
- classList,
- range,
+import { isWithinRange } from './isWithinRange'
import lineColumn from 'line-column'
-import { TextDocument, Range, Position } from 'vscode-languageserver'
-}: DocumentClassList): DocumentClassName[] {
- const parts = classList.split(/(\s+)/)
-import lineColumn from 'line-column'
+import { isWithinRange } from './isWithinRange'
import { isCssContext, isCssDoc } from './css'
-import lineColumn from 'line-column'
+import { isWithinRange } from './isWithinRange'
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
-import lineColumn from 'line-column'
+import { isWithinRange } from './isWithinRange'
import { isWithinRange } from './isWithinRange'
-import lineColumn from 'line-column'
+import { isWithinRange } from './isWithinRange'
import { isJsContext, isJsDoc } from './js'
-import lineColumn from 'line-column'
+import { isWithinRange } from './isWithinRange'
import { flatten } from '../../util/array'
- const end = indexToPosition(classList, index + parts[i].length)
-import { isCssContext, isCssDoc } from './css'
+ return matches
-import { isCssContext, isCssDoc } from './css'
+ return matches
import { TextDocument, Range, Position } from 'vscode-languageserver'
-import { isCssContext, isCssDoc } from './css'
import { DocumentClassName, DocumentClassList, State } from './state'
- classList,
- range,
- important,
- },
- relativeRange: {
- start,
- end,
- },
- range: {
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
import { TextDocument, Range, Position } from 'vscode-languageserver'
+import { DocumentClassName, DocumentClassList, State } from './state'
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
import { DocumentClassName, DocumentClassList, State } from './state'
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+import { TextDocument, Range, Position } from 'vscode-languageserver'
import lineColumn from 'line-column'
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ return matches
import { isCssContext, isCssDoc } from './css'
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ return matches
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ return matches
import { isWithinRange } from './isWithinRange'
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ return matches
import { isJsContext, isJsDoc } from './js'
- character:
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ return matches
import { flatten } from '../../util/array'
- },
- },
-import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ return matches
import {
-import { isWithinRange } from './isWithinRange'
+}
-import { isWithinRange } from './isWithinRange'
+}
import { TextDocument, Range, Position } from 'vscode-languageserver'
- }
+ range: {
+import { TextDocument, Range, Position } from 'vscode-languageserver'
return names
}
+import { DocumentClassName, DocumentClassList, State } from './state'
import { TextDocument, Range, Position } from 'vscode-languageserver'
-import { isCssContext, isCssDoc } from './css'
-export function findClassNamesInRange(
doc: TextDocument,
- range?: Range,
+ (end.line === 0 ? range.start.character : 0) +
+import { TextDocument, Range, Position } from 'vscode-languageserver'
mode?: 'html' | 'css'
+import { TextDocument, Range, Position } from 'vscode-languageserver'
): DocumentClassName[] {
+import { TextDocument, Range, Position } from 'vscode-languageserver'
const classLists = findClassListsInRange(doc, range, mode)
- return flatten(classLists.map(getClassNamesInClassList))
}
+import { isCssContext, isCssDoc } from './css'
import { TextDocument, Range, Position } from 'vscode-languageserver'
+import { isWithinRange } from './isWithinRange'
import { isCssContext, isCssDoc } from './css'
+ (end.line === 0 ? range.start.character : 0) + end.character,
+ let match: RegExpMatchArray
import { isJsContext, isJsDoc } from './js'
+import { TextDocument, Range, Position } from 'vscode-languageserver'
state: State,
-import { isJsContext, isJsDoc } from './js'
+import { DocumentClassName, DocumentClassList, State } from './state'
import { DocumentClassName, DocumentClassList, State } from './state'
import { isWithinRange } from './isWithinRange'
-import { isJsContext, isJsDoc } from './js'
+ }
+}
import { isJsContext, isJsDoc } from './js'
+import { getLanguageBoundaries } from './getLanguageBoundaries'
import lineColumn from 'line-column'
-import { isWithinRange } from './isWithinRange'
+ return names
+}
import {
+ )
}
export function findClassListsInCssRange(
@@ -115,10 +106,7 @@ doc: TextDocument,
range?: Range
): DocumentClassList[] {
const text = doc.getText(range)
- const matches = findAll(
- /(@apply\s+)(?[^;}]+?)(?\s*!important)?\s*[;}]/g,
-import { flatten } from '../../util/array'
+export function findLast(re: RegExp, str: string): RegExpMatchArray {
- )
const globalStart: Position = range ? range.start : { line: 0, character: 0 }
return matches.map((match) => {
@@ -129,7 +117,6 @@ match.index + match[1].length + match.groups.classList.length
)
return {
classList: match.groups.classList,
- important: Boolean(match.groups.important),
range: {
start: {
line: globalStart.line + start.line,
@@ -148,7 +135,7 @@ }
export function findClassListsInHtmlRange(
doc: TextDocument,
- range?: Range
+ range: Range
): DocumentClassList[] {
const text = doc.getText(range)
const matches = findAll(/(?:\b|:)class(?:Name)?=['"`{]/g, text)
@@ -227,17 +214,16 @@ return {
classList: value.substr(beforeOffset, value.length + afterOffset),
range: {
start: {
- line: (range?.start.line || 0) + start.line,
+ line: range.start.line + start.line,
character:
- (end.line === 0 ? range?.start.character || 0 : 0) +
+ (end.line === 0 ? range.start.character : 0) +
start.character,
},
end: {
- line: (range?.start.line || 0) + end.line,
+ line: range.start.line + end.line,
character:
- let match: RegExpMatchArray
+}
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
- end.character,
},
},
}
@@ -251,8 +237,8 @@ }
export function findClassListsInRange(
doc: TextDocument,
- range?: Range,
+ range: Range,
- mode?: 'html' | 'css'
+ mode: 'html' | 'css'
): DocumentClassList[] {
if (mode === 'css') {
return findClassListsInCssRange(doc, range)
@@ -268,30 +254,94 @@ if (isCssDoc(state, doc)) {
return findClassListsInCssRange(doc)
}
-import { TextDocument, Range, Position } from 'vscode-languageserver'
+ if (isVueDoc(doc)) {
+ let text = doc.getText()
+ let blocks = findAll(
+ /<(?template|style|script)\b[^>]*>.*?(<\/\k>|$)/gis,
+ text
+import { flatten } from '../../util/array'
import { flatten } from '../../util/array'
import { DocumentClassName, DocumentClassList, State } from './state'
+ const end = indexToPosition(classList, index + parts[i].length)
+ let cssRanges: Range[] = []
+ const matches = findAll(re, str)
import { TextDocument, Range, Position } from 'vscode-languageserver'
-import { flatten } from '../../util/array'
+ let range = {
+ const matches = findAll(re, str)
import lineColumn from 'line-column'
+ end: indexToPosition(text, blocks[i].index + blocks[i][0].length),
import { TextDocument, Range, Position } from 'vscode-languageserver'
+ const parts = classList.split(/(\s+)/)
+import { DocumentClassName, DocumentClassList, State } from './state'
import { isCssContext, isCssDoc } from './css'
+import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ cssRanges.push(range)
+ } else {
+ htmlRanges.push(range)
import { TextDocument, Range, Position } from 'vscode-languageserver'
-import { flatten } from '../../util/array'
+ const parts = classList.split(/(\s+)/)
+ }
+import { DocumentClassName, DocumentClassList, State } from './state'
import { isCssContext, isCssDoc } from './css'
+import {
+ [],
+ if (matches.length === 0) {
import { TextDocument, Range, Position } from 'vscode-languageserver'
+ ...htmlRanges.map((range) => findClassListsInHtmlRange(doc, range)),
+ ...cssRanges.map((range) => findClassListsInCssRange(doc, range)),
+ ]
import { flatten } from '../../util/array'
+import { flatten } from '../../util/array'
+ }
+
+ if (matches.length === 0) {
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
+ let text = doc.getText()
+ let styleBlocks = findAll(/