initial commit
commit
6d1a8b2772
|
@ -0,0 +1,4 @@
|
||||||
|
out
|
||||||
|
node_modules
|
||||||
|
.vscode-test/
|
||||||
|
.vsix
|
|
@ -0,0 +1,28 @@
|
||||||
|
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Extension",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "${execPath}",
|
||||||
|
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
|
||||||
|
"stopOnEntry": false,
|
||||||
|
"sourceMaps": true,
|
||||||
|
"outFiles": [ "${workspaceRoot}/out/**/*.js" ],
|
||||||
|
"preLaunchTask": "npm: watch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Extension Tests",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "${execPath}",
|
||||||
|
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
|
||||||
|
"stopOnEntry": false,
|
||||||
|
"sourceMaps": true,
|
||||||
|
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
|
||||||
|
"preLaunchTask": "npm: watch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"out": false // set this to true to hide the "out" folder with the compiled JS files
|
||||||
|
},
|
||||||
|
"search.exclude": {
|
||||||
|
"out": true // set this to false to include "out" folder in search results
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch",
|
||||||
|
"problemMatcher": "$tsc-watch",
|
||||||
|
"isBackground": true,
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
.vscode/**
|
||||||
|
.vscode-test/**
|
||||||
|
out/test/**
|
||||||
|
out/**/*.map
|
||||||
|
src/**
|
||||||
|
.gitignore
|
||||||
|
tsconfig.json
|
||||||
|
vsc-extension-quickstart.md
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "vscode-tailwind",
|
||||||
|
"displayName": "vscode-tailwind",
|
||||||
|
"description": "",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publisher": "bradlc",
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.20.0"
|
||||||
|
},
|
||||||
|
"categories": ["Other"],
|
||||||
|
"activationEvents": [
|
||||||
|
"workspaceContains:**/{tailwind,tailwind.config,.tailwindrc}.js"
|
||||||
|
],
|
||||||
|
"main": "./out/extension",
|
||||||
|
"contributes": {},
|
||||||
|
"scripts": {
|
||||||
|
"vscode:prepublish": "npm run compile",
|
||||||
|
"compile": "tsc -p ./",
|
||||||
|
"watch": "tsc -watch -p ./",
|
||||||
|
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||||
|
"test": "npm run compile && node ./node_modules/vscode/bin/test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^7.0.43",
|
||||||
|
"typescript": "^2.6.1",
|
||||||
|
"vscode": "^1.1.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dlv": "^1.1.1",
|
||||||
|
"tailwind-class-names": "^0.5.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
import * as vscode from 'vscode'
|
||||||
|
import { join } from 'path'
|
||||||
|
const tailwindClassNames = require('tailwind-class-names')
|
||||||
|
// const tailwindClassNames = require('/Users/brad/Code/tailwind-class-names/dist')
|
||||||
|
const dlv = require('dlv')
|
||||||
|
|
||||||
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
|
if (!vscode.workspace.name) return
|
||||||
|
|
||||||
|
const configFile = await vscode.workspace.findFiles(
|
||||||
|
'{tailwind,tailwind.config,.tailwindrc}.js',
|
||||||
|
'**/node_modules/**',
|
||||||
|
1
|
||||||
|
)
|
||||||
|
if (!configFile) return
|
||||||
|
|
||||||
|
const plugin = join(
|
||||||
|
vscode.workspace.workspaceFolders[0].uri.fsPath,
|
||||||
|
'node_modules',
|
||||||
|
'tailwindcss'
|
||||||
|
)
|
||||||
|
|
||||||
|
let tw
|
||||||
|
|
||||||
|
try {
|
||||||
|
tw = await tailwindClassNames(
|
||||||
|
configFile[0].fsPath,
|
||||||
|
{
|
||||||
|
tree: true,
|
||||||
|
strings: true
|
||||||
|
},
|
||||||
|
plugin
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const separator = dlv(tw.config, 'options.separator', ':')
|
||||||
|
|
||||||
|
if (separator !== ':') return
|
||||||
|
|
||||||
|
const items = createItems(tw.classNames, separator, tw.config)
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
createCompletionItemProvider(
|
||||||
|
items,
|
||||||
|
['typescriptreact', 'javascript', 'javascriptreact'],
|
||||||
|
/\btw`([^`]*)$/,
|
||||||
|
['`', ' ', separator],
|
||||||
|
tw.config
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
createCompletionItemProvider(
|
||||||
|
items,
|
||||||
|
['css', 'sass', 'scss'],
|
||||||
|
/@apply ([^;}]*)$/,
|
||||||
|
['.', separator],
|
||||||
|
tw.config,
|
||||||
|
'.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
createCompletionItemProvider(
|
||||||
|
items,
|
||||||
|
[
|
||||||
|
'html',
|
||||||
|
'jade',
|
||||||
|
'razor',
|
||||||
|
'php',
|
||||||
|
'blade',
|
||||||
|
'vue',
|
||||||
|
'twig',
|
||||||
|
'markdown',
|
||||||
|
'erb',
|
||||||
|
'handlebars',
|
||||||
|
'ejs',
|
||||||
|
// for jsx
|
||||||
|
'typescriptreact',
|
||||||
|
'javascript',
|
||||||
|
'javascriptreact'
|
||||||
|
],
|
||||||
|
/\bclass(Name)?=["']([^"']*)/, // /\bclass(Name)?=(["'])(?!.*?\2)/
|
||||||
|
["'", '"', ' ', separator],
|
||||||
|
tw.config
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deactivate() {}
|
||||||
|
|
||||||
|
function createCompletionItemProvider(
|
||||||
|
items,
|
||||||
|
languages: string[],
|
||||||
|
regex: RegExp,
|
||||||
|
triggerCharacters: string[],
|
||||||
|
config,
|
||||||
|
prefix = ''
|
||||||
|
): vscode.Disposable {
|
||||||
|
return vscode.languages.registerCompletionItemProvider(
|
||||||
|
languages,
|
||||||
|
{
|
||||||
|
provideCompletionItems(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
): vscode.CompletionItem[] {
|
||||||
|
const range: vscode.Range = new vscode.Range(
|
||||||
|
new vscode.Position(Math.max(position.line - 5, 0), 0),
|
||||||
|
position
|
||||||
|
)
|
||||||
|
const text: string = document.getText(range)
|
||||||
|
|
||||||
|
let p = prefix
|
||||||
|
const separator = config.options.separator || ':'
|
||||||
|
|
||||||
|
const matches = text.match(regex)
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
const parts = matches[matches.length - 1].split(' ')
|
||||||
|
const str = parts[parts.length - 1]
|
||||||
|
|
||||||
|
const pth = str
|
||||||
|
.replace(new RegExp(`${separator}`, 'g'), '.')
|
||||||
|
.replace(/\.$/, '')
|
||||||
|
.replace(/^\./, '')
|
||||||
|
.replace(/\./g, '.children.')
|
||||||
|
|
||||||
|
if (pth !== '') {
|
||||||
|
const itms = dlv(items, pth)
|
||||||
|
if (itms) {
|
||||||
|
return prefixItems(itms.children, str, prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefixItems(items, str, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...triggerCharacters
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function prefixItems(items, str, prefix) {
|
||||||
|
const addPrefix =
|
||||||
|
typeof prefix !== 'undefined' && prefix !== '' && str === prefix
|
||||||
|
|
||||||
|
return Object.keys(items).map(x => {
|
||||||
|
const item = items[x].item
|
||||||
|
if (addPrefix) {
|
||||||
|
item.filterText = item.insertText = `${prefix}${item.label}`
|
||||||
|
} else {
|
||||||
|
item.filterText = item.insertText = item.label
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function depthOf(obj) {
|
||||||
|
if (typeof obj !== 'object') return 0
|
||||||
|
|
||||||
|
let level = 1
|
||||||
|
|
||||||
|
for (let key in obj) {
|
||||||
|
if (!obj.hasOwnProperty(key)) continue
|
||||||
|
|
||||||
|
if (typeof obj[key] === 'object') {
|
||||||
|
const depth = depthOf(obj[key]) + 1
|
||||||
|
level = Math.max(depth, level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return level
|
||||||
|
}
|
||||||
|
|
||||||
|
function createItems(classNames, separator, config, parent = '') {
|
||||||
|
let items = {}
|
||||||
|
|
||||||
|
Object.keys(classNames).forEach(key => {
|
||||||
|
if (depthOf(classNames[key]) === 0) {
|
||||||
|
const item = new vscode.CompletionItem(
|
||||||
|
key,
|
||||||
|
vscode.CompletionItemKind.Constant
|
||||||
|
)
|
||||||
|
if (key !== 'container' && key !== 'group') {
|
||||||
|
if (parent) {
|
||||||
|
item.detail = classNames[key].replace(
|
||||||
|
new RegExp(`:${parent} \{(.*?)\}`),
|
||||||
|
'$1'
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
item.detail = classNames[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items[key] = {
|
||||||
|
item
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(key)
|
||||||
|
const item = new vscode.CompletionItem(
|
||||||
|
`${key}${separator}`,
|
||||||
|
vscode.CompletionItemKind.Constant
|
||||||
|
)
|
||||||
|
item.command = { title: '', command: 'editor.action.triggerSuggest' }
|
||||||
|
if (key === 'hover' || key === 'focus' || key === 'active') {
|
||||||
|
item.detail = `:${key}`
|
||||||
|
} else if (key === 'group-hover') {
|
||||||
|
item.detail = '.group:hover &'
|
||||||
|
} else if (
|
||||||
|
config.screens &&
|
||||||
|
Object.keys(config.screens).indexOf(key) !== -1
|
||||||
|
) {
|
||||||
|
item.detail = `@media (min-width: ${config.screens[key]})`
|
||||||
|
}
|
||||||
|
items[key] = {
|
||||||
|
item,
|
||||||
|
children: createItems(classNames[key], separator, config, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es6",
|
||||||
|
"outDir": "out",
|
||||||
|
"lib": [
|
||||||
|
"es6"
|
||||||
|
],
|
||||||
|
"sourceMap": true,
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
".vscode-test"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue