separate out tailwindcss-language-service package
|
@ -1,3 +1 @@
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
|
||||||
*.vsix
|
|
||||||
|
|
105
README.md
|
@ -1,105 +0,0 @@
|
||||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/banner-dark.png" alt="" />
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
**[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.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### Autocomplete
|
|
||||||
|
|
||||||
Intelligent suggestions for class names, as well as [CSS functions and directives](https://tailwindcss.com/docs/functions-and-directives/).
|
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/autocomplete.png" alt="" />
|
|
||||||
|
|
||||||
### Linting
|
|
||||||
|
|
||||||
Highlights errors and potential bugs in both your CSS and your markup.
|
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/linting.png" alt="" />
|
|
||||||
|
|
||||||
### Hover Preview
|
|
||||||
|
|
||||||
See the complete CSS for a Tailwind class name by hovering over it.
|
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/hover.png" alt="" />
|
|
||||||
|
|
||||||
### CSS Syntax Highlighting
|
|
||||||
|
|
||||||
Provides syntax definitions so that Tailwind features are highlighted correctly.
|
|
||||||
|
|
||||||
## Settings
|
|
||||||
|
|
||||||
### `tailwindCSS.includeLanguages`
|
|
||||||
|
|
||||||
This setting allows you to add additional language support. The key of each entry is the new language ID and the value is any one of the extensions built-in languages, depending on how you want the new language to be treated (e.g. `html`, `css`, or `javascript`):
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tailwindCSS.includeLanguages": {
|
|
||||||
"plaintext": "html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tailwindCSS.emmetCompletions`
|
|
||||||
|
|
||||||
Enable completions when using [Emmet](https://emmet.io/)-style syntax, for example `div.bg-red-500.uppercase`. **Default: `false`**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tailwindCSS.emmetCompletions": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tailwindCSS.colorDecorators`
|
|
||||||
|
|
||||||
Controls whether the editor should render inline color decorators for Tailwind CSS classes and helper functions.
|
|
||||||
|
|
||||||
- `inherit`: Color decorators are rendered if `editor.colorDecorators` is enabled.
|
|
||||||
- `on`: Color decorators are rendered.
|
|
||||||
- `off`: Color decorators are not rendered.
|
|
||||||
|
|
||||||
### `tailwindCSS.validate`
|
|
||||||
|
|
||||||
Enable linting. Rules can be configured individually using the `tailwindcss.lint` settings:
|
|
||||||
|
|
||||||
- `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
|
|
||||||
|
|
||||||
#### `tailwindCSS.lint.invalidScreen`
|
|
||||||
|
|
||||||
Unknown screen name used with the [`@screen` directive](https://tailwindcss.com/docs/functions-and-directives/#screen). **Default: `error`**
|
|
||||||
|
|
||||||
#### `tailwindCSS.lint.invalidVariant`
|
|
||||||
|
|
||||||
Unknown variant name used with the [`@variants` directive](https://tailwindcss.com/docs/functions-and-directives/#variants). **Default: `error`**
|
|
||||||
|
|
||||||
#### `tailwindCSS.lint.invalidTailwindDirective`
|
|
||||||
|
|
||||||
Unknown value used with the [`@tailwind` directive](https://tailwindcss.com/docs/functions-and-directives/#tailwind). **Default: `error`**
|
|
||||||
|
|
||||||
#### `tailwindCSS.lint.invalidApply`
|
|
||||||
|
|
||||||
Unsupported use of the [`@apply` directive](https://tailwindcss.com/docs/functions-and-directives/#apply). **Default: `error`**
|
|
||||||
|
|
||||||
#### `tailwindCSS.lint.invalidConfigPath`
|
|
||||||
|
|
||||||
Unknown or invalid path used with the [`theme` helper](https://tailwindcss.com/docs/functions-and-directives/#theme). **Default: `error`**
|
|
||||||
|
|
||||||
#### `tailwindCSS.lint.cssConflict`
|
|
||||||
|
|
||||||
Class names on the same HTML element which apply the same CSS property or properties. **Default: `warning`**
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
If you’re having issues getting the IntelliSense features to activate, there are a few things you can check:
|
|
||||||
|
|
||||||
- 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).
|
|
||||||
- Ensure that the `tailwindcss` module is installed in your workspace, via `npm`, `yarn`, or `pnpm`. Tailwind CSS IntelliSense does not currently support Yarn Plug'n'Play.
|
|
||||||
- If you installed `tailwindcss` or created your config file while your project was already open in Visual Studio Code you may need to reload the editor. You can either restart VS Code entirely, or use the `Developer: Reload Window` command which can be found in the command palette.
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"version": "independent",
|
||||||
|
"npmClient": "npm"
|
||||||
|
}
|
|
@ -1,220 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "vscode-tailwindcss",
|
"private": true,
|
||||||
"displayName": "Tailwind CSS IntelliSense",
|
|
||||||
"description": "Intelligent Tailwind CSS tooling for VS Code",
|
|
||||||
"preview": true,
|
|
||||||
"author": "Brad Cornes <hello@bradley.dev>",
|
|
||||||
"license": "MIT",
|
|
||||||
"version": "0.4.3",
|
|
||||||
"homepage": "https://github.com/tailwindcss/intellisense",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/tailwindcss/intellisense/issues",
|
|
||||||
"email": "hello@bradley.dev"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/tailwindcss/intellisense.git"
|
|
||||||
},
|
|
||||||
"publisher": "bradlc",
|
|
||||||
"keywords": [
|
|
||||||
"tailwind",
|
|
||||||
"tailwindcss",
|
|
||||||
"css",
|
|
||||||
"intellisense",
|
|
||||||
"autocomplete",
|
|
||||||
"vscode"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"vscode": "^1.33.0"
|
|
||||||
},
|
|
||||||
"categories": [
|
|
||||||
"Linters",
|
|
||||||
"Other"
|
|
||||||
],
|
|
||||||
"galleryBanner": {
|
|
||||||
"color": "#f9fafb"
|
|
||||||
},
|
|
||||||
"icon": "media/icon.png",
|
|
||||||
"activationEvents": [
|
|
||||||
"workspaceContains:**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js"
|
|
||||||
],
|
|
||||||
"main": "dist/extension/index.js",
|
|
||||||
"contributes": {
|
|
||||||
"grammars": [
|
|
||||||
{
|
|
||||||
"scopeName": "tailwindcss.injection",
|
|
||||||
"path": "./syntaxes/tailwind.tmLanguage.json",
|
|
||||||
"injectTo": [
|
|
||||||
"source.css",
|
|
||||||
"source.css.scss",
|
|
||||||
"source.css.less",
|
|
||||||
"source.css.postcss",
|
|
||||||
"source.vue",
|
|
||||||
"source.svelte",
|
|
||||||
"text.html"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"configuration": {
|
|
||||||
"title": "Tailwind CSS IntelliSense",
|
|
||||||
"properties": {
|
|
||||||
"tailwindCSS.emmetCompletions": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"markdownDescription": "Enable class name completions when using Emmet-style syntax, for example `div.bg-red-500.uppercase`"
|
|
||||||
},
|
|
||||||
"tailwindCSS.includeLanguages": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"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.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,
|
|
||||||
"markdownDescription": "Enable linting. Rules can be configured individually using the `tailwindcss.lint.*` settings",
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} --watch -o dist/{{file.toString().replace(/^src\\//, '').replace(/\\.ts$/, '')}}\"",
|
"bootstrap": "lerna clean && lerna bootstrap --hoist"
|
||||||
"build": "glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} -o dist/{{file.toString().replace(/^src\\//, '').replace(/\\.ts$/, '')}}\"",
|
|
||||||
"minify": "glob-exec --foreach --parallel \"dist/**/*.js\" -- \"terser {{file}} --compress --mangle --output {{file.toString()}}\"",
|
|
||||||
"package": "vsce package",
|
|
||||||
"vscode:prepublish": "npm run clean && npm run build && npm run minify",
|
|
||||||
"clean": "rimraf dist",
|
|
||||||
"test": "jest"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ctrl/tinycolor": "^3.1.0",
|
"lerna": "^3.22.1"
|
||||||
"@types/debounce": "^1.2.0",
|
|
||||||
"@types/mocha": "^5.2.0",
|
|
||||||
"@types/moo": "^0.5.3",
|
|
||||||
"@types/node": "^13.9.3",
|
|
||||||
"@types/vscode": "^1.32.0",
|
|
||||||
"@zeit/ncc": "^0.22.0",
|
|
||||||
"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",
|
|
||||||
"esm": "^3.2.25",
|
|
||||||
"fast-glob": "^3.2.4",
|
|
||||||
"glob-exec": "^0.1.1",
|
|
||||||
"globalyzer": "^0.1.4",
|
|
||||||
"globrex": "^0.1.2",
|
|
||||||
"import-from": "^3.0.0",
|
|
||||||
"jest": "^25.5.4",
|
|
||||||
"line-column": "^1.0.2",
|
|
||||||
"mitt": "^1.2.0",
|
|
||||||
"mkdirp": "^1.0.3",
|
|
||||||
"moo": "^0.5.1",
|
|
||||||
"normalize-path": "^3.0.0",
|
|
||||||
"pkg-up": "^3.1.0",
|
|
||||||
"postcss": "^7.0.27",
|
|
||||||
"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",
|
|
||||||
"tslint": "^5.16.0",
|
|
||||||
"typescript": "^3.8.3",
|
|
||||||
"vsce": "^1.76.1",
|
|
||||||
"vscode-emmet-helper-bundled": "0.0.1",
|
|
||||||
"vscode-languageclient": "^5.2.1",
|
|
||||||
"vscode-languageserver": "^5.2.1",
|
|
||||||
"vscode-uri": "^2.1.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 235 KiB |
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 267 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
*.vsix
|
|
@ -0,0 +1,105 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/banner-dark.png" alt="" />
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
**[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.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Autocomplete
|
||||||
|
|
||||||
|
Intelligent suggestions for class names, as well as [CSS functions and directives](https://tailwindcss.com/docs/functions-and-directives/).
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/autocomplete.png" alt="" />
|
||||||
|
|
||||||
|
### Linting
|
||||||
|
|
||||||
|
Highlights errors and potential bugs in both your CSS and your markup.
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/linting.png" alt="" />
|
||||||
|
|
||||||
|
### Hover Preview
|
||||||
|
|
||||||
|
See the complete CSS for a Tailwind class name by hovering over it.
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/bradlc/vscode-tailwindcss/master/.github/hover.png" alt="" />
|
||||||
|
|
||||||
|
### CSS Syntax Highlighting
|
||||||
|
|
||||||
|
Provides syntax definitions so that Tailwind features are highlighted correctly.
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
### `tailwindCSS.includeLanguages`
|
||||||
|
|
||||||
|
This setting allows you to add additional language support. The key of each entry is the new language ID and the value is any one of the extensions built-in languages, depending on how you want the new language to be treated (e.g. `html`, `css`, or `javascript`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"tailwindCSS.includeLanguages": {
|
||||||
|
"plaintext": "html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `tailwindCSS.emmetCompletions`
|
||||||
|
|
||||||
|
Enable completions when using [Emmet](https://emmet.io/)-style syntax, for example `div.bg-red-500.uppercase`. **Default: `false`**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"tailwindCSS.emmetCompletions": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `tailwindCSS.colorDecorators`
|
||||||
|
|
||||||
|
Controls whether the editor should render inline color decorators for Tailwind CSS classes and helper functions.
|
||||||
|
|
||||||
|
- `inherit`: Color decorators are rendered if `editor.colorDecorators` is enabled.
|
||||||
|
- `on`: Color decorators are rendered.
|
||||||
|
- `off`: Color decorators are not rendered.
|
||||||
|
|
||||||
|
### `tailwindCSS.validate`
|
||||||
|
|
||||||
|
Enable linting. Rules can be configured individually using the `tailwindcss.lint` settings:
|
||||||
|
|
||||||
|
- `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
|
||||||
|
|
||||||
|
#### `tailwindCSS.lint.invalidScreen`
|
||||||
|
|
||||||
|
Unknown screen name used with the [`@screen` directive](https://tailwindcss.com/docs/functions-and-directives/#screen). **Default: `error`**
|
||||||
|
|
||||||
|
#### `tailwindCSS.lint.invalidVariant`
|
||||||
|
|
||||||
|
Unknown variant name used with the [`@variants` directive](https://tailwindcss.com/docs/functions-and-directives/#variants). **Default: `error`**
|
||||||
|
|
||||||
|
#### `tailwindCSS.lint.invalidTailwindDirective`
|
||||||
|
|
||||||
|
Unknown value used with the [`@tailwind` directive](https://tailwindcss.com/docs/functions-and-directives/#tailwind). **Default: `error`**
|
||||||
|
|
||||||
|
#### `tailwindCSS.lint.invalidApply`
|
||||||
|
|
||||||
|
Unsupported use of the [`@apply` directive](https://tailwindcss.com/docs/functions-and-directives/#apply). **Default: `error`**
|
||||||
|
|
||||||
|
#### `tailwindCSS.lint.invalidConfigPath`
|
||||||
|
|
||||||
|
Unknown or invalid path used with the [`theme` helper](https://tailwindcss.com/docs/functions-and-directives/#theme). **Default: `error`**
|
||||||
|
|
||||||
|
#### `tailwindCSS.lint.cssConflict`
|
||||||
|
|
||||||
|
Class names on the same HTML element which apply the same CSS property or properties. **Default: `warning`**
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If you’re having issues getting the IntelliSense features to activate, there are a few things you can check:
|
||||||
|
|
||||||
|
- 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).
|
||||||
|
- Ensure that the `tailwindcss` module is installed in your workspace, via `npm`, `yarn`, or `pnpm`. Tailwind CSS IntelliSense does not currently support Yarn Plug'n'Play.
|
||||||
|
- If you installed `tailwindcss` or created your config file while your project was already open in Visual Studio Code you may need to reload the editor. You can either restart VS Code entirely, or use the `Developer: Reload Window` command which can be found in the command palette.
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "vscode-tailwindcss",
|
||||||
|
"version": "0.4.3",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mitt": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw=="
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"version": "3.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||||
|
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
{
|
||||||
|
"name": "vscode-tailwindcss",
|
||||||
|
"displayName": "Tailwind CSS IntelliSense",
|
||||||
|
"description": "Intelligent Tailwind CSS tooling for VS Code",
|
||||||
|
"preview": true,
|
||||||
|
"author": "Brad Cornes <hello@bradley.dev>",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "0.4.3",
|
||||||
|
"homepage": "https://github.com/tailwindcss/intellisense",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/tailwindcss/intellisense/issues",
|
||||||
|
"email": "hello@bradley.dev"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/tailwindcss/intellisense.git"
|
||||||
|
},
|
||||||
|
"publisher": "bradlc",
|
||||||
|
"keywords": [
|
||||||
|
"tailwind",
|
||||||
|
"tailwindcss",
|
||||||
|
"css",
|
||||||
|
"intellisense",
|
||||||
|
"autocomplete",
|
||||||
|
"vscode"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.33.0"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
"Linters",
|
||||||
|
"Other"
|
||||||
|
],
|
||||||
|
"galleryBanner": {
|
||||||
|
"color": "#f9fafb"
|
||||||
|
},
|
||||||
|
"icon": "media/icon.png",
|
||||||
|
"activationEvents": [
|
||||||
|
"workspaceContains:**/{tailwind,tailwind.config,tailwind-config,.tailwindrc}.js"
|
||||||
|
],
|
||||||
|
"main": "dist/extension/index.js",
|
||||||
|
"contributes": {
|
||||||
|
"grammars": [
|
||||||
|
{
|
||||||
|
"scopeName": "tailwindcss.injection",
|
||||||
|
"path": "./syntaxes/tailwind.tmLanguage.json",
|
||||||
|
"injectTo": [
|
||||||
|
"source.css",
|
||||||
|
"source.css.scss",
|
||||||
|
"source.css.less",
|
||||||
|
"source.css.postcss",
|
||||||
|
"source.vue",
|
||||||
|
"source.svelte",
|
||||||
|
"text.html"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration": {
|
||||||
|
"title": "Tailwind CSS IntelliSense",
|
||||||
|
"properties": {
|
||||||
|
"tailwindCSS.emmetCompletions": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"markdownDescription": "Enable class name completions when using Emmet-style syntax, for example `div.bg-red-500.uppercase`"
|
||||||
|
},
|
||||||
|
"tailwindCSS.includeLanguages": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"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.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,
|
||||||
|
"markdownDescription": "Enable linting. Rules can be configured individually using the `tailwindcss.lint.*` settings",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} --watch -o dist/{{file.toString().replace(/^src\\//, '').replace(/\\.ts$/, '')}}\"",
|
||||||
|
"build": "glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} -o dist/{{file.toString().replace(/^src\\//, '').replace(/\\.ts$/, '')}}\"",
|
||||||
|
"minify": "glob-exec --foreach --parallel \"dist/**/*.js\" -- \"terser {{file}} --compress --mangle --output {{file.toString()}}\"",
|
||||||
|
"package": "vsce package",
|
||||||
|
"vscode:prepublish": "npm run clean && npm run build && npm run minify",
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/debounce": "^1.2.0",
|
||||||
|
"@types/mocha": "^5.2.0",
|
||||||
|
"@types/node": "^13.9.3",
|
||||||
|
"@types/vscode": "^1.32.0",
|
||||||
|
"@zeit/ncc": "^0.22.0",
|
||||||
|
"callsite": "^1.0.0",
|
||||||
|
"chokidar": "^3.3.1",
|
||||||
|
"debounce": "^1.2.0",
|
||||||
|
"dlv": "^1.1.3",
|
||||||
|
"dset": "^2.0.1",
|
||||||
|
"esm": "^3.2.25",
|
||||||
|
"fast-glob": "^3.2.4",
|
||||||
|
"glob-exec": "^0.1.1",
|
||||||
|
"import-from": "^3.0.0",
|
||||||
|
"jest": "^25.5.4",
|
||||||
|
"mitt": "^1.2.0",
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"pkg-up": "^3.1.0",
|
||||||
|
"postcss": "^7.0.27",
|
||||||
|
"postcss-selector-parser": "^6.0.2",
|
||||||
|
"resolve-from": "^5.0.0",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"stack-trace": "0.0.10",
|
||||||
|
"tailwindcss-language-service": "0.0.1",
|
||||||
|
"terser": "^4.6.12",
|
||||||
|
"tiny-invariant": "^1.1.0",
|
||||||
|
"tslint": "^5.16.0",
|
||||||
|
"typescript": "^3.8.3",
|
||||||
|
"vsce": "^1.76.1",
|
||||||
|
"vscode-languageclient": "^5.2.1",
|
||||||
|
"vscode-languageserver": "^5.2.1",
|
||||||
|
"vscode-uri": "^2.1.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { TextDocument } from 'vscode-languageserver'
|
||||||
|
import { State } from '../../util/state'
|
||||||
|
import { doValidate } from 'tailwindcss-language-service'
|
||||||
|
|
||||||
|
export async function provideDiagnostics(state: State, document: TextDocument) {
|
||||||
|
state.editor.connection.sendDiagnostics({
|
||||||
|
uri: document.uri,
|
||||||
|
diagnostics: await doValidate(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)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { onMessage } from '../notifications'
|
||||||
|
import { State } from '../util/state'
|
||||||
|
import { getDocumentColors } from 'tailwindcss-language-service'
|
||||||
|
|
||||||
|
export function registerDocumentColorProvider(state: State) {
|
||||||
|
onMessage(
|
||||||
|
state.editor.connection,
|
||||||
|
'getDocumentColors',
|
||||||
|
async ({ document }) => {
|
||||||
|
let doc = state.editor.documents.get(document)
|
||||||
|
if (!doc) return { colors: [] }
|
||||||
|
|
||||||
|
return { colors: getDocumentColors(state, doc) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
|
@ -20,12 +20,13 @@ import {
|
||||||
CodeAction,
|
CodeAction,
|
||||||
} from 'vscode-languageserver'
|
} from 'vscode-languageserver'
|
||||||
import getTailwindState from '../class-names/index'
|
import getTailwindState from '../class-names/index'
|
||||||
import { State, Settings, EditorState } from './util/state'
|
import { State, Settings, EditorState } from 'tailwindcss-language-service'
|
||||||
import {
|
import {
|
||||||
provideCompletions,
|
|
||||||
resolveCompletionItem,
|
resolveCompletionItem,
|
||||||
} from './providers/completionProvider'
|
doComplete,
|
||||||
import { provideHover } from './providers/hoverProvider'
|
doHover,
|
||||||
|
doCodeActions,
|
||||||
|
} from 'tailwindcss-language-service'
|
||||||
import { URI } from 'vscode-uri'
|
import { URI } from 'vscode-uri'
|
||||||
import { getDocumentSettings } from './util/getDocumentSettings'
|
import { getDocumentSettings } from './util/getDocumentSettings'
|
||||||
import {
|
import {
|
||||||
|
@ -34,7 +35,6 @@ import {
|
||||||
clearAllDiagnostics,
|
clearAllDiagnostics,
|
||||||
} from './providers/diagnostics/diagnosticsProvider'
|
} from './providers/diagnostics/diagnosticsProvider'
|
||||||
import { createEmitter } from '../lib/emitter'
|
import { createEmitter } from '../lib/emitter'
|
||||||
import { provideCodeActions } from './providers/codeActions/codeActionProvider'
|
|
||||||
import { registerDocumentColorProvider } from './providers/documentColorProvider'
|
import { registerDocumentColorProvider } from './providers/documentColorProvider'
|
||||||
|
|
||||||
let connection = createConnection(ProposedFeatures.all)
|
let connection = createConnection(ProposedFeatures.all)
|
||||||
|
@ -202,7 +202,9 @@ connection.onDidChangeConfiguration((change) => {
|
||||||
connection.onCompletion(
|
connection.onCompletion(
|
||||||
(params: CompletionParams): Promise<CompletionList> => {
|
(params: CompletionParams): Promise<CompletionList> => {
|
||||||
if (!state.enabled) return null
|
if (!state.enabled) return null
|
||||||
return provideCompletions(state, params)
|
let document = state.editor.documents.get(params.textDocument.uri)
|
||||||
|
if (!document) return null
|
||||||
|
return doComplete(state, document, params.position)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -216,14 +218,16 @@ connection.onCompletionResolve(
|
||||||
connection.onHover(
|
connection.onHover(
|
||||||
(params: TextDocumentPositionParams): Hover => {
|
(params: TextDocumentPositionParams): Hover => {
|
||||||
if (!state.enabled) return null
|
if (!state.enabled) return null
|
||||||
return provideHover(state, params)
|
let document = state.editor.documents.get(params.textDocument.uri)
|
||||||
|
if (!document) return null
|
||||||
|
return doHover(state, document, params.position)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
connection.onCodeAction(
|
connection.onCodeAction(
|
||||||
(params: CodeActionParams): Promise<CodeAction[]> => {
|
(params: CodeActionParams): Promise<CodeAction[]> => {
|
||||||
if (!state.enabled) return null
|
if (!state.enabled) return null
|
||||||
return provideCodeActions(state, params)
|
return doCodeActions(state, params)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from 'tailwindcss-language-service'
|
|
@ -2,11 +2,11 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"rootDir": "src",
|
"rootDir": "../",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src", "../tailwindcss-language-service"]
|
||||||
}
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
/node_modules
|
||||||
|
/dist
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"name": "tailwindcss-language-service",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"typings": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"src",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"start": "tsdx watch",
|
||||||
|
"build": "tsdx build",
|
||||||
|
"test": "tsdx test",
|
||||||
|
"lint": "tsdx lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ctrl/tinycolor": "^3.1.4",
|
||||||
|
"@types/moo": "^0.5.3",
|
||||||
|
"css.escape": "^1.5.1",
|
||||||
|
"detect-indent": "^6.0.0",
|
||||||
|
"dlv": "^1.1.3",
|
||||||
|
"line-column": "^1.0.2",
|
||||||
|
"mitt": "^2.1.0",
|
||||||
|
"moo": "^0.5.1",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"sift-string": "^0.0.2",
|
||||||
|
"tsdx": "^0.13.3",
|
||||||
|
"tslib": "^2.0.1",
|
||||||
|
"typescript": "^4.0.2",
|
||||||
|
"vscode-emmet-helper-bundled": "^0.0.1",
|
||||||
|
"vscode-languageclient": "^5.2.1",
|
||||||
|
"vscode-languageserver": "^5.2.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { CodeAction, CodeActionParams } from 'vscode-languageserver'
|
import { CodeAction, CodeActionParams } from 'vscode-languageserver'
|
||||||
import { State } from '../../util/state'
|
import { State } from '../util/state'
|
||||||
import { getDiagnostics } from '../diagnostics/diagnosticsProvider'
|
import { doValidate } from '../diagnostics/diagnosticsProvider'
|
||||||
import { rangesEqual } from '../../util/rangesEqual'
|
import { rangesEqual } from '../util/rangesEqual'
|
||||||
import {
|
import {
|
||||||
DiagnosticKind,
|
DiagnosticKind,
|
||||||
isInvalidApplyDiagnostic,
|
isInvalidApplyDiagnostic,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
||||||
isInvalidScreenDiagnostic,
|
isInvalidScreenDiagnostic,
|
||||||
isInvalidVariantDiagnostic,
|
isInvalidVariantDiagnostic,
|
||||||
} from '../diagnostics/types'
|
} from '../diagnostics/types'
|
||||||
import { flatten, dedupeBy } from '../../../util/array'
|
import { flatten, dedupeBy } from '../util/array'
|
||||||
import { provideCssConflictCodeActions } from './provideCssConflictCodeActions'
|
import { provideCssConflictCodeActions } from './provideCssConflictCodeActions'
|
||||||
import { provideInvalidApplyCodeActions } from './provideInvalidApplyCodeActions'
|
import { provideInvalidApplyCodeActions } from './provideInvalidApplyCodeActions'
|
||||||
import { provideSuggestionCodeActions } from './provideSuggestionCodeActions'
|
import { provideSuggestionCodeActions } from './provideSuggestionCodeActions'
|
||||||
|
@ -23,7 +23,7 @@ async function getDiagnosticsFromCodeActionParams(
|
||||||
only?: DiagnosticKind[]
|
only?: DiagnosticKind[]
|
||||||
): Promise<AugmentedDiagnostic[]> {
|
): Promise<AugmentedDiagnostic[]> {
|
||||||
let document = state.editor.documents.get(params.textDocument.uri)
|
let document = state.editor.documents.get(params.textDocument.uri)
|
||||||
let diagnostics = await getDiagnostics(state, document, only)
|
let diagnostics = await doValidate(state, document, only)
|
||||||
|
|
||||||
return params.context.diagnostics
|
return params.context.diagnostics
|
||||||
.map((diagnostic) => {
|
.map((diagnostic) => {
|
||||||
|
@ -38,7 +38,7 @@ async function getDiagnosticsFromCodeActionParams(
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function provideCodeActions(
|
export async function doCodeActions(
|
||||||
state: State,
|
state: State,
|
||||||
params: CodeActionParams
|
params: CodeActionParams
|
||||||
): Promise<CodeAction[]> {
|
): Promise<CodeAction[]> {
|
|
@ -1,12 +1,12 @@
|
||||||
import { State } from '../../util/state'
|
import { State } from '../util/state'
|
||||||
import {
|
import {
|
||||||
CodeActionParams,
|
CodeActionParams,
|
||||||
CodeAction,
|
CodeAction,
|
||||||
CodeActionKind,
|
CodeActionKind,
|
||||||
} from 'vscode-languageserver'
|
} from 'vscode-languageserver'
|
||||||
import { CssConflictDiagnostic } from '../diagnostics/types'
|
import { CssConflictDiagnostic } from '../diagnostics/types'
|
||||||
import { joinWithAnd } from '../../util/joinWithAnd'
|
import { joinWithAnd } from '../util/joinWithAnd'
|
||||||
import { removeRangesFromString } from '../../util/removeRangesFromString'
|
import { removeRangesFromString } from '../util/removeRangesFromString'
|
||||||
|
|
||||||
export async function provideCssConflictCodeActions(
|
export async function provideCssConflictCodeActions(
|
||||||
_state: State,
|
_state: State,
|
|
@ -5,24 +5,24 @@ import {
|
||||||
TextEdit,
|
TextEdit,
|
||||||
Range,
|
Range,
|
||||||
} from 'vscode-languageserver'
|
} from 'vscode-languageserver'
|
||||||
import { State } from '../../util/state'
|
import { State } from '../util/state'
|
||||||
import { InvalidApplyDiagnostic } from '../diagnostics/types'
|
import { InvalidApplyDiagnostic } from '../diagnostics/types'
|
||||||
import { getClassNameParts } from '../../util/getClassNameAtPosition'
|
import { isCssDoc } from '../util/css'
|
||||||
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
|
import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
|
||||||
import { isCssDoc } from '../../util/css'
|
import { getClassNameMeta } from '../util/getClassNameMeta'
|
||||||
import { isWithinRange } from '../../util/isWithinRange'
|
import { getClassNameParts } from '../util/getClassNameAtPosition'
|
||||||
|
import { validateApply } from '../util/validateApply'
|
||||||
|
import { isWithinRange } from '../util/isWithinRange'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
import type { Root, NodeSource } from 'postcss'
|
import type { Root, NodeSource } from 'postcss'
|
||||||
import { absoluteRange } from '../../util/absoluteRange'
|
import { absoluteRange } from '../util/absoluteRange'
|
||||||
import { removeRangesFromString } from '../../util/removeRangesFromString'
|
import { removeRangesFromString } from '../util/removeRangesFromString'
|
||||||
import detectIndent from 'detect-indent'
|
import detectIndent from 'detect-indent'
|
||||||
import isObject from '../../../util/isObject'
|
import isObject from '../util/isObject'
|
||||||
import { cssObjToAst } from '../../util/cssObjToAst'
|
import { cssObjToAst } from '../util/cssObjToAst'
|
||||||
import dset from 'dset'
|
import dset from 'dset'
|
||||||
import selectorParser from 'postcss-selector-parser'
|
import selectorParser from 'postcss-selector-parser'
|
||||||
import { flatten } from '../../../util/array'
|
import { flatten } from '../util/array'
|
||||||
import { getClassNameMeta } from '../../util/getClassNameMeta'
|
|
||||||
import { validateApply } from '../../util/validateApply'
|
|
||||||
|
|
||||||
export async function provideInvalidApplyCodeActions(
|
export async function provideInvalidApplyCodeActions(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -129,6 +129,8 @@ export async function provideInvalidApplyCodeActions(
|
||||||
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
|
@ -1,4 +1,4 @@
|
||||||
import { State } from '../../util/state'
|
import { State } from '../util/state'
|
||||||
import {
|
import {
|
||||||
CodeActionParams,
|
CodeActionParams,
|
||||||
CodeAction,
|
CodeAction,
|
|
@ -1,35 +1,36 @@
|
||||||
import { State } from '../util/state'
|
import { State } from './util/state'
|
||||||
import {
|
import type {
|
||||||
CompletionItem,
|
CompletionItem,
|
||||||
CompletionItemKind,
|
CompletionItemKind,
|
||||||
CompletionParams,
|
|
||||||
Range,
|
Range,
|
||||||
MarkupKind,
|
MarkupKind,
|
||||||
CompletionList,
|
CompletionList,
|
||||||
|
TextDocument,
|
||||||
|
Position,
|
||||||
} from 'vscode-languageserver'
|
} from 'vscode-languageserver'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
import removeMeta from '../util/removeMeta'
|
import removeMeta from './util/removeMeta'
|
||||||
import { getColor, getColorFromValue } from '../util/color'
|
import { getColor, getColorFromValue } from './util/color'
|
||||||
import { isHtmlContext } from '../util/html'
|
import { isHtmlContext } from './util/html'
|
||||||
import { isCssContext } from '../util/css'
|
import { isCssContext } from './util/css'
|
||||||
import { findLast } from '../util/find'
|
import { findLast } from './util/find'
|
||||||
import { stringifyConfigValue, stringifyCss } from '../util/stringify'
|
import { stringifyConfigValue, stringifyCss } from './util/stringify'
|
||||||
import { stringifyScreen, Screen } from '../util/screens'
|
import { stringifyScreen, Screen } from './util/screens'
|
||||||
import isObject from '../../util/isObject'
|
import isObject from './util/isObject'
|
||||||
import * as emmetHelper from 'vscode-emmet-helper-bundled'
|
import * as emmetHelper from 'vscode-emmet-helper-bundled'
|
||||||
import { isValidLocationForEmmetAbbreviation } from '../util/isValidLocationForEmmetAbbreviation'
|
import { isValidLocationForEmmetAbbreviation } from './util/isValidLocationForEmmetAbbreviation'
|
||||||
import { getDocumentSettings } from '../util/getDocumentSettings'
|
import { getDocumentSettings } from './util/getDocumentSettings'
|
||||||
import { isJsContext } from '../util/js'
|
import { isJsContext } from './util/js'
|
||||||
import { naturalExpand } from '../util/naturalExpand'
|
import { naturalExpand } from './util/naturalExpand'
|
||||||
import semver from 'semver'
|
import semver from 'semver'
|
||||||
import { docsUrl } from '../util/docsUrl'
|
import { docsUrl } from './util/docsUrl'
|
||||||
import { ensureArray } from '../../util/array'
|
import { ensureArray } from './util/array'
|
||||||
import {
|
import {
|
||||||
getClassAttributeLexer,
|
getClassAttributeLexer,
|
||||||
getComputedClassAttributeLexer,
|
getComputedClassAttributeLexer,
|
||||||
} from '../util/lexers'
|
} from './util/lexers'
|
||||||
import { validateApply } from '../util/validateApply'
|
import { validateApply } from './util/validateApply'
|
||||||
import { flagEnabled } from '../util/flagEnabled'
|
import { flagEnabled } from './util/flagEnabled'
|
||||||
|
|
||||||
function completionsFromClassList(
|
function completionsFromClassList(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -78,19 +79,19 @@ function completionsFromClassList(
|
||||||
items: Object.keys(isSubset ? subset : state.classNames.classNames)
|
items: Object.keys(isSubset ? subset : state.classNames.classNames)
|
||||||
.map((className, index) => {
|
.map((className, index) => {
|
||||||
let label = className
|
let label = className
|
||||||
let kind: CompletionItemKind = CompletionItemKind.Constant
|
let kind: CompletionItemKind = 21
|
||||||
let documentation: string = null
|
let documentation: string = null
|
||||||
let command: any
|
let command: any
|
||||||
let sortText = naturalExpand(index)
|
let sortText = naturalExpand(index)
|
||||||
if (isContextItem(state, [...subsetKey, className])) {
|
if (isContextItem(state, [...subsetKey, className])) {
|
||||||
kind = CompletionItemKind.Module
|
kind = 9
|
||||||
command = { title: '', command: 'editor.action.triggerSuggest' }
|
command = { title: '', command: 'editor.action.triggerSuggest' }
|
||||||
label += sep
|
label += sep
|
||||||
sortText = '-' + sortText // move to top
|
sortText = '-' + sortText // move to top
|
||||||
} else {
|
} else {
|
||||||
const color = getColor(state, [className])
|
const color = getColor(state, [className])
|
||||||
if (color !== null) {
|
if (color !== null) {
|
||||||
kind = CompletionItemKind.Color
|
kind = 16
|
||||||
if (typeof color !== 'string' && color.a !== 0) {
|
if (typeof color !== 'string' && color.a !== 0) {
|
||||||
documentation = color.toRgbString()
|
documentation = color.toRgbString()
|
||||||
}
|
}
|
||||||
|
@ -122,10 +123,10 @@ function completionsFromClassList(
|
||||||
|
|
||||||
function provideClassAttributeCompletions(
|
function provideClassAttributeCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ context, position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
let str = document.getText({
|
||||||
let str = doc.getText({
|
|
||||||
start: { line: Math.max(position.line - 10, 0), character: 0 },
|
start: { line: Math.max(position.line - 10, 0), character: 0 },
|
||||||
end: position,
|
end: position,
|
||||||
})
|
})
|
||||||
|
@ -170,10 +171,10 @@ function provideClassAttributeCompletions(
|
||||||
|
|
||||||
function provideAtApplyCompletions(
|
function provideAtApplyCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ context, position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
let str = document.getText({
|
||||||
let str = doc.getText({
|
|
||||||
start: { line: Math.max(position.line - 30, 0), character: 0 },
|
start: { line: Math.max(position.line - 30, 0), character: 0 },
|
||||||
end: position,
|
end: position,
|
||||||
})
|
})
|
||||||
|
@ -197,7 +198,7 @@ function provideAtApplyCompletions(
|
||||||
end: position,
|
end: position,
|
||||||
},
|
},
|
||||||
(item) => {
|
(item) => {
|
||||||
if (item.kind === CompletionItemKind.Module) {
|
if (item.kind === 9) {
|
||||||
return flagEnabled(state, 'applyComplexClasses')
|
return flagEnabled(state, 'applyComplexClasses')
|
||||||
}
|
}
|
||||||
let validated = validateApply(state, item.data)
|
let validated = validateApply(state, item.data)
|
||||||
|
@ -208,19 +209,18 @@ function provideAtApplyCompletions(
|
||||||
|
|
||||||
function provideClassNameCompletions(
|
function provideClassNameCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
params: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(params.textDocument.uri)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isHtmlContext(state, doc, params.position) ||
|
isHtmlContext(state, document, position) ||
|
||||||
isJsContext(state, doc, params.position)
|
isJsContext(state, document, position)
|
||||||
) {
|
) {
|
||||||
return provideClassAttributeCompletions(state, params)
|
return provideClassAttributeCompletions(state, document, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCssContext(state, doc, params.position)) {
|
if (isCssContext(state, document, position)) {
|
||||||
return provideAtApplyCompletions(state, params)
|
return provideAtApplyCompletions(state, document, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
@ -228,15 +228,14 @@ function provideClassNameCompletions(
|
||||||
|
|
||||||
function provideCssHelperCompletions(
|
function provideCssHelperCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
if (!isCssContext(state, document, position)) {
|
||||||
|
|
||||||
if (!isCssContext(state, doc, position)) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = doc.getText({
|
let text = document.getText({
|
||||||
start: { line: position.line, character: 0 },
|
start: { line: position.line, character: 0 },
|
||||||
// read one extra character so we can see if it's a ] later
|
// read one extra character so we can see if it's a ] later
|
||||||
end: { line: position.line, character: position.character + 1 },
|
end: { line: position.line, character: position.character + 1 },
|
||||||
|
@ -303,11 +302,7 @@ function provideCssHelperCompletions(
|
||||||
label: item,
|
label: item,
|
||||||
filterText: `${replaceDot ? '.' : ''}${item}`,
|
filterText: `${replaceDot ? '.' : ''}${item}`,
|
||||||
sortText: naturalExpand(index),
|
sortText: naturalExpand(index),
|
||||||
kind: color
|
kind: color ? 16 : isObject(obj[item]) ? 9 : 10,
|
||||||
? CompletionItemKind.Color
|
|
||||||
: isObject(obj[item])
|
|
||||||
? CompletionItemKind.Module
|
|
||||||
: CompletionItemKind.Property,
|
|
||||||
// VS Code bug causes '0' to not display in some cases
|
// VS Code bug causes '0' to not display in some cases
|
||||||
detail: detail === '0' ? '0 ' : detail,
|
detail: detail === '0' ? '0 ' : detail,
|
||||||
documentation: color,
|
documentation: color,
|
||||||
|
@ -336,15 +331,14 @@ function provideCssHelperCompletions(
|
||||||
// TODO: vary docs links based on Tailwind version
|
// TODO: vary docs links based on Tailwind version
|
||||||
function provideTailwindDirectiveCompletions(
|
function provideTailwindDirectiveCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
if (!isCssContext(state, document, position)) {
|
||||||
|
|
||||||
if (!isCssContext(state, doc, position)) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = doc.getText({
|
let text = document.getText({
|
||||||
start: { line: position.line, character: 0 },
|
start: { line: position.line, character: 0 },
|
||||||
end: position,
|
end: position,
|
||||||
})
|
})
|
||||||
|
@ -360,7 +354,7 @@ function provideTailwindDirectiveCompletions(
|
||||||
? {
|
? {
|
||||||
label: 'base',
|
label: 'base',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `This injects Tailwind’s base styles and any base styles registered by plugins.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `This injects Tailwind’s base styles and any base styles registered by plugins.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#tailwind'
|
'functions-and-directives/#tailwind'
|
||||||
|
@ -370,7 +364,7 @@ function provideTailwindDirectiveCompletions(
|
||||||
: {
|
: {
|
||||||
label: 'preflight',
|
label: 'preflight',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `This injects Tailwind’s base styles, which is a combination of Normalize.css and some additional base styles.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `This injects Tailwind’s base styles, which is a combination of Normalize.css and some additional base styles.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#tailwind'
|
'functions-and-directives/#tailwind'
|
||||||
|
@ -380,7 +374,7 @@ function provideTailwindDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: 'components',
|
label: 'components',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `This injects Tailwind’s component classes and any component classes registered by plugins.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `This injects Tailwind’s component classes and any component classes registered by plugins.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#tailwind'
|
'functions-and-directives/#tailwind'
|
||||||
|
@ -390,7 +384,7 @@ function provideTailwindDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: 'utilities',
|
label: 'utilities',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `This injects Tailwind’s utility classes and any utility classes registered by plugins.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `This injects Tailwind’s utility classes and any utility classes registered by plugins.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#tailwind'
|
'functions-and-directives/#tailwind'
|
||||||
|
@ -400,7 +394,7 @@ function provideTailwindDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: 'screens',
|
label: 'screens',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `Use this directive to control where Tailwind injects the responsive variations of each utility.\n\nIf omitted, Tailwind will append these classes to the very end of your stylesheet by default.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `Use this directive to control where Tailwind injects the responsive variations of each utility.\n\nIf omitted, Tailwind will append these classes to the very end of your stylesheet by default.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#tailwind'
|
'functions-and-directives/#tailwind'
|
||||||
|
@ -409,7 +403,7 @@ function provideTailwindDirectiveCompletions(
|
||||||
},
|
},
|
||||||
].map((item) => ({
|
].map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
kind: CompletionItemKind.Constant,
|
kind: 21,
|
||||||
data: '@tailwind',
|
data: '@tailwind',
|
||||||
textEdit: {
|
textEdit: {
|
||||||
newText: item.label,
|
newText: item.label,
|
||||||
|
@ -427,15 +421,14 @@ function provideTailwindDirectiveCompletions(
|
||||||
|
|
||||||
function provideVariantsDirectiveCompletions(
|
function provideVariantsDirectiveCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
if (!isCssContext(state, document, position)) {
|
||||||
|
|
||||||
if (!isCssContext(state, doc, position)) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = doc.getText({
|
let text = document.getText({
|
||||||
start: { line: position.line, character: 0 },
|
start: { line: position.line, character: 0 },
|
||||||
end: position,
|
end: position,
|
||||||
})
|
})
|
||||||
|
@ -457,7 +450,7 @@ function provideVariantsDirectiveCompletions(
|
||||||
.map((variant) => ({
|
.map((variant) => ({
|
||||||
// TODO: detail
|
// TODO: detail
|
||||||
label: variant,
|
label: variant,
|
||||||
kind: CompletionItemKind.Constant,
|
kind: 21,
|
||||||
data: 'variant',
|
data: 'variant',
|
||||||
textEdit: {
|
textEdit: {
|
||||||
newText: variant,
|
newText: variant,
|
||||||
|
@ -475,15 +468,14 @@ function provideVariantsDirectiveCompletions(
|
||||||
|
|
||||||
function provideScreenDirectiveCompletions(
|
function provideScreenDirectiveCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
if (!isCssContext(state, document, position)) {
|
||||||
|
|
||||||
if (!isCssContext(state, doc, position)) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = doc.getText({
|
let text = document.getText({
|
||||||
start: { line: position.line, character: 0 },
|
start: { line: position.line, character: 0 },
|
||||||
end: position,
|
end: position,
|
||||||
})
|
})
|
||||||
|
@ -504,7 +496,7 @@ function provideScreenDirectiveCompletions(
|
||||||
isIncomplete: false,
|
isIncomplete: false,
|
||||||
items: Object.keys(screens).map((screen, index) => ({
|
items: Object.keys(screens).map((screen, index) => ({
|
||||||
label: screen,
|
label: screen,
|
||||||
kind: CompletionItemKind.Constant,
|
kind: 21,
|
||||||
data: 'screen',
|
data: 'screen',
|
||||||
sortText: naturalExpand(index),
|
sortText: naturalExpand(index),
|
||||||
textEdit: {
|
textEdit: {
|
||||||
|
@ -523,15 +515,14 @@ function provideScreenDirectiveCompletions(
|
||||||
|
|
||||||
function provideCssDirectiveCompletions(
|
function provideCssDirectiveCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): CompletionList {
|
): CompletionList {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
if (!isCssContext(state, document, position)) {
|
||||||
|
|
||||||
if (!isCssContext(state, doc, position)) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = doc.getText({
|
let text = document.getText({
|
||||||
start: { line: position.line, character: 0 },
|
start: { line: position.line, character: 0 },
|
||||||
end: position,
|
end: position,
|
||||||
})
|
})
|
||||||
|
@ -544,7 +535,7 @@ function provideCssDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: '@tailwind',
|
label: '@tailwind',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `Use the \`@tailwind\` directive to insert Tailwind’s \`base\`, \`components\`, \`utilities\` and \`screens\` styles into your CSS.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `Use the \`@tailwind\` directive to insert Tailwind’s \`base\`, \`components\`, \`utilities\` and \`screens\` styles into your CSS.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#tailwind'
|
'functions-and-directives/#tailwind'
|
||||||
|
@ -554,7 +545,7 @@ function provideCssDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: '@variants',
|
label: '@variants',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `You can generate \`responsive\`, \`hover\`, \`focus\`, \`active\`, and \`group-hover\` versions of your own utilities by wrapping their definitions in the \`@variants\` directive.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `You can generate \`responsive\`, \`hover\`, \`focus\`, \`active\`, and \`group-hover\` versions of your own utilities by wrapping their definitions in the \`@variants\` directive.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#variants'
|
'functions-and-directives/#variants'
|
||||||
|
@ -564,7 +555,7 @@ function provideCssDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: '@responsive',
|
label: '@responsive',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `You can generate responsive variants of your own classes by wrapping their definitions in the \`@responsive\` directive.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `You can generate responsive variants of your own classes by wrapping their definitions in the \`@responsive\` directive.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#responsive'
|
'functions-and-directives/#responsive'
|
||||||
|
@ -574,7 +565,7 @@ function provideCssDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: '@screen',
|
label: '@screen',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `The \`@screen\` directive allows you to create media queries that reference your breakpoints by name instead of duplicating their values in your own CSS.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `The \`@screen\` directive allows you to create media queries that reference your breakpoints by name instead of duplicating their values in your own CSS.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#screen'
|
'functions-and-directives/#screen'
|
||||||
|
@ -584,7 +575,7 @@ function provideCssDirectiveCompletions(
|
||||||
{
|
{
|
||||||
label: '@apply',
|
label: '@apply',
|
||||||
documentation: {
|
documentation: {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: `Use \`@apply\` to inline any existing utility classes into your own custom CSS.\n\n[Tailwind CSS Documentation](${docsUrl(
|
value: `Use \`@apply\` to inline any existing utility classes into your own custom CSS.\n\n[Tailwind CSS Documentation](${docsUrl(
|
||||||
state.version,
|
state.version,
|
||||||
'functions-and-directives/#apply'
|
'functions-and-directives/#apply'
|
||||||
|
@ -597,7 +588,7 @@ function provideCssDirectiveCompletions(
|
||||||
isIncomplete: false,
|
isIncomplete: false,
|
||||||
items: items.map((item) => ({
|
items: items.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
kind: CompletionItemKind.Keyword,
|
kind: 14,
|
||||||
data: 'directive',
|
data: 'directive',
|
||||||
textEdit: {
|
textEdit: {
|
||||||
newText: item.label,
|
newText: item.label,
|
||||||
|
@ -615,16 +606,15 @@ function provideCssDirectiveCompletions(
|
||||||
|
|
||||||
async function provideEmmetCompletions(
|
async function provideEmmetCompletions(
|
||||||
state: State,
|
state: State,
|
||||||
{ position, textDocument }: CompletionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): Promise<CompletionList> {
|
): Promise<CompletionList> {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
let settings = await getDocumentSettings(state, document)
|
||||||
|
|
||||||
let settings = await getDocumentSettings(state, doc)
|
|
||||||
if (settings.emmetCompletions !== true) return null
|
if (settings.emmetCompletions !== true) return null
|
||||||
|
|
||||||
const syntax = isHtmlContext(state, doc, position)
|
const syntax = isHtmlContext(state, document, position)
|
||||||
? 'html'
|
? 'html'
|
||||||
: isJsContext(state, doc, position)
|
: isJsContext(state, document, position)
|
||||||
? 'jsx'
|
? 'jsx'
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
@ -633,7 +623,7 @@ async function provideEmmetCompletions(
|
||||||
}
|
}
|
||||||
|
|
||||||
const extractAbbreviationResults = emmetHelper.extractAbbreviation(
|
const extractAbbreviationResults = emmetHelper.extractAbbreviation(
|
||||||
doc,
|
document,
|
||||||
position,
|
position,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
@ -649,14 +639,14 @@ async function provideEmmetCompletions(
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isValidLocationForEmmetAbbreviation(
|
!isValidLocationForEmmetAbbreviation(
|
||||||
doc,
|
document,
|
||||||
extractAbbreviationResults.abbreviationRange
|
extractAbbreviationResults.abbreviationRange
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const emmetItems = emmetHelper.doComplete(doc, position, syntax, {})
|
const emmetItems = emmetHelper.doComplete(document, position, syntax, {})
|
||||||
|
|
||||||
if (!emmetItems || !emmetItems.items || emmetItems.items.length !== 1) {
|
if (!emmetItems || !emmetItems.items || emmetItems.items.length !== 1) {
|
||||||
return null
|
return null
|
||||||
|
@ -679,23 +669,24 @@ async function provideEmmetCompletions(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function provideCompletions(
|
export async function doComplete(
|
||||||
state: State,
|
state: State,
|
||||||
params: CompletionParams
|
document: TextDocument,
|
||||||
): Promise<CompletionList> {
|
position: Position
|
||||||
|
) {
|
||||||
if (state === null) return { items: [], isIncomplete: false }
|
if (state === null) return { items: [], isIncomplete: false }
|
||||||
|
|
||||||
const result =
|
const result =
|
||||||
provideClassNameCompletions(state, params) ||
|
provideClassNameCompletions(state, document, position) ||
|
||||||
provideCssHelperCompletions(state, params) ||
|
provideCssHelperCompletions(state, document, position) ||
|
||||||
provideCssDirectiveCompletions(state, params) ||
|
provideCssDirectiveCompletions(state, document, position) ||
|
||||||
provideScreenDirectiveCompletions(state, params) ||
|
provideScreenDirectiveCompletions(state, document, position) ||
|
||||||
provideVariantsDirectiveCompletions(state, params) ||
|
provideVariantsDirectiveCompletions(state, document, position) ||
|
||||||
provideTailwindDirectiveCompletions(state, params)
|
provideTailwindDirectiveCompletions(state, document, position)
|
||||||
|
|
||||||
if (result) return result
|
if (result) return result
|
||||||
|
|
||||||
return provideEmmetCompletions(state, params)
|
return provideEmmetCompletions(state, document, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveCompletionItem(
|
export function resolveCompletionItem(
|
||||||
|
@ -728,7 +719,7 @@ export function resolveCompletionItem(
|
||||||
const css = stringifyCss(item.data.join(':'), className)
|
const css = stringifyCss(item.data.join(':'), className)
|
||||||
if (css) {
|
if (css) {
|
||||||
item.documentation = {
|
item.documentation = {
|
||||||
kind: MarkupKind.Markdown,
|
kind: 'markdown' as typeof MarkupKind.Markdown,
|
||||||
value: ['```css', css, '```'].join('\n'),
|
value: ['```css', css, '```'].join('\n'),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { TextDocument } from 'vscode-languageserver'
|
import type { TextDocument } from 'vscode-languageserver'
|
||||||
import { State } from '../../util/state'
|
import { State } from '../util/state'
|
||||||
import { getDocumentSettings } from '../../util/getDocumentSettings'
|
import { getDocumentSettings } from '../util/getDocumentSettings'
|
||||||
import { DiagnosticKind, AugmentedDiagnostic } from './types'
|
import { DiagnosticKind, AugmentedDiagnostic } from './types'
|
||||||
import { getCssConflictDiagnostics } from './getCssConflictDiagnostics'
|
import { getCssConflictDiagnostics } from './getCssConflictDiagnostics'
|
||||||
import { getInvalidApplyDiagnostics } from './getInvalidApplyDiagnostics'
|
import { getInvalidApplyDiagnostics } from './getInvalidApplyDiagnostics'
|
||||||
|
@ -9,7 +9,7 @@ import { getInvalidVariantDiagnostics } from './getInvalidVariantDiagnostics'
|
||||||
import { getInvalidConfigPathDiagnostics } from './getInvalidConfigPathDiagnostics'
|
import { getInvalidConfigPathDiagnostics } from './getInvalidConfigPathDiagnostics'
|
||||||
import { getInvalidTailwindDirectiveDiagnostics } from './getInvalidTailwindDirectiveDiagnostics'
|
import { getInvalidTailwindDirectiveDiagnostics } from './getInvalidTailwindDirectiveDiagnostics'
|
||||||
|
|
||||||
export async function getDiagnostics(
|
export async function doValidate(
|
||||||
state: State,
|
state: State,
|
||||||
document: TextDocument,
|
document: TextDocument,
|
||||||
only: DiagnosticKind[] = [
|
only: DiagnosticKind[] = [
|
||||||
|
@ -50,7 +50,7 @@ export async function getDiagnostics(
|
||||||
export async function provideDiagnostics(state: State, document: TextDocument) {
|
export async function provideDiagnostics(state: State, document: TextDocument) {
|
||||||
state.editor.connection.sendDiagnostics({
|
state.editor.connection.sendDiagnostics({
|
||||||
uri: document.uri,
|
uri: document.uri,
|
||||||
diagnostics: await getDiagnostics(state, document),
|
diagnostics: await doValidate(state, document),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { joinWithAnd } from '../../util/joinWithAnd'
|
import { joinWithAnd } from '../util/joinWithAnd'
|
||||||
import { State, Settings } from '../../util/state'
|
import { State, Settings } from '../util/state'
|
||||||
import { TextDocument, DiagnosticSeverity } from 'vscode-languageserver'
|
import type { TextDocument, DiagnosticSeverity } from 'vscode-languageserver'
|
||||||
import { CssConflictDiagnostic, DiagnosticKind } from './types'
|
import { CssConflictDiagnostic, DiagnosticKind } from './types'
|
||||||
import {
|
import {
|
||||||
findClassListsInDocument,
|
findClassListsInDocument,
|
||||||
getClassNamesInClassList,
|
getClassNamesInClassList,
|
||||||
} from '../../util/find'
|
} from '../util/find'
|
||||||
import { getClassNameDecls } from '../../util/getClassNameDecls'
|
import { getClassNameDecls } from '../util/getClassNameDecls'
|
||||||
import { getClassNameMeta } from '../../util/getClassNameMeta'
|
import { getClassNameMeta } from '../util/getClassNameMeta'
|
||||||
import { equal } from '../../../util/array'
|
import { equal } from '../util/array'
|
||||||
|
|
||||||
export function getCssConflictDiagnostics(
|
export function getCssConflictDiagnostics(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -58,8 +58,8 @@ export function getCssConflictDiagnostics(
|
||||||
range: className.range,
|
range: className.range,
|
||||||
severity:
|
severity:
|
||||||
severity === 'error'
|
severity === 'error'
|
||||||
? DiagnosticSeverity.Error
|
? 1 /* DiagnosticSeverity.Error */
|
||||||
: DiagnosticSeverity.Warning,
|
: 2 /* DiagnosticSeverity.Warning */,
|
||||||
message: `'${className.className}' applies the same CSS ${
|
message: `'${className.className}' applies the same CSS ${
|
||||||
properties.length === 1 ? 'property' : 'properties'
|
properties.length === 1 ? 'property' : 'properties'
|
||||||
} as ${joinWithAnd(
|
} as ${joinWithAnd(
|
|
@ -1,9 +1,9 @@
|
||||||
import { findClassNamesInRange } from '../../util/find'
|
import { findClassNamesInRange } from '../util/find'
|
||||||
import { InvalidApplyDiagnostic, DiagnosticKind } from './types'
|
import { InvalidApplyDiagnostic, DiagnosticKind } from './types'
|
||||||
import { Settings, State } from '../../util/state'
|
import { Settings, State } from '../util/state'
|
||||||
import { TextDocument, DiagnosticSeverity } from 'vscode-languageserver'
|
import type { TextDocument, DiagnosticSeverity } from 'vscode-languageserver'
|
||||||
import { validateApply } from '../../util/validateApply'
|
import { validateApply } from '../util/validateApply'
|
||||||
import { flagEnabled } from '../../util/flagEnabled'
|
import { flagEnabled } from '../util/flagEnabled'
|
||||||
|
|
||||||
export function getInvalidApplyDiagnostics(
|
export function getInvalidApplyDiagnostics(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -27,8 +27,8 @@ export function getInvalidApplyDiagnostics(
|
||||||
code: DiagnosticKind.InvalidApply,
|
code: DiagnosticKind.InvalidApply,
|
||||||
severity:
|
severity:
|
||||||
severity === 'error'
|
severity === 'error'
|
||||||
? DiagnosticSeverity.Error
|
? 1 /* DiagnosticSeverity.Error */
|
||||||
: DiagnosticSeverity.Warning,
|
: 2 /* DiagnosticSeverity.Warning */,
|
||||||
range: className.range,
|
range: className.range,
|
||||||
message: result.reason,
|
message: result.reason,
|
||||||
className,
|
className,
|
|
@ -1,14 +1,14 @@
|
||||||
import { State, Settings } from '../../util/state'
|
import { State, Settings } from '../util/state'
|
||||||
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
||||||
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
|
import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
|
||||||
import { isCssDoc } from '../../util/css'
|
import { isCssDoc } from '../util/css'
|
||||||
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
|
import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
|
||||||
import { findAll, indexToPosition } from '../../util/find'
|
import { findAll, indexToPosition } from '../util/find'
|
||||||
import { stringToPath } from '../../util/stringToPath'
|
import { stringToPath } from '../util/stringToPath'
|
||||||
import isObject from '../../../util/isObject'
|
import isObject from '../util/isObject'
|
||||||
import { closest } from '../../util/closest'
|
import { closest } from '../util/closest'
|
||||||
import { absoluteRange } from '../../util/absoluteRange'
|
import { absoluteRange } from '../util/absoluteRange'
|
||||||
import { combinations } from '../../util/combinations'
|
import { combinations } from '../util/combinations'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
|
|
||||||
function pathToString(path: string | string[]): string {
|
function pathToString(path: string | string[]): string {
|
||||||
|
@ -218,8 +218,8 @@ export function getInvalidConfigPathDiagnostics(
|
||||||
),
|
),
|
||||||
severity:
|
severity:
|
||||||
severity === 'error'
|
severity === 'error'
|
||||||
? DiagnosticSeverity.Error
|
? 1 /* DiagnosticSeverity.Error */
|
||||||
: DiagnosticSeverity.Warning,
|
: 2 /* DiagnosticSeverity.Warning */,
|
||||||
message: result.reason,
|
message: result.reason,
|
||||||
suggestions: result.suggestions,
|
suggestions: result.suggestions,
|
||||||
})
|
})
|
|
@ -1,11 +1,11 @@
|
||||||
import { State, Settings } from '../../util/state'
|
import { State, Settings } from '../util/state'
|
||||||
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
||||||
import { InvalidScreenDiagnostic, DiagnosticKind } from './types'
|
import { InvalidScreenDiagnostic, DiagnosticKind } from './types'
|
||||||
import { isCssDoc } from '../../util/css'
|
import { isCssDoc } from '../util/css'
|
||||||
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
|
import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
|
||||||
import { findAll, indexToPosition } from '../../util/find'
|
import { findAll, indexToPosition } from '../util/find'
|
||||||
import { closest } from '../../util/closest'
|
import { closest } from '../util/closest'
|
||||||
import { absoluteRange } from '../../util/absoluteRange'
|
import { absoluteRange } from '../util/absoluteRange'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
|
|
||||||
export function getInvalidScreenDiagnostics(
|
export function getInvalidScreenDiagnostics(
|
||||||
|
@ -63,8 +63,8 @@ export function getInvalidScreenDiagnostics(
|
||||||
),
|
),
|
||||||
severity:
|
severity:
|
||||||
severity === 'error'
|
severity === 'error'
|
||||||
? DiagnosticSeverity.Error
|
? 1 /* DiagnosticSeverity.Error */
|
||||||
: DiagnosticSeverity.Warning,
|
: 2 /* DiagnosticSeverity.Warning */,
|
||||||
message,
|
message,
|
||||||
suggestions,
|
suggestions,
|
||||||
})
|
})
|
|
@ -1,12 +1,12 @@
|
||||||
import { State, Settings } from '../../util/state'
|
import { State, Settings } from '../util/state'
|
||||||
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
||||||
import { InvalidTailwindDirectiveDiagnostic, DiagnosticKind } from './types'
|
import { InvalidTailwindDirectiveDiagnostic, DiagnosticKind } from './types'
|
||||||
import { isCssDoc } from '../../util/css'
|
import { isCssDoc } from '../util/css'
|
||||||
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
|
import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
|
||||||
import { findAll, indexToPosition } from '../../util/find'
|
import { findAll, indexToPosition } from '../util/find'
|
||||||
import semver from 'semver'
|
import semver from 'semver'
|
||||||
import { closest } from '../../util/closest'
|
import { closest } from '../util/closest'
|
||||||
import { absoluteRange } from '../../util/absoluteRange'
|
import { absoluteRange } from '../util/absoluteRange'
|
||||||
|
|
||||||
export function getInvalidTailwindDirectiveDiagnostics(
|
export function getInvalidTailwindDirectiveDiagnostics(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -71,8 +71,8 @@ export function getInvalidTailwindDirectiveDiagnostics(
|
||||||
),
|
),
|
||||||
severity:
|
severity:
|
||||||
severity === 'error'
|
severity === 'error'
|
||||||
? DiagnosticSeverity.Error
|
? 1 /* DiagnosticSeverity.Error */
|
||||||
: DiagnosticSeverity.Warning,
|
: 2 /* DiagnosticSeverity.Warning */,
|
||||||
message,
|
message,
|
||||||
suggestions,
|
suggestions,
|
||||||
})
|
})
|
|
@ -1,11 +1,11 @@
|
||||||
import { State, Settings } from '../../util/state'
|
import { State, Settings } from '../util/state'
|
||||||
import { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
|
||||||
import { InvalidVariantDiagnostic, DiagnosticKind } from './types'
|
import { InvalidVariantDiagnostic, DiagnosticKind } from './types'
|
||||||
import { isCssDoc } from '../../util/css'
|
import { isCssDoc } from '../util/css'
|
||||||
import { getLanguageBoundaries } from '../../util/getLanguageBoundaries'
|
import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
|
||||||
import { findAll, indexToPosition } from '../../util/find'
|
import { findAll, indexToPosition } from '../util/find'
|
||||||
import { closest } from '../../util/closest'
|
import { closest } from '../util/closest'
|
||||||
import { absoluteRange } from '../../util/absoluteRange'
|
import { absoluteRange } from '../util/absoluteRange'
|
||||||
|
|
||||||
export function getInvalidVariantDiagnostics(
|
export function getInvalidVariantDiagnostics(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -64,8 +64,8 @@ export function getInvalidVariantDiagnostics(
|
||||||
),
|
),
|
||||||
severity:
|
severity:
|
||||||
severity === 'error'
|
severity === 'error'
|
||||||
? DiagnosticSeverity.Error
|
? 1 /* DiagnosticSeverity.Error */
|
||||||
: DiagnosticSeverity.Warning,
|
: 2 /* DiagnosticSeverity.Warning */,
|
||||||
message,
|
message,
|
||||||
suggestions,
|
suggestions,
|
||||||
})
|
})
|
|
@ -1,5 +1,5 @@
|
||||||
import { Diagnostic } from 'vscode-languageserver'
|
import type { Diagnostic } from 'vscode-languageserver'
|
||||||
import { DocumentClassName, DocumentClassList } from '../../util/state'
|
import { DocumentClassName, DocumentClassList } from '../util/state'
|
||||||
|
|
||||||
export enum DiagnosticKind {
|
export enum DiagnosticKind {
|
||||||
CssConflict = 'cssConflict',
|
CssConflict = 'cssConflict',
|
|
@ -0,0 +1,43 @@
|
||||||
|
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'
|
||||||
|
import type { TextDocument } from 'vscode-languageserver'
|
||||||
|
const dlv = require('dlv')
|
||||||
|
|
||||||
|
export function getDocumentColors(state: State, document: TextDocument) {
|
||||||
|
let colors = []
|
||||||
|
if (!state.enabled) return colors
|
||||||
|
|
||||||
|
let classLists = findClassListsInDocument(state, document)
|
||||||
|
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 === null || typeof color === 'string' || color.a === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
colors.push({ range: className.range, color: color.toRgbString() })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let helperFns = findHelperFunctionsInDocument(state, document)
|
||||||
|
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
|
||||||
|
}
|
|
@ -1,30 +1,31 @@
|
||||||
import { State } from '../util/state'
|
import { State } from './util/state'
|
||||||
import { Hover, TextDocumentPositionParams } from 'vscode-languageserver'
|
import type { Hover, TextDocument, Position } from 'vscode-languageserver'
|
||||||
import { stringifyCss, stringifyConfigValue } from '../util/stringify'
|
import { stringifyCss, stringifyConfigValue } from './util/stringify'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
import { isCssContext } from '../util/css'
|
import { isCssContext } from './util/css'
|
||||||
import { findClassNameAtPosition } from '../util/find'
|
import { findClassNameAtPosition } from './util/find'
|
||||||
import { validateApply } from '../util/validateApply'
|
import { validateApply } from './util/validateApply'
|
||||||
import { getClassNameParts } from '../util/getClassNameAtPosition'
|
import { getClassNameParts } from './util/getClassNameAtPosition'
|
||||||
|
|
||||||
export function provideHover(
|
export function doHover(
|
||||||
state: State,
|
state: State,
|
||||||
params: TextDocumentPositionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): Hover {
|
): Hover {
|
||||||
return (
|
return (
|
||||||
provideClassNameHover(state, params) || provideCssHelperHover(state, params)
|
provideClassNameHover(state, document, position) ||
|
||||||
|
provideCssHelperHover(state, document, position)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function provideCssHelperHover(
|
function provideCssHelperHover(
|
||||||
state: State,
|
state: State,
|
||||||
{ textDocument, position }: TextDocumentPositionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): Hover {
|
): Hover {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
if (!isCssContext(state, document, position)) return null
|
||||||
|
|
||||||
if (!isCssContext(state, doc, position)) return null
|
const line = document.getText({
|
||||||
|
|
||||||
const line = doc.getText({
|
|
||||||
start: { line: position.line, character: 0 },
|
start: { line: position.line, character: 0 },
|
||||||
end: { line: position.line + 1, character: 0 },
|
end: { line: position.line + 1, character: 0 },
|
||||||
})
|
})
|
||||||
|
@ -72,17 +73,16 @@ function provideCssHelperHover(
|
||||||
|
|
||||||
function provideClassNameHover(
|
function provideClassNameHover(
|
||||||
state: State,
|
state: State,
|
||||||
{ textDocument, position }: TextDocumentPositionParams
|
document: TextDocument,
|
||||||
|
position: Position
|
||||||
): Hover {
|
): Hover {
|
||||||
let doc = state.editor.documents.get(textDocument.uri)
|
let className = findClassNameAtPosition(state, document, position)
|
||||||
|
|
||||||
let className = findClassNameAtPosition(state, doc, position)
|
|
||||||
if (className === null) return null
|
if (className === null) return null
|
||||||
|
|
||||||
const parts = getClassNameParts(state, className.className)
|
const parts = getClassNameParts(state, className.className)
|
||||||
if (!parts) return null
|
if (!parts) return null
|
||||||
|
|
||||||
if (isCssContext(state, doc, position)) {
|
if (isCssContext(state, document, position)) {
|
||||||
let validated = validateApply(state, parts)
|
let validated = validateApply(state, parts)
|
||||||
if (validated === null || validated.isApplyable === false) {
|
if (validated === null || validated.isApplyable === false) {
|
||||||
return null
|
return null
|
|
@ -0,0 +1,7 @@
|
||||||
|
export { doComplete, resolveCompletionItem } from './completionProvider'
|
||||||
|
export { doValidate } from './diagnostics/diagnosticsProvider'
|
||||||
|
export { doHover } from './hoverProvider'
|
||||||
|
export { doCodeActions } from './codeActions/codeActionProvider'
|
||||||
|
export { getDocumentColors } from './documentColorProvider'
|
||||||
|
export * from './util/state'
|
||||||
|
export * from './diagnostics/types'
|
|
@ -1,4 +1,4 @@
|
||||||
import { Range } from 'vscode-languageserver'
|
import type { Range } from 'vscode-languageserver'
|
||||||
|
|
||||||
export function absoluteRange(range: Range, reference?: Range) {
|
export function absoluteRange(range: Range, reference?: Range) {
|
||||||
return {
|
return {
|
|
@ -0,0 +1,28 @@
|
||||||
|
export function dedupe<T>(arr: Array<T>): Array<T> {
|
||||||
|
return arr.filter((value, index, self) => self.indexOf(value) === index)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dedupeBy<T>(
|
||||||
|
arr: Array<T>,
|
||||||
|
transform: (item: T) => any
|
||||||
|
): Array<T> {
|
||||||
|
return arr.filter(
|
||||||
|
(value, index, self) =>
|
||||||
|
self.map(transform).indexOf(transform(value)) === index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ensureArray<T>(value: T | T[]): T[] {
|
||||||
|
return Array.isArray(value) ? value : [value]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function flatten<T>(arrays: T[][]): T[] {
|
||||||
|
return [].concat.apply([], arrays)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function equal(arr1: any[], arr2: any[]): boolean {
|
||||||
|
return (
|
||||||
|
JSON.stringify(arr1.concat([]).sort()) ===
|
||||||
|
JSON.stringify(arr2.concat([]).sort())
|
||||||
|
)
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ const dlv = require('dlv')
|
||||||
import { State } from './state'
|
import { State } from './state'
|
||||||
import removeMeta from './removeMeta'
|
import removeMeta from './removeMeta'
|
||||||
import { TinyColor } from '@ctrl/tinycolor'
|
import { TinyColor } from '@ctrl/tinycolor'
|
||||||
import { ensureArray, dedupe, flatten } from '../../util/array'
|
import { ensureArray, dedupe, flatten } from './array'
|
||||||
|
|
||||||
const COLOR_PROPS = [
|
const COLOR_PROPS = [
|
||||||
'caret-color',
|
'caret-color',
|
|
@ -1,6 +1,6 @@
|
||||||
export function combinations(str: string): string[] {
|
export function combinations(str: string): string[] {
|
||||||
let fn = function (active: string, rest: string, a: string[]) {
|
let fn = function (active: string, rest: string, a: string[]) {
|
||||||
if (!active && !rest) return
|
if (!active && !rest) return undefined
|
||||||
if (!rest) {
|
if (!rest) {
|
||||||
a.push(active)
|
a.push(active)
|
||||||
} else {
|
} else {
|
|
@ -1,4 +1,4 @@
|
||||||
import { TextDocument, Position } from 'vscode-languageserver'
|
import type { TextDocument, Position } from 'vscode-languageserver'
|
||||||
import { isInsideTag, isVueDoc, isSvelteDoc, isHtmlDoc } from './html'
|
import { isInsideTag, isVueDoc, isSvelteDoc, isHtmlDoc } from './html'
|
||||||
import { State } from './state'
|
import { State } from './state'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { TextDocument, Range, Position } from 'vscode-languageserver'
|
import type { TextDocument, Range, Position } from 'vscode-languageserver'
|
||||||
import {
|
import {
|
||||||
DocumentClassName,
|
DocumentClassName,
|
||||||
DocumentClassList,
|
DocumentClassList,
|
||||||
|
@ -10,7 +10,7 @@ import { isCssContext, isCssDoc } from './css'
|
||||||
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
|
import { isHtmlContext, isHtmlDoc, isSvelteDoc, isVueDoc } from './html'
|
||||||
import { isWithinRange } from './isWithinRange'
|
import { isWithinRange } from './isWithinRange'
|
||||||
import { isJsContext, isJsDoc } from './js'
|
import { isJsContext, isJsDoc } from './js'
|
||||||
import { flatten } from '../../util/array'
|
import { flatten } from './array'
|
||||||
import {
|
import {
|
||||||
getClassAttributeLexer,
|
getClassAttributeLexer,
|
||||||
getComputedClassAttributeLexer,
|
getComputedClassAttributeLexer,
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { State, Settings } from './state'
|
||||||
|
import type { TextDocument } from 'vscode-languageserver'
|
||||||
|
|
||||||
|
export async function getDocumentSettings(
|
||||||
|
state: State,
|
||||||
|
document: TextDocument
|
||||||
|
): Promise<Settings> {
|
||||||
|
if (!state.editor.capabilities.configuration) {
|
||||||
|
return Promise.resolve(state.editor.globalSettings)
|
||||||
|
}
|
||||||
|
let result = state.editor.documentSettings.get(document.uri)
|
||||||
|
if (!result) {
|
||||||
|
result = await state.emitter.emit('getConfiguration', {
|
||||||
|
languageId: document.languageId,
|
||||||
|
})
|
||||||
|
state.editor.documentSettings.set(document.uri, result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { TextDocument, Range } from 'vscode-languageserver'
|
import type { TextDocument, Range } from 'vscode-languageserver'
|
||||||
import { isVueDoc, isHtmlDoc, isSvelteDoc } from './html'
|
import { isVueDoc, isHtmlDoc, isSvelteDoc } from './html'
|
||||||
import { State } from './state'
|
import { State } from './state'
|
||||||
import { findAll, indexToPosition } from './find'
|
import { findAll, indexToPosition } from './find'
|
|
@ -1,4 +1,4 @@
|
||||||
import { TextDocument, Position } from 'vscode-languageserver'
|
import type { TextDocument, Position } from 'vscode-languageserver'
|
||||||
import { State } from './state'
|
import { State } from './state'
|
||||||
|
|
||||||
export const HTML_LANGUAGES = [
|
export const HTML_LANGUAGES = [
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function isObject(variable: any): boolean {
|
||||||
|
return Object.prototype.toString.call(variable) === '[object Object]'
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { TextDocument, Range, Position } from 'vscode-languageserver'
|
import type { TextDocument, Range, Position } from 'vscode-languageserver'
|
||||||
|
|
||||||
export function isValidLocationForEmmetAbbreviation(
|
export function isValidLocationForEmmetAbbreviation(
|
||||||
document: TextDocument,
|
document: TextDocument,
|
|
@ -1,4 +1,4 @@
|
||||||
import { Position, Range } from 'vscode-languageserver'
|
import type { Position, Range } from 'vscode-languageserver'
|
||||||
|
|
||||||
export function isWithinRange(position: Position, range: Range): boolean {
|
export function isWithinRange(position: Position, range: Range): boolean {
|
||||||
if (
|
if (
|
|
@ -1,4 +1,4 @@
|
||||||
import { TextDocument, Position } from 'vscode-languageserver'
|
import type { TextDocument, Position } from 'vscode-languageserver'
|
||||||
import { isHtmlDoc, isInsideTag, isVueDoc, isSvelteDoc } from './html'
|
import { isHtmlDoc, isInsideTag, isVueDoc, isSvelteDoc } from './html'
|
||||||
import { State } from './state'
|
import { State } from './state'
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import moo from 'moo'
|
||||||
|
import { lazy } from './lazy'
|
||||||
|
|
||||||
|
const classAttributeStates: () => { [x: string]: moo.Rules } = () => ({
|
||||||
|
doubleClassList: {
|
||||||
|
lbrace: { match: new RegExp('(?<!\\\\)\\{'), push: 'interpBrace' },
|
||||||
|
rbrace: { match: new RegExp('(?<!\\\\)\\}'), pop: 1 },
|
||||||
|
end: { match: new RegExp('(?<!\\\\)"'), pop: 1 },
|
||||||
|
classlist: { match: new RegExp('[\\s\\S]'), lineBreaks: true },
|
||||||
|
},
|
||||||
|
singleClassList: {
|
||||||
|
lbrace: { match: new RegExp('(?<!\\\\)\\{'), push: 'interpBrace' },
|
||||||
|
rbrace: { match: new RegExp('(?<!\\\\)\\}'), pop: 1 },
|
||||||
|
end: { match: new RegExp("(?<!\\\\)'"), pop: 1 },
|
||||||
|
classlist: { match: new RegExp('[\\s\\S]'), lineBreaks: true },
|
||||||
|
},
|
||||||
|
tickClassList: {
|
||||||
|
lbrace: { match: new RegExp('(?<=(?<!\\\\)\\$)\\{'), push: 'interpBrace' },
|
||||||
|
rbrace: { match: new RegExp('(?<!\\\\)\\}'), pop: 1 },
|
||||||
|
end: { match: new RegExp('(?<!\\\\)`'), pop: 1 },
|
||||||
|
classlist: { match: new RegExp('[\\s\\S]'), lineBreaks: true },
|
||||||
|
},
|
||||||
|
interpBrace: {
|
||||||
|
startSingle: { match: new RegExp("(?<!\\\\)'"), push: 'singleClassList' },
|
||||||
|
startDouble: { match: new RegExp('(?<!\\\\)"'), push: 'doubleClassList' },
|
||||||
|
startTick: { match: new RegExp('(?<!\\\\)`'), push: 'tickClassList' },
|
||||||
|
lbrace: { match: new RegExp('(?<!\\\\)\\{'), push: 'interpBrace' },
|
||||||
|
rbrace: { match: new RegExp('(?<!\\\\)\\}'), pop: 1 },
|
||||||
|
text: { match: new RegExp('[\\s\\S]'), lineBreaks: true },
|
||||||
|
},
|
||||||
|
interpSingle: {
|
||||||
|
startDouble: { match: new RegExp('(?<!\\\\)"'), push: 'doubleClassList' },
|
||||||
|
startTick: { match: new RegExp('(?<!\\\\)`'), push: 'tickClassList' },
|
||||||
|
single: { match: new RegExp("(?<!\\\\)'"), pop: 1 },
|
||||||
|
text: { match: new RegExp('[\\s\\S]'), lineBreaks: true },
|
||||||
|
},
|
||||||
|
interpDouble: {
|
||||||
|
startSingle: { match: new RegExp("(?<!\\\\)'"), push: 'singleClassList' },
|
||||||
|
startTick: { match: new RegExp('(?<!\\\\)`'), push: 'tickClassList' },
|
||||||
|
double: { match: new RegExp('(?<!\\\\)"'), pop: 1 },
|
||||||
|
text: { match: new RegExp('[\\s\\S]'), lineBreaks: true },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const simpleClassAttributeStates: { [x: string]: moo.Rules } = {
|
||||||
|
main: {
|
||||||
|
start: { match: '"', push: 'doubleClassList' },
|
||||||
|
},
|
||||||
|
doubleClassList: {
|
||||||
|
end: { match: '"', pop: 1 },
|
||||||
|
classlist: { match: /[\s\S]/, lineBreaks: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getClassAttributeLexer = lazy(() => {
|
||||||
|
let supportsNegativeLookbehind = true
|
||||||
|
try {
|
||||||
|
new RegExp('(?<!)')
|
||||||
|
} catch (_) {
|
||||||
|
supportsNegativeLookbehind = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportsNegativeLookbehind) {
|
||||||
|
return moo.states({
|
||||||
|
main: {
|
||||||
|
start1: { match: '"', push: 'doubleClassList' },
|
||||||
|
start2: { match: "'", push: 'singleClassList' },
|
||||||
|
start3: { match: '{', push: 'interpBrace' },
|
||||||
|
},
|
||||||
|
...classAttributeStates(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return moo.states(simpleClassAttributeStates)
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getComputedClassAttributeLexer = lazy(() => {
|
||||||
|
let supportsNegativeLookbehind = true
|
||||||
|
try {
|
||||||
|
new RegExp('(?<!)')
|
||||||
|
} catch (_) {
|
||||||
|
supportsNegativeLookbehind = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportsNegativeLookbehind) {
|
||||||
|
return moo.states({
|
||||||
|
main: {
|
||||||
|
lbrace: { match: '{', push: 'interpBrace' },
|
||||||
|
single: { match: "'", push: 'interpSingle' },
|
||||||
|
double: { match: '"', push: 'interpDouble' },
|
||||||
|
},
|
||||||
|
...classAttributeStates(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return moo.states(simpleClassAttributeStates)
|
||||||
|
})
|
|
@ -1,4 +1,4 @@
|
||||||
import isObject from '../../util/isObject'
|
import isObject from './isObject'
|
||||||
|
|
||||||
export default function removeMeta(obj: any): any {
|
export default function removeMeta(obj: any): any {
|
||||||
let result = {}
|
let result = {}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Range } from 'vscode-languageserver'
|
import { Range } from 'vscode-languageserver'
|
||||||
import lineColumn from 'line-column'
|
import lineColumn from 'line-column'
|
||||||
import { ensureArray } from '../../util/array'
|
import { ensureArray } from './array'
|
||||||
|
|
||||||
export function removeRangesFromString(
|
export function removeRangesFromString(
|
||||||
str: string,
|
str: string,
|
|
@ -1,4 +1,4 @@
|
||||||
import { Range } from 'vscode-languageserver'
|
import type { Range } from 'vscode-languageserver'
|
||||||
|
|
||||||
export function resolveRange(range: Range, relativeTo?: Range) {
|
export function resolveRange(range: Range, relativeTo?: Range) {
|
||||||
return {
|
return {
|
|
@ -1,4 +1,4 @@
|
||||||
import isObject from '../../util/isObject'
|
import isObject from './isObject'
|
||||||
|
|
||||||
export type MinMaxScreen = {
|
export type MinMaxScreen = {
|
||||||
min?: string
|
min?: string
|
||||||
|
@ -15,8 +15,8 @@ function isRawScreen(screen: unknown): screen is RawScreen {
|
||||||
return isObject(screen) && (screen as RawScreen).raw !== undefined
|
return isObject(screen) && (screen as RawScreen).raw !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stringifyScreen(screen: Screen): string {
|
export function stringifyScreen(screen: Screen): string | undefined {
|
||||||
if (!screen) return
|
if (!screen) return undefined
|
||||||
if (typeof screen === 'string') return `@media (min-width: ${screen})`
|
if (typeof screen === 'string') return `@media (min-width: ${screen})`
|
||||||
if (isRawScreen(screen)) {
|
if (isRawScreen(screen)) {
|
||||||
return `@media ${(screen as RawScreen).raw}`
|
return `@media ${(screen as RawScreen).raw}`
|
|
@ -1,5 +1,4 @@
|
||||||
import { TextDocuments, Connection, Range } from 'vscode-languageserver'
|
import type { TextDocuments, Connection, Range } from 'vscode-languageserver'
|
||||||
import { NotificationEmitter } from '../../lib/emitter'
|
|
||||||
|
|
||||||
export type ClassNamesTree = {
|
export type ClassNamesTree = {
|
||||||
[key: string]: ClassNamesTree
|
[key: string]: ClassNamesTree
|
||||||
|
@ -42,9 +41,15 @@ export type Settings = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NotificationEmitter {
|
||||||
|
on: (name: string, handler: (args: any) => void) => void
|
||||||
|
off: (name: string, handler: (args: any) => void) => void
|
||||||
|
emit: (name: string, args: any) => Promise<any>
|
||||||
|
}
|
||||||
|
|
||||||
export type State = null | {
|
export type State = null | {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
emitter: NotificationEmitter
|
emitter?: NotificationEmitter
|
||||||
version?: string
|
version?: string
|
||||||
configPath?: string
|
configPath?: string
|
||||||
config?: any
|
config?: any
|
|
@ -1,7 +1,7 @@
|
||||||
import removeMeta from './removeMeta'
|
import removeMeta from './removeMeta'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
import escapeClassName from 'css.escape'
|
import escapeClassName from 'css.escape'
|
||||||
import { ensureArray } from '../../util/array'
|
import { ensureArray } from './array'
|
||||||
|
|
||||||
export function stringifyConfigValue(x: any): string {
|
export function stringifyConfigValue(x: any): string {
|
||||||
if (typeof x === 'string') return x
|
if (typeof x === 'string') return x
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"include": ["src", "types"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"lib": ["dom", "esnext"],
|
||||||
|
"importHelpers": true,
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": false,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"jsx": "react",
|
||||||
|
"esModuleInterop": true
|
||||||
|
}
|
||||||
|
}
|