Repository: yaegassy/coc-tailwindcss3
Branch: master
Commit: 3eae6148c841
Files: 16
Total size: 72.8 KB
Directory structure:
gitextract_tl3tduef/
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── esbuild.js
├── package.json
├── src/
│ ├── config.ts
│ ├── constants.ts
│ ├── headwind/
│ │ ├── headwindFeature.ts
│ │ └── headwindUtils.ts
│ ├── index.ts
│ └── util/
│ ├── array.ts
│ ├── isObject.ts
│ └── languages.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.js
================================================
module.exports = {
env: {
node: true,
},
parser: '@typescript-eslint/parser',
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
};
================================================
FILE: .gitignore
================================================
lib
_ref
### Generated by gibo (https://github.com/simonwhitaker/gibo)
### https://raw.github.com/github/gitignore/d0b80a469983a7beece8fa1f5c48a8242318b531/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
================================================
FILE: .npmignore
================================================
src
node_modules
tsconfig.json
*.map
.tags
.DS_Store
webpack.config.js
esbuild.js
yarn.lock
yarn-error.log
.github
.eslintrc.js
.prettierrc
_ref
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 yaegassy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# coc-tailwindcss3
> fork from [vscode-tailwindcss](https://github.com/tailwindlabs/tailwindcss-intellisense/tree/master/packages/vscode-tailwindcss) and [headwind](https://github.com/heybourn/headwind)
Intelligent Tailwind CSS tooling for [coc.nvim](https://github.com/neoclide/coc.nvim).
<img width="744" alt="coc-tailwindcss3-screenshot" src="https://user-images.githubusercontent.com/188642/163154916-1810be1e-fa23-4936-82c1-14f3ca294e63.png">
## Install
```vim
:CocInstall @yaegassy/coc-tailwindcss3
```
> scoped packages
## Configuration options
- `tailwindCSS.enable`: Enable coc-tailwindcss3 extension, default: `true`
- `tailwindCSS.trace.server`: Trace level of tailwindCSS language server, default: `off`
- `tailwindCSS.custom.serverPath`: Custom path to server module. If there is no setting, the built-in module will be used, default: `""`
- `tailwindCSS.emmetCompletions`: Enable class name completions when using Emmet-style syntax, for example `div.bg-red-500.uppercase`, default: `false`
- `tailwindCSS.includeLanguages`: Enable features in languages that are not supported by default. Add a mapping here between the new language and an already supported language. E.g.: `{"plaintext": "html"}`, default: `{ "eelixir": "html", "elixir": "html", "eruby": "html", "html.twig": "html" }`
- `tailwindCSS.files.exclude`: Configure glob patterns to exclude from all IntelliSense features. Inherits all glob patterns from the `#files.exclude#` setting, default: `["**/.git/**", "**/node_modules/**", "**/.hg/**", "**/.svn/**"]`
- `tailwindCSS.classAttributes`: The HTML attributes for which to provide class completions, hover previews, linting etc, default: `["class", "className", "ngClass"]`
- `tailwindCSS.suggestions`: Enable autocomplete suggestions, default: `true`
- `tailwindCSS.hovers`: Enable hovers, default: `true`
- `tailwindCSS.codeActions`: Enable code actions, default: `true`
- `tailwindCSS.validate`: Enable linting. Rules can be configured individually using the `tailwindcss.lint.*` settings, default: `true`
- `tailwindCSS.lint.cssConflict`: Class names on the same HTML element which apply the same CSS property or properties, valid option ["ignore", "warning", "error"], default: `warning`
- `tailwindCSS.lint.invalidApply`: Unsupported use of the [`@apply` directive](https://tailwindcss.com/docs/functions-and-directives/#apply), valid option ["ignore", "warning", "error"], default: `error`
- `tailwindCSS.lint.invalidScreen`: Unknown screen name used with the [`@screen` directive](https://tailwindcss.com/docs/functions-and-directives/#screen), valid option ["ignore", "warning", "error"], default: `error`
- `tailwindCSS.lint.invalidVariant`: Unknown variant name used with the [`@variants` directive](https://tailwindcss.com/docs/functions-and-directives/#variants), valid option ["ignore", "warning", "error"], default: `error`
- `tailwindCSS.lint.invalidConfigPath`: Unknown or invalid path used with the [`theme` helper](https://tailwindcss.com/docs/functions-and-directives/#theme), valid option ["ignore", "warning", "error"], default: `error`
- `tailwindCSS.lint.invalidTailwindDirective`: Unknown value used with the [`@tailwind` directive](https://tailwindcss.com/docs/functions-and-directives/#tailwind), valid option ["ignore", "warning", "error"], default: `error`
- `tailwindCSS.lint.recommendedVariantOrder`: Class variants not in the recommended order (applies in [JIT mode](https://tailwindcss.com/docs/just-in-time-mode) only), valid option ["ignore", "warning", "error"], default: `error`
- `tailwindCSS.lint.suggestCanonicalClasses`: Indicate when utilities may be written in a more optimal form, valid option ["ignore", "warning", "error"], default: `warning`
- `tailwindCSS.experimental.classRegex`: ...
- `tailwindCSS.inspectPort`: Enable the Node.js inspector agent for the language server and listen on the specified port, default: `null`
- `tailwindCSS.headwind.defaultSortOrder`: Sort order: A string array that determines the default sort order.
- Check the "Configuration" section of [package.json](package.json) for default values.
- `tailwindCSS.headwind.classRegex`: An object with language IDs as keys and their values determining the regex to search for Tailwind CSS classes.
- Check the "Configuration" section of [package.json](package.json) for default values.
- `tailwindCSS.headwind.runOnSave`: A flag that controls whether or not Headwind will sort your Tailwind CSS classes on save, default: `false`
- `tailwindCSS.headwind.removeDuplicates`: A flag that controls whether or not Headwind will remove duplicate Tailwind CSS classes, default: `true`
- `tailwindCSS.headwind.prependCustomClasses`: A flag that controls whether or not Headwind will move custom CSS classes before (true) or after (false) the Tailwind CSS classes, default: `false`
- `tailwindCSS.headwind.customTailwindPrefix`: If the Tailwind Prefix function is used, this can be specified here (e.g. tw-), default: `""`
## Commands
- `tailwindCSS.showOutput`: Tailwind CSS: Show Output
- `tailwindCSS.headwind.sortTailwindClasses`: Headwind: Sort Tailwind CSS Classes
## Custom Server Path
> tailwindCSS.custom.serverPath: Custom path to server module. If there is no setting, the built-in module will be used, default: ""
This setting allows you to use the tailwind's language server module installed in any location.
### Usage Example 1 (Use extensions installed in VSCode)
**setting**:
```jsonc
{
"tailwindCSS.custom.serverPath": "/path/to/.vscode/extensions/bradlc.vscode-tailwindcss-0.12.3/dist/tailwindServer.js
}
```
### Usage Example 2 (npm)
**prepare**:
```bash
npm i -g @tailwindcss/language-server
```
or `insiders` verson
```bash
npm i -g @tailwindcss/language-server@insiders
```
- <https://www.npmjs.com/package/@tailwindcss/language-server/v/insiders?activeTab=versions>
**setting**:
```jsonc
{
"tailwindCSS.custom.serverPath": "/path/to/.nvm/versions/node/v20.15.0/bin/tailwindcss-language-server"
}
```
## Thanks
- <https://github.com/tailwindlabs/tailwindcss-intellisense>
- <https://github.com/heybourn/headwind>
- <https://github.com/iamcco/coc-tailwindcss>
## License
MIT
---
> This extension is built with [create-coc-extension](https://github.com/fannheyward/create-coc-extension)
================================================
FILE: esbuild.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
async function start(watch) {
await require('esbuild').build({
entryPoints: ['src/index.ts'],
bundle: true,
watch,
minify: process.env.NODE_ENV === 'production',
sourcemap: process.env.NODE_ENV === 'development',
mainFields: ['module', 'main'],
external: ['coc.nvim'],
platform: 'node',
target: 'node14.14',
outfile: 'lib/index.js',
});
}
let watch = false;
if (process.argv.length > 2 && process.argv[2] === '--watch') {
console.log('watching...');
watch = {
onRebuild(error) {
if (error) {
console.error('watch build failed:', error);
} else {
console.log('watch build succeeded');
}
},
};
}
start(watch).catch((e) => {
console.error(e);
});
================================================
FILE: package.json
================================================
{
"name": "@yaegassy/coc-tailwindcss3",
"version": "0.6.14",
"description": "Intelligent Tailwind CSS tooling for coc.nvim",
"author": "yaegassy <yosstools@gmail.com>",
"license": "MIT",
"main": "lib/index.js",
"keywords": [
"coc.nvim",
"tailwind",
"tailwindcss",
"css",
"intellisense",
"autocomplete",
"vim",
"neovim"
],
"engines": {
"coc": "^0.0.80"
},
"repository": {
"type": "git",
"url": "https://github.com/yaegassy/coc-tailwindcss3"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"lint": "eslint src --ext ts",
"clean": "rimraf lib",
"watch": "node esbuild.js --watch",
"build": "node esbuild.js",
"prepare": "node esbuild.js"
},
"prettier": {
"singleQuote": true,
"printWidth": 120,
"semi": true
},
"devDependencies": {
"@types/minimatch": "^3.0.5",
"@types/node": "^20.10.6",
"@types/normalize-path": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^6.17.0",
"@typescript-eslint/parser": "^6.17.0",
"coc.nvim": "0.0.83-next.17",
"esbuild": "^0.15.12",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.2",
"prettier": "^3.1.1",
"rimraf": "^5.0.1",
"typescript": "^5.3.3"
},
"activationEvents": [
"*"
],
"contributes": {
"configuration": {
"type": "object",
"title": "coc-tailwindcss3 configuration",
"properties": {
"tailwindCSS.enable": {
"type": "boolean",
"default": true,
"description": "Enable coc-tailwindcss3 extension"
},
"tailwindCSS.trace.server": {
"type": "string",
"default": "off",
"enum": [
"off",
"messages",
"verbose"
],
"description": "Trace level of tailwindCSS language server"
},
"tailwindCSS.custom.serverPath": {
"type": "string",
"default": "",
"description": "Custom path to server module. If there is no setting, the built-in module will be used"
},
"tailwindCSS.emmetCompletions": {
"type": "boolean",
"default": false,
"description": "Enable class name completions when using Emmet-style syntax, for example `div.bg-red-500.uppercase`"
},
"tailwindCSS.includeLanguages": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"default": {
"eelixir": "html",
"elixir": "html",
"eruby": "html",
"html.twig": "html"
},
"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.files.exclude": {
"type": "array",
"items": {
"type": "string"
},
"default": [
"**/.git/**",
"**/node_modules/**",
"**/.hg/**",
"**/.svn/**"
],
"markdownDescription": "Configure glob patterns to exclude from all IntelliSense features. Inherits all glob patterns from the `#files.exclude#` setting."
},
"tailwindCSS.classAttributes": {
"type": "array",
"items": {
"type": "string"
},
"default": [
"class",
"className",
"ngClass"
],
"markdownDescription": "The HTML attributes for which to provide class completions, hover previews, linting etc."
},
"tailwindCSS.suggestions": {
"type": "boolean",
"default": true,
"markdownDescription": "Enable autocomplete suggestions.",
"scope": "language-overridable"
},
"tailwindCSS.hovers": {
"type": "boolean",
"default": true,
"markdownDescription": "Enable hovers.",
"scope": "language-overridable"
},
"tailwindCSS.codeActions": {
"type": "boolean",
"default": true,
"markdownDescription": "Enable code actions.",
"scope": "language-overridable"
},
"tailwindCSS.colorDecorators": {
"type": "boolean",
"default": true,
"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"
},
"tailwindCSS.lint.recommendedVariantOrder": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"markdownDescription": "Class variants not in the recommended order (applies in [JIT mode](https://tailwindcss.com/docs/just-in-time-mode) only)",
"scope": "language-overridable"
},
"tailwindCSS.lint.suggestCanonicalClasses": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"markdownDescription": "Indicate when utilities may be written in a more optimal form",
"scope": "language-overridable"
},
"tailwindCSS.experimental.classRegex": {
"type": "array",
"scope": "language-overridable"
},
"tailwindCSS.showPixelEquivalents": {
"type": "boolean",
"default": true,
"markdownDescription": "Show `px` equivalents for `rem` CSS values."
},
"tailwindCSS.rootFontSize": {
"type": "number",
"default": 16,
"markdownDescription": "Root font size in pixels. Used to convert `rem` CSS values to their `px` equivalents. See `#tailwindCSS.showPixelEquivalents#`."
},
"tailwindCSS.inspectPort": {
"type": [
"number",
"null"
],
"default": null,
"markdownDescription": "Enable the Node.js inspector agent for the language server and listen on the specified port."
},
"tailwindCSS.headwind.defaultSortOrder": {
"type": "array",
"default": [
"container",
"static",
"fixed",
"absolute",
"relative",
"sticky",
"inset-0",
"inset-x-0",
"inset-y-0",
"inset-x-auto",
"inset-y-auto",
"inset-auto",
"top-0",
"bottom-0",
"left-0",
"right-0",
"top-auto",
"bottom-auto",
"left-auto",
"right-auto",
"z-0",
"z-10",
"z-20",
"z-30",
"z-40",
"z-50",
"z-auto",
"flex",
"inline-flex",
"flex-row",
"flex-row-reverse",
"flex-col",
"flex-col-reverse",
"flex-no-wrap",
"flex-wrap",
"flex-wrap-reverse",
"items-stretch",
"items-start",
"items-center",
"items-end",
"items-baseline",
"content-start",
"content-center",
"content-end",
"content-between",
"content-around",
"self-auto",
"self-start",
"self-center",
"self-end",
"self-stretch",
"justify-start",
"justify-center",
"justify-end",
"justify-between",
"justify-around",
"flex-1",
"flex-auto",
"flex-initial",
"flex-none",
"flex-grow",
"flex-grow-0",
"flex-shrink",
"flex-shrink-0",
"order-first",
"order-last",
"order-none",
"order-1",
"order-2",
"order-3",
"order-4",
"order-5",
"order-6",
"order-7",
"order-8",
"order-9",
"order-10",
"order-11",
"order-12",
"visible",
"invisible",
"hidden",
"block",
"inline-block",
"inline",
"table",
"table-row",
"table-cell",
"clearfix",
"float-left",
"float-right",
"float-none",
"object-contain",
"object-cover",
"object-fill",
"object-none",
"object-scale-down",
"object-bottom",
"object-center",
"object-left",
"object-left-bottom",
"object-left-top",
"object-right",
"object-right-bottom",
"object-right-top",
"object-top",
"w-0",
"w-1",
"w-2",
"w-3",
"w-4",
"w-5",
"w-6",
"w-8",
"w-10",
"w-12",
"w-16",
"w-20",
"w-24",
"w-32",
"w-40",
"w-48",
"w-56",
"w-64",
"w-auto",
"w-px",
"w-1/2",
"w-1/3",
"w-2/3",
"w-1/4",
"w-2/4",
"w-3/4",
"w-1/5",
"w-2/5",
"w-3/5",
"w-4/5",
"w-1/6",
"w-2/6",
"w-3/6",
"w-4/6",
"w-5/6",
"w-1/12",
"w-2/12",
"w-3/12",
"w-4/12",
"w-5/12",
"w-6/12",
"w-7/12",
"w-8/12",
"w-9/12",
"w-10/12",
"w-11/12",
"w-full",
"w-screen",
"h-0",
"h-1",
"h-2",
"h-3",
"h-4",
"h-5",
"h-6",
"h-8",
"h-10",
"h-12",
"h-16",
"h-20",
"h-24",
"h-32",
"h-40",
"h-48",
"h-56",
"h-64",
"h-auto",
"h-px",
"h-full",
"h-screen",
"max-w-xs",
"max-w-sm",
"max-w-md",
"max-w-lg",
"max-w-xl",
"max-w-2xl",
"max-w-3xl",
"max-w-4xl",
"max-w-5xl",
"max-w-6xl",
"max-w-full",
"max-h-full",
"max-h-screen",
"min-w-0",
"min-w-full",
"min-h-0",
"min-h-full",
"min-h-screen",
"p-0",
"p-1",
"p-2",
"p-3",
"p-4",
"p-5",
"p-6",
"p-8",
"p-10",
"p-12",
"p-16",
"p-20",
"p-24",
"p-32",
"p-40",
"p-48",
"p-56",
"p-64",
"p-px",
"px-0",
"px-1",
"px-2",
"px-3",
"px-4",
"px-5",
"px-6",
"px-8",
"px-10",
"px-12",
"px-16",
"px-20",
"px-24",
"px-32",
"px-40",
"px-48",
"px-56",
"px-64",
"px-px",
"py-0",
"py-1",
"py-2",
"py-3",
"py-4",
"py-5",
"py-6",
"py-8",
"py-10",
"py-12",
"py-16",
"py-20",
"py-24",
"py-32",
"py-40",
"py-48",
"py-56",
"py-64",
"py-px",
"pt-0",
"pt-1",
"pt-2",
"pt-3",
"pt-4",
"pt-5",
"pt-6",
"pt-8",
"pt-10",
"pt-12",
"pt-16",
"pt-20",
"pt-24",
"pt-32",
"pt-40",
"pt-48",
"pt-56",
"pt-64",
"pt-px",
"pb-0",
"pb-1",
"pb-2",
"pb-3",
"pb-4",
"pb-5",
"pb-6",
"pb-8",
"pb-10",
"pb-12",
"pb-16",
"pb-20",
"pb-24",
"pb-32",
"pb-40",
"pb-48",
"pb-56",
"pb-64",
"pb-px",
"pl-0",
"pl-1",
"pl-2",
"pl-3",
"pl-4",
"pl-5",
"pl-6",
"pl-8",
"pl-10",
"pl-12",
"pl-16",
"pl-20",
"pl-24",
"pl-32",
"pl-40",
"pl-48",
"pl-56",
"pl-64",
"pl-px",
"pr-0",
"pr-1",
"pr-2",
"pr-3",
"pr-4",
"pr-5",
"pr-6",
"pr-8",
"pr-10",
"pr-12",
"pr-16",
"pr-20",
"pr-24",
"pr-32",
"pr-40",
"pr-48",
"pr-56",
"pr-64",
"pr-px",
"m-0",
"m-1",
"m-2",
"m-3",
"m-4",
"m-5",
"m-6",
"m-8",
"m-10",
"m-12",
"m-16",
"m-20",
"m-24",
"m-32",
"m-40",
"m-48",
"m-56",
"m-64",
"m-auto",
"m-px",
"mx-0",
"mx-1",
"mx-2",
"mx-3",
"mx-4",
"mx-5",
"mx-6",
"mx-8",
"mx-10",
"mx-12",
"mx-16",
"mx-20",
"mx-24",
"mx-32",
"mx-40",
"mx-48",
"mx-56",
"mx-64",
"mx-auto",
"mx-px",
"my-0",
"my-1",
"my-2",
"my-3",
"my-4",
"my-5",
"my-6",
"my-8",
"my-10",
"my-12",
"my-16",
"my-20",
"my-24",
"my-32",
"my-40",
"my-48",
"my-56",
"my-64",
"my-auto",
"my-px",
"mt-0",
"mt-1",
"mt-2",
"mt-3",
"mt-4",
"mt-5",
"mt-6",
"mt-8",
"mt-10",
"mt-12",
"mt-16",
"mt-20",
"mt-24",
"mt-32",
"mt-40",
"mt-48",
"mt-56",
"mt-64",
"mt-auto",
"mt-px",
"mb-0",
"mb-1",
"mb-2",
"mb-3",
"mb-4",
"mb-5",
"mb-6",
"mb-8",
"mb-10",
"mb-12",
"mb-16",
"mb-20",
"mb-24",
"mb-32",
"mb-40",
"mb-48",
"mb-56",
"mb-64",
"mb-auto",
"mb-px",
"ml-0",
"ml-1",
"ml-2",
"ml-3",
"ml-4",
"ml-5",
"ml-6",
"ml-8",
"ml-10",
"ml-12",
"ml-16",
"ml-20",
"ml-24",
"ml-32",
"ml-40",
"ml-48",
"ml-56",
"ml-64",
"ml-auto",
"ml-px",
"mr-0",
"mr-1",
"mr-2",
"mr-3",
"mr-4",
"mr-5",
"mr-6",
"mr-8",
"mr-10",
"mr-12",
"mr-16",
"mr-20",
"mr-24",
"mr-32",
"mr-40",
"mr-48",
"mr-56",
"mr-64",
"mr-auto",
"mr-px",
"-m-0",
"-m-1",
"-m-2",
"-m-3",
"-m-4",
"-m-5",
"-m-6",
"-m-8",
"-m-10",
"-m-12",
"-m-16",
"-m-20",
"-m-24",
"-m-32",
"-m-40",
"-m-48",
"-m-56",
"-m-64",
"-m-px",
"-mx-0",
"-mx-1",
"-mx-2",
"-mx-3",
"-mx-4",
"-mx-5",
"-mx-6",
"-mx-8",
"-mx-10",
"-mx-12",
"-mx-16",
"-mx-20",
"-mx-24",
"-mx-32",
"-mx-40",
"-mx-48",
"-mx-56",
"-mx-64",
"-mx-px",
"-my-0",
"-my-1",
"-my-2",
"-my-3",
"-my-4",
"-my-5",
"-my-6",
"-my-8",
"-my-10",
"-my-12",
"-my-16",
"-my-20",
"-my-24",
"-my-32",
"-my-40",
"-my-48",
"-my-56",
"-my-64",
"-my-px",
"-mt-0",
"-mt-1",
"-mt-2",
"-mt-3",
"-mt-4",
"-mt-5",
"-mt-6",
"-mt-8",
"-mt-10",
"-mt-12",
"-mt-16",
"-mt-20",
"-mt-24",
"-mt-32",
"-mt-40",
"-mt-48",
"-mt-56",
"-mt-64",
"-mt-px",
"-mb-0",
"-mb-1",
"-mb-2",
"-mb-3",
"-mb-4",
"-mb-5",
"-mb-6",
"-mb-8",
"-mb-10",
"-mb-12",
"-mb-16",
"-mb-20",
"-mb-24",
"-mb-32",
"-mb-40",
"-mb-48",
"-mb-56",
"-mb-64",
"-mb-px",
"-ml-0",
"-ml-1",
"-ml-2",
"-ml-3",
"-ml-4",
"-ml-5",
"-ml-6",
"-ml-8",
"-ml-10",
"-ml-12",
"-ml-16",
"-ml-20",
"-ml-24",
"-ml-32",
"-ml-40",
"-ml-48",
"-ml-56",
"-ml-64",
"-ml-px",
"-mr-0",
"-mr-1",
"-mr-2",
"-mr-3",
"-mr-4",
"-mr-5",
"-mr-6",
"-mr-8",
"-mr-10",
"-mr-12",
"-mr-16",
"-mr-20",
"-mr-24",
"-mr-32",
"-mr-40",
"-mr-48",
"-mr-56",
"-mr-64",
"-mr-px",
"overflow-auto",
"overflow-hidden",
"overflow-visible",
"overflow-scroll",
"overflow-x-auto",
"overflow-x-hidden",
"overflow-x-visible",
"overflow-x-scroll",
"overflow-y-auto",
"overflow-y-hidden",
"overflow-y-visible",
"overflow-y-scroll",
"scrolling-touch",
"scrolling-auto",
"font-sans",
"font-serif",
"font-mono",
"text-xs",
"text-sm",
"text-base",
"text-lg",
"text-xl",
"text-2xl",
"text-3xl",
"text-4xl",
"text-5xl",
"text-6xl",
"antialiased",
"subpixel-antialiased",
"italic",
"not-italic",
"font-hairline",
"font-thin",
"font-light",
"font-normal",
"font-medium",
"font-semibold",
"font-bold",
"font-extrabold",
"font-black",
"leading-none",
"leading-tight",
"leading-snug",
"leading-normal",
"leading-relaxed",
"leading-loose",
"tracking-tighter",
"tracking-tight",
"tracking-normal",
"tracking-wide",
"tracking-wider",
"tracking-widest",
"text-left",
"text-center",
"text-right",
"text-justify",
"text-transparent",
"text-black",
"text-white",
"text-gray-100",
"text-gray-200",
"text-gray-300",
"text-gray-400",
"text-gray-500",
"text-gray-600",
"text-gray-700",
"text-gray-800",
"text-gray-900",
"text-red-100",
"text-red-200",
"text-red-300",
"text-red-400",
"text-red-500",
"text-red-600",
"text-red-700",
"text-red-800",
"text-red-900",
"text-orange-100",
"text-orange-200",
"text-orange-300",
"text-orange-400",
"text-orange-500",
"text-orange-600",
"text-orange-700",
"text-orange-800",
"text-orange-900",
"text-yellow-100",
"text-yellow-200",
"text-yellow-300",
"text-yellow-400",
"text-yellow-500",
"text-yellow-600",
"text-yellow-700",
"text-yellow-800",
"text-yellow-900",
"text-green-100",
"text-green-200",
"text-green-300",
"text-green-400",
"text-green-500",
"text-green-600",
"text-green-700",
"text-green-800",
"text-green-900",
"text-teal-100",
"text-teal-200",
"text-teal-300",
"text-teal-400",
"text-teal-500",
"text-teal-600",
"text-teal-700",
"text-teal-800",
"text-teal-900",
"text-blue-100",
"text-blue-200",
"text-blue-300",
"text-blue-400",
"text-blue-500",
"text-blue-600",
"text-blue-700",
"text-blue-800",
"text-blue-900",
"text-indigo-100",
"text-indigo-200",
"text-indigo-300",
"text-indigo-400",
"text-indigo-500",
"text-indigo-600",
"text-indigo-700",
"text-indigo-800",
"text-indigo-900",
"text-purple-100",
"text-purple-200",
"text-purple-300",
"text-purple-400",
"text-purple-500",
"text-purple-600",
"text-purple-700",
"text-purple-800",
"text-purple-900",
"text-pink-100",
"text-pink-200",
"text-pink-300",
"text-pink-400",
"text-pink-500",
"text-pink-600",
"text-pink-700",
"text-pink-800",
"text-pink-900",
"placeholder-transparent",
"placeholder-black",
"placeholder-white",
"placeholder-gray-100",
"placeholder-gray-200",
"placeholder-gray-300",
"placeholder-gray-400",
"placeholder-gray-500",
"placeholder-gray-600",
"placeholder-gray-700",
"placeholder-gray-800",
"placeholder-gray-900",
"placeholder-red-100",
"placeholder-red-200",
"placeholder-red-300",
"placeholder-red-400",
"placeholder-red-500",
"placeholder-red-600",
"placeholder-red-700",
"placeholder-red-800",
"placeholder-red-900",
"placeholder-orange-100",
"placeholder-orange-200",
"placeholder-orange-300",
"placeholder-orange-400",
"placeholder-orange-500",
"placeholder-orange-600",
"placeholder-orange-700",
"placeholder-orange-800",
"placeholder-orange-900",
"placeholder-yellow-100",
"placeholder-yellow-200",
"placeholder-yellow-300",
"placeholder-yellow-400",
"placeholder-yellow-500",
"placeholder-yellow-600",
"placeholder-yellow-700",
"placeholder-yellow-800",
"placeholder-yellow-900",
"placeholder-green-100",
"placeholder-green-200",
"placeholder-green-300",
"placeholder-green-400",
"placeholder-green-500",
"placeholder-green-600",
"placeholder-green-700",
"placeholder-green-800",
"placeholder-green-900",
"placeholder-teal-100",
"placeholder-teal-200",
"placeholder-teal-300",
"placeholder-teal-400",
"placeholder-teal-500",
"placeholder-teal-600",
"placeholder-teal-700",
"placeholder-teal-800",
"placeholder-teal-900",
"placeholder-blue-100",
"placeholder-blue-200",
"placeholder-blue-300",
"placeholder-blue-400",
"placeholder-blue-500",
"placeholder-blue-600",
"placeholder-blue-700",
"placeholder-blue-800",
"placeholder-blue-900",
"placeholder-indigo-100",
"placeholder-indigo-200",
"placeholder-indigo-300",
"placeholder-indigo-400",
"placeholder-indigo-500",
"placeholder-indigo-600",
"placeholder-indigo-700",
"placeholder-indigo-800",
"placeholder-indigo-900",
"placeholder-purple-100",
"placeholder-purple-200",
"placeholder-purple-300",
"placeholder-purple-400",
"placeholder-purple-500",
"placeholder-purple-600",
"placeholder-purple-700",
"placeholder-purple-800",
"placeholder-purple-900",
"placeholder-pink-100",
"placeholder-pink-200",
"placeholder-pink-300",
"placeholder-pink-400",
"placeholder-pink-500",
"placeholder-pink-600",
"placeholder-pink-700",
"placeholder-pink-800",
"placeholder-pink-900",
"placeholder-left",
"placeholder-center",
"placeholder-right",
"placeholder-justify",
"underline",
"line-through",
"no-underline",
"uppercase",
"lowercase",
"capitalize",
"normal-case",
"break-normal",
"break-words",
"break-all",
"truncate",
"whitespace-normal",
"whitespace-no-wrap",
"whitespace-pre",
"whitespace-pre-line",
"whitespace-pre-wrap",
"align-baseline",
"align-top",
"align-middle",
"align-bottom",
"align-text-top",
"align-text-bottom",
"list-none",
"list-disc",
"list-decimal",
"list-inside",
"list-outside",
"bg-fixed",
"bg-local",
"bg-scroll",
"bg-transparent",
"bg-black",
"bg-white",
"bg-gray-100",
"bg-gray-200",
"bg-gray-300",
"bg-gray-400",
"bg-gray-500",
"bg-gray-600",
"bg-gray-700",
"bg-gray-800",
"bg-gray-900",
"bg-red-100",
"bg-red-200",
"bg-red-300",
"bg-red-400",
"bg-red-500",
"bg-red-600",
"bg-red-700",
"bg-red-800",
"bg-red-900",
"bg-orange-100",
"bg-orange-200",
"bg-orange-300",
"bg-orange-400",
"bg-orange-500",
"bg-orange-600",
"bg-orange-700",
"bg-orange-800",
"bg-orange-900",
"bg-yellow-100",
"bg-yellow-200",
"bg-yellow-300",
"bg-yellow-400",
"bg-yellow-500",
"bg-yellow-600",
"bg-yellow-700",
"bg-yellow-800",
"bg-yellow-900",
"bg-green-100",
"bg-green-200",
"bg-green-300",
"bg-green-400",
"bg-green-500",
"bg-green-600",
"bg-green-700",
"bg-green-800",
"bg-green-900",
"bg-teal-100",
"bg-teal-200",
"bg-teal-300",
"bg-teal-400",
"bg-teal-500",
"bg-teal-600",
"bg-teal-700",
"bg-teal-800",
"bg-teal-900",
"bg-blue-100",
"bg-blue-200",
"bg-blue-300",
"bg-blue-400",
"bg-blue-500",
"bg-blue-600",
"bg-blue-700",
"bg-blue-800",
"bg-blue-900",
"bg-indigo-100",
"bg-indigo-200",
"bg-indigo-300",
"bg-indigo-400",
"bg-indigo-500",
"bg-indigo-600",
"bg-indigo-700",
"bg-indigo-800",
"bg-indigo-900",
"bg-purple-100",
"bg-purple-200",
"bg-purple-300",
"bg-purple-400",
"bg-purple-500",
"bg-purple-600",
"bg-purple-700",
"bg-purple-800",
"bg-purple-900",
"bg-pink-100",
"bg-pink-200",
"bg-pink-300",
"bg-pink-400",
"bg-pink-500",
"bg-pink-600",
"bg-pink-700",
"bg-pink-800",
"bg-pink-900",
"bg-bottom",
"bg-center",
"bg-left",
"bg-left-bottom",
"bg-left-top",
"bg-right",
"bg-right-bottom",
"bg-right-top",
"bg-top",
"bg-repeat",
"bg-no-repeat",
"bg-repeat-x",
"bg-repeat-y",
"bg-repeat-round",
"bg-repeat-space",
"bg-auto",
"bg-cover",
"bg-contain",
"border",
"border-0",
"border-2",
"border-4",
"border-8",
"border-t",
"border-t-0",
"border-t-2",
"border-t-4",
"border-t-8",
"border-b",
"border-b-0",
"border-b-2",
"border-b-4",
"border-b-8",
"border-l",
"border-l-0",
"border-l-2",
"border-l-4",
"border-l-8",
"border-r",
"border-r-0",
"border-r-2",
"border-r-4",
"border-r-8",
"border-collapse",
"border-separate",
"border-transparent",
"border-black",
"border-white",
"border-gray-100",
"border-gray-200",
"border-gray-300",
"border-gray-400",
"border-gray-500",
"border-gray-600",
"border-gray-700",
"border-gray-800",
"border-gray-900",
"border-red-100",
"border-red-200",
"border-red-300",
"border-red-400",
"border-red-500",
"border-red-600",
"border-red-700",
"border-red-800",
"border-red-900",
"border-orange-100",
"border-orange-200",
"border-orange-300",
"border-orange-400",
"border-orange-500",
"border-orange-600",
"border-orange-700",
"border-orange-800",
"border-orange-900",
"border-yellow-100",
"border-yellow-200",
"border-yellow-300",
"border-yellow-400",
"border-yellow-500",
"border-yellow-600",
"border-yellow-700",
"border-yellow-800",
"border-yellow-900",
"border-green-100",
"border-green-200",
"border-green-300",
"border-green-400",
"border-green-500",
"border-green-600",
"border-green-700",
"border-green-800",
"border-green-900",
"border-teal-100",
"border-teal-200",
"border-teal-300",
"border-teal-400",
"border-teal-500",
"border-teal-600",
"border-teal-700",
"border-teal-800",
"border-teal-900",
"border-blue-100",
"border-blue-200",
"border-blue-300",
"border-blue-400",
"border-blue-500",
"border-blue-600",
"border-blue-700",
"border-blue-800",
"border-blue-900",
"border-indigo-100",
"border-indigo-200",
"border-indigo-300",
"border-indigo-400",
"border-indigo-500",
"border-indigo-600",
"border-indigo-700",
"border-indigo-800",
"border-indigo-900",
"border-purple-100",
"border-purple-200",
"border-purple-300",
"border-purple-400",
"border-purple-500",
"border-purple-600",
"border-purple-700",
"border-purple-800",
"border-purple-900",
"border-pink-100",
"border-pink-200",
"border-pink-300",
"border-pink-400",
"border-pink-500",
"border-pink-600",
"border-pink-700",
"border-pink-800",
"border-pink-900",
"border-solid",
"border-dashed",
"border-dotted",
"border-double",
"border-none",
"rounded-none",
"rounded-sm",
"rounded",
"rounded-lg",
"rounded-full",
"rounded-t-none",
"rounded-t-sm",
"rounded-t",
"rounded-t-lg",
"rounded-t-full",
"rounded-b-none",
"rounded-b-sm",
"rounded-b",
"rounded-b-lg",
"rounded-b-full",
"rounded-l-none",
"rounded-l-sm",
"rounded-l",
"rounded-l-lg",
"rounded-l-full",
"rounded-r-none",
"rounded-r-sm",
"rounded-r",
"rounded-r-lg",
"rounded-r-full",
"rounded-tl-none",
"rounded-tl-sm",
"rounded-tl",
"rounded-tl-lg",
"rounded-tl-full",
"rounded-tr-none",
"rounded-tr-sm",
"rounded-tr",
"rounded-tr-lg",
"rounded-tr-full",
"rounded-bl-none",
"rounded-bl-sm",
"rounded-bl",
"rounded-bl-lg",
"rounded-bl-full",
"rounded-br-none",
"rounded-br-sm",
"rounded-br",
"rounded-br-lg",
"rounded-br-full",
"shadow",
"shadow-md",
"shadow-lg",
"shadow-xl",
"shadow-2xl",
"shadow-inner",
"shadow-outline",
"shadow-none",
"outline-none",
"opacity-0",
"opacity-25",
"opacity-50",
"opacity-75",
"opacity-100",
"table-auto",
"table-fixed",
"appearance-none",
"cursor-auto",
"cursor-default",
"cursor-pointer",
"cursor-wait",
"cursor-move",
"cursor-not-allowed",
"pointer-events-none",
"pointer-events-auto",
"resize-none",
"resize",
"resize-x",
"resize-y",
"select-none",
"select-text",
"select-all",
"select-auto",
"sr-only",
"not-sr-only",
"fill-current",
"stroke-current"
],
"description": "Sort order: A string array that determines the default sort order.",
"scope": "window"
},
"tailwindCSS.headwind.classRegex": {
"type": "object",
"default": {
"jade": [
{
"regex": "\\.([\\._a-zA-Z0-9\\-]+)",
"separator": "\\.",
"replacement": "."
},
"\\bclass\\s*=\\s*[\\\"\\']([\\._a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\']"
],
"html": "\\bclass\\s*=\\s*[\\\"\\']([\\._a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\']",
"css": "\\B@apply\\s+([\\._a-zA-Z0-9\\s\\-\\:\\/]+);",
"javascript": [
"(?:\\b(?:class(?:Name)?|tw)\\s*=\\s*(?:(?:{([\\w\\d\\s!?_\\-:/${}()[\\]\"'`,]+)})|([\"'`][\\.\\w\\d\\s_\\-:/]+[\"'`])))",
"(?:[\"'`]([\\.\\w\\d\\s_\\-:/${}()[\\]]+)[\"'`])"
],
"javascriptreact": [
"(?:\\b(?:class(?:Name)?|tw)\\s*=\\s*(?:(?:{([\\w\\d\\s!?_\\-:/${}()[\\]\"'`,]+)})|([\"'`][\\w\\d\\s_\\-:/]+[\"'`])))",
"(?:[\"'`]([\\.\\w\\d\\s_\\-:/${}()[\\]]+)[\"'`])"
],
"typescript": [
"(?:\\b(?:class(?:Name)?|tw)\\s*=\\s*(?:(?:{([\\w\\d\\s!?_\\-:/${}()[\\]\"'`,]+)})|([\"'`][\\w\\d\\s_\\-:/]+[\"'`])))",
"(?:[\"'`]([\\.\\w\\d\\s_\\-:/${}()[\\]]+)[\"'`])"
],
"typescriptreact": [
"(?:\\b(?:class(?:Name)?|tw)\\s*=\\s*(?:(?:{([\\w\\d\\s!?_\\-:/${}()[\\]\"'`,]+)})|([\"'`][\\w\\d\\s_\\-:/]+[\"'`])))",
"(?:[\"'`]([\\.\\w\\d\\s_\\-:/${}()[\\]]+)[\"'`])"
]
},
"description": "An object with language IDs as keys and their values determining the regex to search for Tailwind CSS classes.",
"scope": "window"
},
"tailwindCSS.headwind.runOnSave": {
"type": "boolean",
"default": false,
"description": "A flag that controls whether or not Headwind will sort your Tailwind CSS classes on save.",
"scope": "window"
},
"tailwindCSS.headwind.removeDuplicates": {
"default": true,
"description": "A flag that controls whether or not Headwind will remove duplicate Tailwind CSS classes.",
"type": "boolean",
"scope": "window"
},
"tailwindCSS.headwind.prependCustomClasses": {
"default": false,
"description": "A flag that controls whether or not Headwind will move custom CSS classes before (true) or after (false) the Tailwind CSS classes.",
"type": "boolean",
"scope": "window"
},
"tailwindCSS.headwind.customTailwindPrefix": {
"default": "",
"description": "If the Tailwind Prefix function is used, this can be specified here (e.g. tw-).",
"type": "string",
"scope": "window"
}
}
},
"commands": [
{
"command": "tailwindCSS.showOutput",
"title": "Tailwind CSS: Show Output"
},
{
"command": "tailwindCSS.headwind.sortTailwindClasses",
"title": "Headwind: Sort Tailwind CSS Classes"
}
]
},
"dependencies": {
"@tailwindcss/language-server": "^0.14.29",
"minimatch": "^5.0.1",
"normalize-path": "^3.0.0",
"rustywind": "^0.7.1"
},
"packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447"
}
================================================
FILE: src/config.ts
================================================
import { workspace } from 'coc.nvim';
export function getConfigTailwindCssEnable() {
return workspace.getConfiguration('tailwindCSS').get<boolean>('enable');
}
export function getConfigCustomServerPath() {
return workspace.getConfiguration('tailwindCSS').get<string>('custom.serverPath', '');
}
export function getConfigExcludePatterns(): string[] {
return workspace.getConfiguration('tailwindCSS').get<string[]>('files.exclude', []);
}
================================================
FILE: src/constants.ts
================================================
// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-server/src/lib/constants.ts
export const CONFIG_GLOB = '{tailwind,tailwind.config,tailwind.*.config,tailwind.config.*}.{js,cjs,ts,mjs}';
export const PACKAGE_LOCK_GLOB = '{package-lock.json,yarn.lock,pnpm-lock.yaml}';
export const CSS_GLOB = '*.{css,scss,sass,less,pcss}';
================================================
FILE: src/headwind/headwindFeature.ts
================================================
import { commands, ExtensionContext, OutputChannel, Range, workspace } from 'coc.nvim';
import { buildMatchers, getTextMatch, sortClassString } from './headwindUtils';
export type LangConfig =
| string
| string[]
| { regex?: string | string[]; separator?: string; replacement?: string }
| undefined;
const config = workspace.getConfiguration();
const langConfig: { [key: string]: LangConfig | LangConfig[] } = config.get('tailwindCSS.headwind.classRegex') || {};
const sortOrder = config.get('tailwindCSS.headwind.defaultSortOrder');
const customTailwindPrefixConfig = config.get('tailwindCSS.headwind.customTailwindPrefix');
const customTailwindPrefix = typeof customTailwindPrefixConfig === 'string' ? customTailwindPrefixConfig : '';
const shouldRemoveDuplicatesConfig = config.get('tailwindCSS.headwind.removeDuplicates');
const shouldRemoveDuplicates = typeof shouldRemoveDuplicatesConfig === 'boolean' ? shouldRemoveDuplicatesConfig : true;
const shouldPrependCustomClassesConfig = config.get('tailwindCSS.headwind.prependCustomClasses');
const shouldPrependCustomClasses =
typeof shouldPrependCustomClassesConfig === 'boolean' ? shouldPrependCustomClassesConfig : false;
let isActive = false;
export function activate(context: ExtensionContext, outputChannel: OutputChannel) {
if (isActive) {
return;
}
isActive = true;
context.subscriptions.push({
dispose() {
isActive = false;
},
});
const disposable = commands.registerCommand('tailwindCSS.headwind.sortTailwindClasses', async () => {
const doc = await workspace.document;
const editorText = doc.textDocument.getText();
const editorLangId = doc.textDocument.languageId;
outputChannel.appendLine(`\n${'#'.repeat(10)} headwind exec\n`);
outputChannel.appendLine(`editorLangId: ${editorLangId}`);
outputChannel.appendLine(`langConfig: ${JSON.stringify(langConfig[editorLangId], null, 2)}\n`);
const matchers = buildMatchers(langConfig[editorLangId] || langConfig['html']);
for (const matcher of matchers) {
getTextMatch(matcher.regex, editorText, (text, startPosition) => {
outputChannel.appendLine(`Regex: ${matcher.regex}`);
outputChannel.appendLine(`MatchText: ${text}\n`);
const endPosition = startPosition + text.length;
const range = Range.create(
doc.textDocument.positionAt(startPosition),
doc.textDocument.positionAt(endPosition),
);
const options = {
shouldRemoveDuplicates,
shouldPrependCustomClasses,
customTailwindPrefix,
separator: matcher.separator,
replacement: matcher.replacement,
};
doc.applyEdits([
{
range,
newText: sortClassString(text, Array.isArray(sortOrder) ? sortOrder : [], options),
},
]);
});
}
});
context.subscriptions.push(disposable);
// if runOnSave is enabled organize tailwind classes before saving
if (config.get('tailwindCSS.headwind.runOnSave')) {
context.subscriptions.push(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
workspace.onWillSaveTextDocument((_e) => {
commands.executeCommand('tailwindCSS.headwind.sortTailwindClasses');
}),
);
}
}
================================================
FILE: src/headwind/headwindUtils.ts
================================================
import { LangConfig } from './headwindFeature';
export interface Options {
shouldRemoveDuplicates: boolean;
shouldPrependCustomClasses: boolean;
customTailwindPrefix: string;
separator?: RegExp;
replacement?: string;
}
/**
* Sorts a string of CSS classes according to a predefined order.
* @param classString The string to sort
* @param sortOrder The default order to sort the array at
*
* @returns The sorted string
*/
export const sortClassString = (classString: string, sortOrder: string[], options: Options): string => {
let classArray = classString.split(options.separator || /\s+/g);
if (options.shouldRemoveDuplicates) {
classArray = removeDuplicates(classArray);
}
// prepend custom tailwind prefix to all tailwind sortOrder-classes
const sortOrderClone = [...sortOrder];
if (options.customTailwindPrefix.length > 0) {
for (let i = 0; i < sortOrderClone.length; i++) {
sortOrderClone[i] = options.customTailwindPrefix + sortOrderClone[i];
}
}
classArray = sortClassArray(classArray, sortOrderClone, options.shouldPrependCustomClasses);
return classArray.join(options.replacement || ' ').trim();
};
const sortClassArray = (classArray: string[], sortOrder: string[], shouldPrependCustomClasses: boolean): string[] => [
...classArray.filter((el) => shouldPrependCustomClasses && sortOrder.indexOf(el) === -1), // append the classes that were not in the sort order if configured this way
...classArray
.filter((el) => sortOrder.indexOf(el) !== -1) // take the classes that are in the sort order
.sort((a, b) => sortOrder.indexOf(a) - sortOrder.indexOf(b)), // and sort them
...classArray.filter((el) => !shouldPrependCustomClasses && sortOrder.indexOf(el) === -1), // prepend the classes that were not in the sort order if configured this way
];
const removeDuplicates = (classArray: string[]): string[] => [...new Set(classArray)];
function isArrayOfStrings(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string');
}
export type Matcher = {
regex: RegExp[];
separator?: RegExp;
replacement?: string;
};
function buildMatcher(value: LangConfig): Matcher {
if (typeof value === 'string') {
return {
regex: [new RegExp(value, 'gi')],
};
} else if (isArrayOfStrings(value)) {
return {
regex: value.map((v) => new RegExp(v, 'gi')),
};
} else if (value == undefined) {
return {
regex: [],
};
} else {
return {
regex:
typeof value.regex === 'string'
? [new RegExp(value.regex, 'gi')]
: isArrayOfStrings(value.regex)
? value.regex.map((v) => new RegExp(v, 'gi'))
: [],
separator: typeof value.separator === 'string' ? new RegExp(value.separator, 'g') : undefined,
replacement: value.replacement || value.separator,
};
}
}
export function buildMatchers(value: LangConfig | LangConfig[]): Matcher[] {
if (value == undefined) {
return [];
} else if (Array.isArray(value)) {
if (!value.length) {
return [];
} else if (!isArrayOfStrings(value)) {
return value.map((v) => buildMatcher(v));
}
}
return [buildMatcher(value)];
}
export function getTextMatch(
regexes: RegExp[],
text: string,
callback: (text: string, startPosition: number) => void,
startPosition = 0,
): void {
if (regexes.length >= 1) {
let wrapper: RegExpExecArray | null;
while ((wrapper = regexes[0].exec(text)) !== null) {
const wrapperMatch = wrapper[0];
const valueMatchIndex = wrapper.findIndex((match, idx) => idx !== 0 && match);
const valueMatch = wrapper[valueMatchIndex];
const newStartPosition = startPosition + wrapper.index + wrapperMatch.lastIndexOf(valueMatch);
if (regexes.length === 1) {
callback(valueMatch, newStartPosition);
} else {
getTextMatch(regexes.slice(1), valueMatch, callback, newStartPosition);
}
}
}
}
================================================
FILE: src/index.ts
================================================
import {
commands,
ExtensionContext,
LanguageClient,
LanguageClientOptions,
OutputChannel,
ServerOptions,
TextDocument,
Thenable,
TransportKind,
Uri,
window,
workspace,
WorkspaceFolder,
} from 'coc.nvim';
import fs from 'fs';
import path from 'path';
import minimatch from 'minimatch';
import normalizePath from 'normalize-path';
import { getConfigCustomServerPath, getConfigExcludePatterns, getConfigTailwindCssEnable } from './config';
import { CONFIG_GLOB } from './constants';
import { dedupe, equal } from './util/array';
import isObject from './util/isObject';
import { languages as defaultLanguages } from './util/languages';
import * as headwindFeature from './headwind/headwindFeature';
export type ConfigurationScope = Uri | TextDocument | WorkspaceFolder | { uri?: Uri; languageId: string };
const clients: Map<string, LanguageClient | null> = new Map();
const languages: Map<string, string[]> = new Map();
let _sortedWorkspaceFolders: string[] | undefined;
function sortedWorkspaceFolders(): string[] {
if (_sortedWorkspaceFolders === void 0) {
_sortedWorkspaceFolders = workspace.workspaceFolders
? workspace.workspaceFolders
.map((folder) => {
let result = folder.uri.toString();
if (result.charAt(result.length - 1) !== '/') {
result = result + '/';
}
return result;
})
.sort((a, b) => {
return a.length - b.length;
})
: [];
}
return _sortedWorkspaceFolders;
}
function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
const sorted = sortedWorkspaceFolders();
for (const element of sorted) {
let uri = folder.uri.toString();
if (uri.charAt(uri.length - 1) !== '/') {
uri = uri + '/';
}
if (uri.startsWith(element)) {
const workdir = workspace.getWorkspaceFolder(element);
if (workdir) {
return workdir;
}
}
}
return folder;
}
function getUserLanguages(folder?: WorkspaceFolder): Record<string, string> {
const langs = folder ? workspace.getConfiguration('tailwindCSS', folder.uri.toString()).includeLanguages : undefined;
return isObject(langs) ? langs : {};
}
function isExcluded(file: string, folder: WorkspaceFolder): boolean {
const exclude = getConfigExcludePatterns();
for (const pattern of exclude) {
if (minimatch(file, path.join(Uri.parse(folder!.uri).fsPath, pattern))) {
return true;
}
}
return false;
}
export async function activate(context: ExtensionContext) {
if (!getConfigTailwindCssEnable()) return;
let module = getConfigCustomServerPath();
if (module && fs.existsSync(module)) {
module = module;
} else {
module = context.asAbsolutePath(
path.join('node_modules', '@tailwindcss', 'language-server', 'bin', 'tailwindcss-language-server'),
);
}
const outputChannel: OutputChannel = window.createOutputChannel('tailwindcss-language-server');
context.subscriptions.push(
commands.registerCommand('tailwindCSS.showOutput', () => {
if (outputChannel) {
outputChannel.show();
}
}),
);
const configWatcher = workspace.createFileSystemWatcher(`**/${CONFIG_GLOB}`, false, true, true);
configWatcher.onDidCreate((uri) => {
let folder = workspace.getWorkspaceFolder(uri.toString());
if (!folder || isExcluded(uri.fsPath, folder)) {
return;
}
folder = getOuterMostWorkspaceFolder(folder);
bootWorkspaceClient(folder);
});
context.subscriptions.push(configWatcher);
// TODO: check if the actual language MAPPING changed
// not just the language IDs
// e.g. "plaintext" already exists but you change it from "html" to "css"
context.subscriptions.push(
workspace.onDidChangeConfiguration((event) => {
clients.forEach((client, key) => {
const folder = workspace.getWorkspaceFolder(Uri.parse(key).toString());
if (!folder) return;
if (event.affectsConfiguration('tailwindCSS.includeLanguages', folder.uri.toString())) {
const userLanguages = getUserLanguages(folder);
if (userLanguages) {
const userLanguageIds = Object.keys(userLanguages);
const newLanguages = dedupe([...defaultLanguages, ...userLanguageIds]);
if (!equal(newLanguages, languages.get(folder.uri.toString()) as any[])) {
languages.set(folder.uri.toString(), newLanguages);
if (client) {
clients.delete(folder.uri.toString());
client.stop();
bootWorkspaceClient(folder);
}
}
}
}
});
}),
);
function bootWorkspaceClient(folder: WorkspaceFolder) {
if (clients.has(folder.uri.toString())) {
return;
}
clients.set(folder.uri.toString(), null);
if (!languages.has(folder.uri.toString())) {
languages.set(folder.uri.toString(), dedupe([...defaultLanguages, ...Object.keys(getUserLanguages(folder))]));
}
const configuration = {
edidor: workspace.getConfiguration('editor'),
tailwindCSS: workspace.getConfiguration('tailwindCSS'),
};
// MEMO: // If defaultValue (null) is omitted, LS will output the following log
// ----
// Unable to resolve "undefined": unknown node or service
const inspectPort = configuration.tailwindCSS.get('inspectPort', null);
// register headwind
headwindFeature.activate(context, outputChannel);
const serverOptions: ServerOptions = {
run: {
module,
transport: TransportKind.ipc,
options: { execArgv: inspectPort === null ? [] : [`--inspect=${inspectPort}`] },
},
debug: {
module,
transport: TransportKind.ipc,
options: {
execArgv: ['--nolazy', `--inspect=${6011 + clients.size}`],
},
},
};
const languageObj = languages.get(folder.uri.toString());
if (!languageObj) return;
const documentSelector = languageObj.map((language) => ({
scheme: 'file',
language,
pattern: normalizePath(`${Uri.parse(folder!.uri).fsPath.replace(/[\[\]\{\}]/g, '?')}/**/*`),
}));
const clientOptions: LanguageClientOptions = {
documentSelector,
diagnosticCollectionName: 'tailwindcss-language-server',
workspaceFolder: folder,
outputChannel: outputChannel,
synchronize: {
fileEvents: workspace.createFileSystemWatcher(CONFIG_GLOB),
},
middleware: {
workspace: {
configuration: (params) => {
return params.items.map(({ section, scopeUri }) => {
let scope: ConfigurationScope = folder;
if (scopeUri) {
const doc = workspace.textDocuments.find((doc) => doc.uri.toString() === scopeUri);
if (doc) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
scope = {
languageId: doc.languageId,
};
}
}
return workspace.getConfiguration(section);
});
},
},
},
initializationOptions: {
userLanguages: getUserLanguages(folder),
},
};
const client = new LanguageClient('tailwindCSS', 'Tailwind CSS Language Server', serverOptions, clientOptions);
// MEMO: Define a dummy onRequest.
//
// eslint-disable-next-line @typescript-eslint/no-unused-vars
client.onRequest('@/tailwindCSS/getDocumentSymbols', async ({ uri }) => {
// MEMO: In coc.nvim, vscode.executeDocumentSymbolProvider is not provided by executeCommand.
//return commands.executeCommand<SymbolInformation[]>('vscode.executeDocumentSymbolProvider', Uri.parse(uri));
});
client.start();
clients.set(folder.uri.toString(), client);
}
async function didOpenTextDocument(document: TextDocument): Promise<void> {
const uri = Uri.parse(document.uri);
if (uri.scheme !== 'file') return;
// Stop folder search for unsupported languageId (filetype) [for coc-tailwindcss3]
const supportedLanguages: string[] = [];
supportedLanguages.push(...defaultLanguages);
const includeLanguages = workspace.getConfiguration('tailwindCSS').get<string[]>('includeLanguages');
if (includeLanguages) supportedLanguages.push(...Object.keys(includeLanguages));
if (!supportedLanguages.includes(document.languageId)) return;
let folder = workspace.getWorkspaceFolder(document.uri);
// Files outside a folder can't be handled. This might depend on the language.
// Single file languages like JSON might handle files outside the workspace folders.
if (!folder) {
return;
}
// If we have nested workspace folders we only start a server on the outer most workspace folder.
folder = getOuterMostWorkspaceFolder(folder);
bootWorkspaceClient(folder);
}
context.subscriptions.push(workspace.onDidOpenTextDocument(didOpenTextDocument));
workspace.textDocuments.forEach(didOpenTextDocument);
context.subscriptions.push(
workspace.onDidChangeWorkspaceFolders((event) => {
_sortedWorkspaceFolders = undefined;
for (const folder of event.removed) {
const client = clients.get(folder.uri.toString());
if (client) {
clients.delete(folder.uri.toString());
client.stop();
}
}
}),
);
}
export async function deactivate(): Promise<void> {
const promises: Thenable<void>[] = [];
for (const client of clients.values()) {
if (client) {
promises.push(client.stop());
}
}
return Promise.all(promises).then(() => undefined);
}
================================================
FILE: src/util/array.ts
================================================
// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-service/src/util/array.ts
export function dedupe<T>(arr: Array<T>): Array<T> {
return arr.filter((value, index, self) => self.indexOf(value) === index);
}
export function equal(a: any[], b: any[]): boolean {
if (a === b) return true;
if (a.length !== b.length) return false;
const aSorted = a.concat().sort();
const bSorted = b.concat().sort();
for (let i = 0; i < aSorted.length; ++i) {
if (aSorted[i] !== bSorted[i]) return false;
}
return true;
}
================================================
FILE: src/util/isObject.ts
================================================
// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-service/src/util/isObject.ts
export default function isObject(variable: any): boolean {
return Object.prototype.toString.call(variable) === '[object Object]';
}
================================================
FILE: src/util/languages.ts
================================================
export const htmlLanguages = [
'aspnetcorerazor',
'astro',
'astro-markdown',
'blade',
'django-html',
'edge',
'ejs',
'erb',
'gohtml',
'GoHTML',
'haml',
'handlebars',
'hbs',
'html',
'HTML (Eex)',
'HTML (EEx)',
'html-eex',
'htmldjango',
'jade',
'leaf',
'liquid',
'markdown',
'mdx',
'mustache',
'njk',
'nunjucks',
'phoenix-heex',
'php',
'razor',
'slim',
'twig',
];
export const cssLanguages = ['css', 'less', 'postcss', 'sass', 'scss', 'stylus', 'sugarss', 'tailwindcss'];
export const jsLanguages = [
'javascript',
'javascriptreact',
'reason',
'rescript',
'typescript',
'typescriptreact',
'glimmer-js',
'glimmer-ts',
];
export const specialLanguages = ['vue', 'svelte'];
// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-service/src/util/languages.ts
export const languages = [...cssLanguages, ...htmlLanguages, ...jsLanguages, ...specialLanguages];
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"target": "es2017",
"lib": ["es2017", "es2018", "DOM"],
"module": "commonjs",
"declaration": false,
"sourceMap": true,
"outDir": "lib",
"strict": true,
"moduleResolution": "node",
"noImplicitAny": false,
"esModuleInterop": true
},
"include": ["src"]
}
gitextract_tl3tduef/ ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── esbuild.js ├── package.json ├── src/ │ ├── config.ts │ ├── constants.ts │ ├── headwind/ │ │ ├── headwindFeature.ts │ │ └── headwindUtils.ts │ ├── index.ts │ └── util/ │ ├── array.ts │ ├── isObject.ts │ └── languages.ts └── tsconfig.json
SYMBOL INDEX (26 symbols across 8 files)
FILE: esbuild.js
function start (line 2) | async function start(watch) {
method onRebuild (line 21) | onRebuild(error) {
FILE: src/config.ts
function getConfigTailwindCssEnable (line 3) | function getConfigTailwindCssEnable() {
function getConfigCustomServerPath (line 7) | function getConfigCustomServerPath() {
function getConfigExcludePatterns (line 11) | function getConfigExcludePatterns(): string[] {
FILE: src/constants.ts
constant CONFIG_GLOB (line 3) | const CONFIG_GLOB = '{tailwind,tailwind.config,tailwind.*.config,tailwin...
constant PACKAGE_LOCK_GLOB (line 4) | const PACKAGE_LOCK_GLOB = '{package-lock.json,yarn.lock,pnpm-lock.yaml}';
constant CSS_GLOB (line 5) | const CSS_GLOB = '*.{css,scss,sass,less,pcss}';
FILE: src/headwind/headwindFeature.ts
type LangConfig (line 4) | type LangConfig =
function activate (line 27) | function activate(context: ExtensionContext, outputChannel: OutputChanne...
FILE: src/headwind/headwindUtils.ts
type Options (line 3) | interface Options {
function isArrayOfStrings (line 48) | function isArrayOfStrings(value: unknown): value is string[] {
type Matcher (line 52) | type Matcher = {
function buildMatcher (line 58) | function buildMatcher(value: LangConfig): Matcher {
function buildMatchers (line 85) | function buildMatchers(value: LangConfig | LangConfig[]): Matcher[] {
function getTextMatch (line 98) | function getTextMatch(
FILE: src/index.ts
type ConfigurationScope (line 31) | type ConfigurationScope = Uri | TextDocument | WorkspaceFolder | { uri?:...
function sortedWorkspaceFolders (line 37) | function sortedWorkspaceFolders(): string[] {
function getOuterMostWorkspaceFolder (line 56) | function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): Workspace...
function getUserLanguages (line 73) | function getUserLanguages(folder?: WorkspaceFolder): Record<string, stri...
function isExcluded (line 78) | function isExcluded(file: string, folder: WorkspaceFolder): boolean {
function activate (line 90) | async function activate(context: ExtensionContext) {
function deactivate (line 287) | async function deactivate(): Promise<void> {
FILE: src/util/array.ts
function dedupe (line 3) | function dedupe<T>(arr: Array<T>): Array<T> {
function equal (line 7) | function equal(a: any[], b: any[]): boolean {
FILE: src/util/isObject.ts
function isObject (line 2) | function isObject(variable: any): boolean {
Condensed preview — 16 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (81K chars).
[
{
"path": ".eslintrc.js",
"chars": 568,
"preview": "module.exports = {\n env: {\n node: true,\n },\n parser: '@typescript-eslint/parser',\n extends: ['plugin:@typescript-"
},
{
"path": ".gitignore",
"chars": 2222,
"preview": "lib\n_ref\n\n### Generated by gibo (https://github.com/simonwhitaker/gibo)\n### https://raw.github.com/github/gitignore/d0b8"
},
{
"path": ".npmignore",
"chars": 145,
"preview": "src\nnode_modules\ntsconfig.json\n*.map\n.tags\n.DS_Store\nwebpack.config.js\nesbuild.js\nyarn.lock\nyarn-error.log\n.github\n.esli"
},
{
"path": "LICENSE",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2022 yaegassy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
},
{
"path": "README.md",
"chars": 6286,
"preview": "# coc-tailwindcss3\n\n> fork from [vscode-tailwindcss](https://github.com/tailwindlabs/tailwindcss-intellisense/tree/maste"
},
{
"path": "esbuild.js",
"chars": 796,
"preview": "/* eslint-disable @typescript-eslint/no-var-requires */\nasync function start(watch) {\n await require('esbuild').build({"
},
{
"path": "package.json",
"chars": 43451,
"preview": "{\n \"name\": \"@yaegassy/coc-tailwindcss3\",\n \"version\": \"0.6.14\",\n \"description\": \"Intelligent Tailwind CSS tooling for "
},
{
"path": "src/config.ts",
"chars": 446,
"preview": "import { workspace } from 'coc.nvim';\n\nexport function getConfigTailwindCssEnable() {\n return workspace.getConfiguratio"
},
{
"path": "src/constants.ts",
"chars": 385,
"preview": "// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-server/sr"
},
{
"path": "src/headwind/headwindFeature.ts",
"chars": 3292,
"preview": "import { commands, ExtensionContext, OutputChannel, Range, workspace } from 'coc.nvim';\nimport { buildMatchers, getTextM"
},
{
"path": "src/headwind/headwindUtils.ts",
"chars": 3989,
"preview": "import { LangConfig } from './headwindFeature';\n\nexport interface Options {\n shouldRemoveDuplicates: boolean;\n shouldP"
},
{
"path": "src/index.ts",
"chars": 9699,
"preview": "import {\n commands,\n ExtensionContext,\n LanguageClient,\n LanguageClientOptions,\n OutputChannel,\n ServerOptions,\n "
},
{
"path": "src/util/array.ts",
"chars": 586,
"preview": "// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-service/s"
},
{
"path": "src/util/isObject.ts",
"chars": 274,
"preview": "// PORTING: https://github.com/tailwindlabs/tailwindcss-intellisense/blob/master/packages/tailwindcss-language-service/s"
},
{
"path": "src/util/languages.ts",
"chars": 990,
"preview": "export const htmlLanguages = [\n 'aspnetcorerazor',\n 'astro',\n 'astro-markdown',\n 'blade',\n 'django-html',\n 'edge',"
},
{
"path": "tsconfig.json",
"chars": 321,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"es2017\",\n \"lib\": [\"es2017\", \"es2018\", \"DOM\"],\n \"module\": \"commonjs\",\n \""
}
]
About this extraction
This page contains the full source code of the yaegassy/coc-tailwindcss3 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 16 files (72.8 KB), approximately 18.6k tokens, and a symbol index with 26 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.