diff --git a/package-lock.json b/package-lock.json index f844afb78a3c31adf7b940746d88f9e90ad99f41..d3461d15178fbd81895623d655bde63ebf413264 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1034,13 +1034,6 @@ "integrity": "sha512-dOrgprHnkDaj1pmrwdcMAf0QRNQzqTB5rxJph+iIQshSmIvtgRqJ0nim8u1vvXU8iOXZrH96+M46JDFTPLingA==", "dev": true }, "lockfileVersion": 1, - "version": "7.9.6", - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@types/moo/-/moo-0.5.3.tgz", - "integrity": "sha512-PJJ/jvb5Gor8DWvXN3e75njfQyYNRz0PaFSZ3br9GfHM9N2FxvuJ/E/ytcQePJOLzHlvgFSsIJIvfUMUxWTbnA==", - "dev": true - }, - "lockfileVersion": 1, "@babel/generator": "^7.9.6", "version": "13.13.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz", @@ -4949,12 +4942,6 @@ "mkdirp": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==", - "dev": true - }, - "moo": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", - "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", "dev": true }, "ms": { diff --git a/package.json b/package.json index 139370c58cbe44bd4b75ede982513933acf9c4be..69d62d97f70770c055be6a9d69bc98fb4d3f295a 100755 --- a/package.json +++ b/package.json @@ -76,8 +76,6 @@ "devDependencies": { "@ctrl/tinycolor": "^3.1.0", "@types/mocha": "^5.2.0", "license": "MIT", -{ - "license": "MIT", "name": "vscode-tailwindcss", "@types/vscode": "^1.32.0", "@zeit/ncc": "^0.22.0", @@ -96,7 +94,6 @@ "jest": "^25.5.4", "line-column": "^1.0.2", "mitt": "^1.2.0", "mkdirp": "^1.0.3", - "moo": "^0.5.1", "pkg-up": "^3.1.0", "postcss": "^7.0.27", "postcss-selector-parser": "^6.0.2", diff --git a/src/lsp/providers/completionProvider.ts b/src/lsp/providers/completionProvider.ts index eae7546bffc68d70c05ef1ebbdd0353fac33a42d..8f2c43d8325bc847a7b05a87dc180025a647f2a9 100644 --- a/src/lsp/providers/completionProvider.ts +++ b/src/lsp/providers/completionProvider.ts @@ -12,7 +12,7 @@ import removeMeta from '../util/removeMeta' import { getColor, getColorFromValue } from '../util/color' import { isHtmlContext } from '../util/html' import { isCssContext } from '../util/css' -import { findLast } from '../util/find' +import { findLast, findJsxStrings, arrFindLast } from '../util/find' import { stringifyConfigValue, stringifyCss } from '../util/stringify' import { stringifyScreen, Screen } from '../util/screens' import isObject from '../../util/isObject' @@ -24,10 +24,6 @@ import { naturalExpand } from '../util/naturalExpand' import semver from 'semver' import { docsUrl } from '../util/docsUrl' import { ensureArray } from '../../util/array' -import { - getClassAttributeLexer, - getComputedClassAttributeLexer, -} from '../util/lexers' function completionsFromClassList( state: State, @@ -126,45 +122,38 @@ start: { line: Math.max(position.line - 10, 0), character: 0 }, end: position, }) -import removeMeta from '../util/removeMeta' CompletionItemKind, + if (match === null) { return null } - const lexer = - match[0][0] === ':' -import { State } from '../util/state' + let isSubset: boolean = false import { State } from '../util/state' -} from 'vscode-languageserver' -import { getColor, getColorFromValue } from '../util/color' + CompletionItem, -import { State } from '../util/state' + let isSubset: boolean = false import { -import { State } from '../util/state' + let isSubset: boolean = false CompletionItem, - try { -import { getColor, getColorFromValue } from '../util/color' + CompletionItemKind, CompletionItem, -import { getColor, getColorFromValue } from '../util/color' CompletionItemKind, -import { getColor, getColorFromValue } from '../util/color' + let isSubset: boolean = false CompletionParams, -import { getColor, getColorFromValue } from '../util/color' + let isSubset: boolean = false Range, - for (let i = tokens.length - 1; i >= 0; i--) { -import { getColor, getColorFromValue } from '../util/color' + filter?: (item: CompletionItem) => boolean CompletionList, - classList = tokens[i].value + classList + if (lastOpenString) { - CompletionList, + CompletionItemKind, CompletionItem, + CompletionList, -import { State } from '../util/state' + CompletionItemKind, CompletionItem, - CompletionList, } from 'vscode-languageserver' +import { State } from '../util/state' Range, - Range, - CompletionItem, return completionsFromClassList(state, classList, { start: { line: position.line, @@ -173,11 +163,22 @@ end: position, }) } import { State } from '../util/state' +import { stringifyConfigValue, stringifyCss } from '../util/stringify' + } CompletionItem, + if (rest.indexOf(match.groups.initial) !== -1) { + return null CompletionParams, + let replacementRange = { import { State } from '../util/state' + start: { ): CompletionList { +} from 'vscode-languageserver' + character: position.character - rest.length, + }, + end: position, + }) } function provideAtApplyCompletions( diff --git a/src/lsp/util/find.ts b/src/lsp/util/find.ts index bd770aa37cce04fb856e76bf21b272c6c8c4f07f..3fb04517624e5208d2b2c4f2152e3285e1bb9d8a 100644 --- a/src/lsp/util/find.ts +++ b/src/lsp/util/find.ts @@ -19,6 +19,57 @@ } return matches[matches.length - 1] } +export function arrFindLast(arr: T[], predicate: (item: T) => boolean): T { + for (let i = arr.length - 1; i >= 0; --i) { + const x = arr[i] + if (predicate(x)) { + return x + } + } + return null +} + +enum Quote { + SINGLE = "'", + DOUBLE = '"', + TICK = '`', +} +type StringInfo = { + start: number + end?: number + char: Quote +} + +export function findJsxStrings(str: string): StringInfo[] { + const chars = str.split('') + const strings: StringInfo[] = [] + let bracketCount = 0 + for (let i = 0; i < chars.length; i++) { + const char = chars[i] + if (char === '{') { + bracketCount += 1 + } else if (char === '}') { + bracketCount -= 1 + } else if ( + char === Quote.SINGLE || + char === Quote.DOUBLE || + char === Quote.TICK + ) { + let open = arrFindLast(strings, (string) => string.char === char) + if (strings.length === 0 || !open || (open && open.end)) { + strings.push({ start: i + 1, char }) + } else { + open.end = i + } + } + if (i !== 0 && bracketCount === 0) { + // end + break + } + } + return strings +} + export function findClassNamesInRange( doc: TextDocument, range: Range diff --git a/src/lsp/util/lazy.ts b/src/lsp/util/lazy.ts deleted file mode 100644 index 858dac58c1fcc51d0bddc53027a47816db0e942e..0000000000000000000000000000000000000000 --- a/src/lsp/util/lazy.ts +++ /dev/null @@ -1,19 +0,0 @@ -// https://www.codementor.io/@agustinchiappeberrini/lazy-evaluation-and-javascript-a5m7g8gs3 - -export interface Lazy { - (): T - isLazy: boolean -} - -export const lazy = (getter: () => T): Lazy => { - let evaluated: boolean = false - let _res: T = null - const res = >function (): T { - if (evaluated) return _res - _res = getter.apply(this, arguments) - evaluated = true - return _res - } - res.isLazy = true - return res -} diff --git a/src/lsp/util/lexers.ts b/src/lsp/util/lexers.ts deleted file mode 100644 index 65197b943a3ef18cb7b5ab1435c10235bca67bbe..0000000000000000000000000000000000000000 --- a/src/lsp/util/lexers.ts +++ /dev/null @@ -1,53 +0,0 @@ -import moo from 'moo' -import { lazy } from './lazy' - -const classAttributeStates: { [x: string]: moo.Rules } = { - doubleClassList: { - lbrace: { match: /(? - moo.states({ - main: { - start1: { match: '"', push: 'doubleClassList' }, - start2: { match: "'", push: 'singleClassList' }, - start3: { match: '{', push: 'interp' }, - }, - ...classAttributeStates, - }) -) - -export const getComputedClassAttributeLexer = lazy(() => - moo.states({ - main: { - quote: { match: /['"{]/, push: 'interp' }, - }, - // TODO: really this should use a different interp definition that is - // terminated correctly based on the initial quote type - ...classAttributeStates, - }) -)