Home

tailwind-ctp-intellisense @master - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tree log patch
refactor diagnostics and add types
Brad Cornes <bradlc41@gmail.com>
4 years ago
5 changed files, 274 additions(+), 95 deletions(-)
M src/lsp/providers/codeActionProvider/index.ts -> src/lsp/providers/codeActionProvider/index.ts
diff --git a/src/lsp/providers/codeActionProvider/index.ts b/src/lsp/providers/codeActionProvider/index.ts
index 19d724e27e2e2fe641eceadbea635c44cf65eccd..28b51444d56fb61000f2e34b32affdfdd19e4f01 100644
--- a/src/lsp/providers/codeActionProvider/index.ts
+++ b/src/lsp/providers/codeActionProvider/index.ts
@@ -4,39 +4,92 @@   CodeActionParams,
   CodeActionKind,
   Range,
   TextEdit,
+} from 'vscode-languageserver'
+import { State } from '../../util/state'
+import { findLast } from '../../util/find'
+import { isWithinRange } from '../../util/isWithinRange'
+import { getClassNameParts } from '../../util/getClassNameAtPosition'
+const dlv = require('dlv')
+import dset from 'dset'
+import { removeRangeFromString } from '../../util/removeRangeFromString'
+import detectIndent from 'detect-indent'
+import {
   Diagnostic,
+import {
 } from 'vscode-languageserver'
+export function provideCodeActions(
 import { State } from '../../util/state'
+  CodeAction,
 import { findLast, findClassNamesInRange } from '../../util/find'
 import {
+  state: State,
 import {
+  CodeAction,
 import { getClassNameParts } from '../../util/getClassNameAtPosition'
+  CodeAction,
 const dlv = require('dlv')
+  CodeAction,
 import dset from 'dset'
+  CodeAction,
 import { removeRangeFromString } from '../../util/removeRangeFromString'
 import {
+import { State } from '../../util/state'
+  state: State,
   TextEdit,
+  state: State,
+  params: CodeActionParams,
+  CodeAction,
 import { cssObjToAst } from '../../util/cssObjToAst'
+  CodeAction,
 import isObject from '../../../util/isObject'
 import {
+  Diagnostic,
+  let diagnostics = await getDiagnostics(state, document, only)
+import {
 import { State } from '../../util/state'
   CodeAction,
+  CodeAction,
+  CodeAction,
   state: State,
+  CodeAction,
   params: CodeActionParams
   CodeAction,
+  CodeAction,
   CodeActionParams,
+      })
+  CodeAction,
   if (params.context.diagnostics.length === 0) {
   CodeAction,
+  CodeAction,
   Range,
+}
+
+  CodeAction,
   }
+  CodeAction,
 import {
-import { State } from '../../util/state'
   CodeAction,
+  CodeAction,
+): Promise<CodeAction[]> {
+  params: CodeActionParams
   Diagnostic,
+  CodeAction,
     params.context.diagnostics
   CodeAction,
+  CodeAction,
 import { State } from '../../util/state'
+
+  CodeAction,
         if (diagnostic.code === 'invalidApply') {
+    state,
+    params,
+    codes
+  )
+
+  return Promise.all(
+    diagnostics
+      .map((diagnostic) => {
+        if (isInvalidApplyDiagnostic(diagnostic)) {
           return provideInvalidApplyCodeAction(state, params, diagnostic)
         }
 
@@ -135,36 +188,17 @@
 async function provideInvalidApplyCodeAction(
   state: State,
   params: CodeActionParams,
-  diagnostic: Diagnostic
+  diagnostic: InvalidApplyDiagnostic
 ): Promise<CodeAction> {
   let document = state.editor.documents.get(params.textDocument.uri)
   let documentText = document.getText()
   const { postcss } = state.modules
   let change: TextEdit
 
-  let documentClassNames = findClassNamesInRange(
-import { isWithinRange } from '../../util/isWithinRange'
   CodeAction,
-import { isWithinRange } from '../../util/isWithinRange'
   CodeActionParams,
-      start: {
-        line: Math.max(0, diagnostic.range.start.line - 10),
-        character: 0,
-import { isWithinRange } from '../../util/isWithinRange'
   Diagnostic,
 import {
-import isObject from '../../../util/isObject'
-    },
-    'css'
-  )
-  let documentClassName = documentClassNames.find((className) =>
-    isWithinRange(diagnostic.range.start, className.range)
-  )
-  if (!documentClassName) {
-    return null
-  }
-  let totalClassNamesInClassList = documentClassName.classList.classList.split(
-import {
   if (params.context.diagnostics.length === 0) {
   ).length
 
@@ -197,7 +231,7 @@             let ast = classNameToAst(
               state,
               className,
               rule.selector,
-              documentClassName.classList.important
+              diagnostic.className.classList.important
             )
 
             if (!ast) {
@@ -263,13 +297,13 @@         [params.textDocument.uri]: [
           ...(totalClassNamesInClassList > 1
             ? [
                 {
-
+): Promise<CodeAction[]> {
 import { State } from '../../util/state'
                   newText: removeRangeFromString(
   CodeAction,
+  CodeActionKind,
-import {
   CodeAction,
-  CodeAction,
+          kind: CodeActionKind.QuickFix,
                   ),
                 },
               ]
I src/lsp/providers/diagnostics/types.ts
diff --git a/src/lsp/providers/diagnostics/types.ts b/src/lsp/providers/diagnostics/types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..684cda7c824aa7cc382c6ffed6b30010d31ddc97
--- /dev/null
+++ b/src/lsp/providers/diagnostics/types.ts
@@ -0,0 +1,82 @@
+import { Diagnostic } from 'vscode-languageserver'
+import { DocumentClassName, DocumentClassList } from '../../util/state'
+
+export enum DiagnosticKind {
+  UtilityConflicts = 'utilityConflicts',
+  InvalidApply = 'invalidApply',
+  InvalidScreen = 'invalidScreen',
+  InvalidVariant = 'invalidVariant',
+  InvalidConfigPath = 'invalidConfigPath',
+  InvalidTailwindDirective = 'invalidTailwindDirective',
+}
+
+export type UtilityConflictsDiagnostic = Diagnostic & {
+  code: DiagnosticKind.UtilityConflicts
+  className: DocumentClassName
+  otherClassName: DocumentClassName
+}
+
+export function isUtilityConflictsDiagnostic(
+  diagnostic: AugmentedDiagnostic
+): diagnostic is UtilityConflictsDiagnostic {
+  return diagnostic.code === DiagnosticKind.UtilityConflicts
+}
+
+export type InvalidApplyDiagnostic = Diagnostic & {
+  code: DiagnosticKind.InvalidApply
+  className: DocumentClassName
+}
+
+export function isInvalidApplyDiagnostic(
+  diagnostic: AugmentedDiagnostic
+): diagnostic is InvalidApplyDiagnostic {
+  return diagnostic.code === DiagnosticKind.InvalidApply
+}
+
+export type InvalidScreenDiagnostic = Diagnostic & {
+  code: DiagnosticKind.InvalidScreen
+}
+
+export function isInvalidScreenDiagnostic(
+  diagnostic: AugmentedDiagnostic
+): diagnostic is InvalidScreenDiagnostic {
+  return diagnostic.code === DiagnosticKind.InvalidScreen
+}
+
+export type InvalidVariantDiagnostic = Diagnostic & {
+  code: DiagnosticKind.InvalidVariant
+}
+
+export function isInvalidVariantDiagnostic(
+  diagnostic: AugmentedDiagnostic
+): diagnostic is InvalidVariantDiagnostic {
+  return diagnostic.code === DiagnosticKind.InvalidVariant
+}
+
+export type InvalidConfigPathDiagnostic = Diagnostic & {
+  code: DiagnosticKind.InvalidConfigPath
+}
+
+export function isInvalidConfigPathDiagnostic(
+  diagnostic: AugmentedDiagnostic
+): diagnostic is InvalidConfigPathDiagnostic {
+  return diagnostic.code === DiagnosticKind.InvalidConfigPath
+}
+
+export type InvalidTailwindDirectiveDiagnostic = Diagnostic & {
+  code: DiagnosticKind.InvalidTailwindDirective
+}
+
+export function isInvalidTailwindDirectiveDiagnostic(
+  diagnostic: AugmentedDiagnostic
+): diagnostic is InvalidTailwindDirectiveDiagnostic {
+  return diagnostic.code === DiagnosticKind.InvalidTailwindDirective
+}
+
+export type AugmentedDiagnostic =
+  | UtilityConflictsDiagnostic
+  | InvalidApplyDiagnostic
+  | InvalidScreenDiagnostic
+  | InvalidVariantDiagnostic
+  | InvalidConfigPathDiagnostic
+  | InvalidTailwindDirectiveDiagnostic
M src/lsp/providers/diagnosticsProvider.ts -> src/lsp/providers/diagnostics/diagnosticsProvider.ts
diff --git a/src/lsp/providers/diagnosticsProvider.ts b/src/lsp/providers/diagnostics/diagnosticsProvider.ts
rename from src/lsp/providers/diagnosticsProvider.ts
rename to src/lsp/providers/diagnostics/diagnosticsProvider.ts
index f6fa9092b7d83df2bd1647b212f32527f8c843ee..56362d5488cc8776715de6feac2096c57149f255 100644
--- a/src/lsp/providers/diagnosticsProvider.ts
+++ b/src/lsp/providers/diagnostics/diagnosticsProvider.ts
@@ -1,122 +1,141 @@
+  document: TextDocument,
 import {
+  document: TextDocument,
   TextDocument,
+  document: TextDocument,
   Diagnostic,
-  DiagnosticSeverity,
-  Range,
-} from 'vscode-languageserver'
-import { State, Settings } from '../util/state'
-import { isCssDoc } from '../util/css'
 import {
   findClassNamesInRange,
   findClassListsInDocument,
   getClassNamesInClassList,
   findAll,
   indexToPosition,
-import {
+  document: TextDocument,
   DiagnosticSeverity,
-import {
+  document: TextDocument,
   Range,
-import {
+  document: TextDocument,
 } from 'vscode-languageserver'
-import {
+  document: TextDocument,
 import { State, Settings } from '../util/state'
-import {
+  document: TextDocument,
 import { isCssDoc } from '../util/css'
 const dlv = require('dlv')
 import semver from 'semver'
   TextDocument,
+            message: `'${className.className}' and '${otherClassName.className}' apply the same CSS properties.`,
+import { absoluteRange } from '../../util/absoluteRange'
+  settings: Settings
 import {
-  TextDocument,
+  settings: Settings
   TextDocument,
-  TextDocument,
+  settings: Settings
   Diagnostic,
-  TextDocument,
+import {
+  settings: Settings
   DiagnosticSeverity,
+  DiagnosticKind,
+  UtilityConflictsDiagnostic,
+  InvalidScreenDiagnostic,
+  InvalidVariantDiagnostic,
+  InvalidConfigPathDiagnostic,
+  InvalidTailwindDirectiveDiagnostic,
+  AugmentedDiagnostic,
+): Diagnostic[] {
   TextDocument,
-  Range,
 
 function getInvalidApplyDiagnostics(
   state: State,
   document: TextDocument,
   settings: Settings
 ): Diagnostic[] {
+  Diagnostic,
   let severity = settings.lint.invalidApply
   if (severity === 'ignore') return []
 
   const classNames = findClassNamesInRange(document, undefined, 'css')
 
   Diagnostic,
+} from '../util/find'
+): Diagnostic[] {
   Range,
   Diagnostic,
+import {
 } from 'vscode-languageserver'
-      const meta = getClassNameMeta(state, className)
+
   Diagnostic,
-import { isCssDoc } from '../util/css'
+import { equal } from '../../util/array'
 
   Diagnostic,
+import { getDocumentSettings } from '../util/getDocumentSettings'
+): Diagnostic[] {
   findClassNamesInRange,
+  Diagnostic,
   TextDocument,
-} from 'vscode-languageserver'
-  DiagnosticSeverity,
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
 import {
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
   TextDocument,
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
   Diagnostic,
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
   DiagnosticSeverity,
+import { isObject } from '../../class-names/isObject'
   DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
   Range,
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
 } from 'vscode-languageserver'
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
 import { State, Settings } from '../util/state'
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
 import { isCssDoc } from '../util/css'
-  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
   findClassNamesInRange,
   Range,
+import { State, Settings } from '../util/state'
+  if (severity === 'ignore') return []
-  Range,
+  if (severity === 'ignore') return []
 import {
-  Range,
+  if (severity === 'ignore') return []
   TextDocument,
-  Range,
+  TextDocument,
   Diagnostic,
+  DiagnosticSeverity,
+  let severity = settings.lint.invalidApply
   Range,
-  DiagnosticSeverity,
-        } else {
+          className.className
-          message = `'@apply' cannot be used with '${className}' because its definition includes pseudo-selectors (${meta.pseudo
+        }' because its definition includes pseudo-selectors (${meta.pseudo
-            .map((p) => `'${p}'`)
+          .map((p) => `'${p}'`)
-            .join(', ')}).`
+          .join(', ')}).`
   Range,
-import {
+import { State, Settings } from '../util/state'
+  if (severity === 'ignore') return []
   Range,
-import { State, Settings } from '../util/state'
 
-      if (!message) return null
+    if (!message) return null
 
-  Range,
+    return {
+      code: DiagnosticKind.InvalidApply,
+  if (severity === 'ignore') return []
   findClassNamesInRange,
-} from 'vscode-languageserver'
+  const classNames = findClassNamesInRange(document, undefined, 'css')
-} from 'vscode-languageserver'
+  const classNames = findClassNamesInRange(document, undefined, 'css')
 import {
-} from 'vscode-languageserver'
+  const classNames = findClassNamesInRange(document, undefined, 'css')
   TextDocument,
-} from 'vscode-languageserver'
+  const classNames = findClassNamesInRange(document, undefined, 'css')
   Diagnostic,
-} from 'vscode-languageserver'
+  const classNames = findClassNamesInRange(document, undefined, 'css')
   DiagnosticSeverity,
-} from 'vscode-languageserver'
+  const classNames = findClassNamesInRange(document, undefined, 'css')
   Range,
-        code: 'invalidApply',
+  if (severity === 'ignore') return []
   Range,
-import { State, Settings } from '../util/state'
-    })
-    .filter(Boolean)
+  })
 
+  const classNames = findClassNamesInRange(document, undefined, 'css')
 } from 'vscode-languageserver'
-  findClassNamesInRange,
 }
 
 function getUtilityConflictDiagnostics(
@@ -124,12 +143,12 @@   state: State,
   document: TextDocument,
   settings: Settings
   Diagnostic,
-import {
+        } else {
   let severity = settings.lint.utilityConflicts
   if (severity === 'ignore') return []
 
-import { State, Settings } from '../util/state'
   Diagnostic,
+          message = `'@apply' cannot be used with '${className}' because it is nested inside of at-rules (${meta.context
   const classLists = findClassListsInDocument(state, document)
 
   classLists.forEach((classList) => {
@@ -155,6 +174,9 @@           equal(meta.context, otherMeta.context) &&
           equal(meta.pseudo, otherMeta.pseudo)
         ) {
           diagnostics.push({
+            code: DiagnosticKind.UtilityConflicts,
+            className,
+            otherClassName,
             range: className.range,
             severity:
               severity === 'error'
@@ -184,11 +206,11 @@   state: State,
   document: TextDocument,
   settings: Settings
   Diagnostic,
-import {
+      } else if (meta.pseudo && meta.pseudo.length > 0) {
   let severity = settings.lint.invalidScreen
   if (severity === 'ignore') return []
 
-import { State, Settings } from '../util/state'
+  let diagnostics: Diagnostic[] = classNames
   Diagnostic,
   let ranges: Range[] = []
 
@@ -220,6 +242,7 @@         message += ` Did you mean '${suggestion}'?`
       }
 
       diagnostics.push({
+        code: DiagnosticKind.InvalidScreen,
         range: absoluteRange(
           {
             start: indexToPosition(
@@ -247,12 +270,12 @@   state: State,
   document: TextDocument,
   settings: Settings
   Diagnostic,
-import {
+          message = `'@apply' cannot be used with '${className}' because its definition includes pseudo-selectors (${meta.pseudo
   let severity = settings.lint.invalidVariant
   if (severity === 'ignore') return []
 
-import { State, Settings } from '../util/state'
   Diagnostic,
+            .map((p) => `'${p}'`)
   let ranges: Range[] = []
 
   if (isCssDoc(state, document)) {
@@ -288,6 +311,7 @@         let variantStartIndex =
           listStartIndex + variants.slice(0, i).join('').length
 
         diagnostics.push({
+          code: DiagnosticKind.InvalidVariant,
           range: absoluteRange(
             {
               start: indexToPosition(text, variantStartIndex),
@@ -313,12 +337,12 @@   state: State,
   document: TextDocument,
   settings: Settings
   Diagnostic,
-import {
+      if (!message) return null
   let severity = settings.lint.invalidConfigPath
   if (severity === 'ignore') return []
 
-import { State, Settings } from '../util/state'
   Diagnostic,
+      return {
   let ranges: Range[] = []
 
   if (isCssDoc(state, document)) {
@@ -427,6 +451,7 @@         1 + // open paren
         match.groups.quote.length
 
       diagnostics.push({
+        code: DiagnosticKind.InvalidConfigPath,
         range: absoluteRange(
           {
             start: indexToPosition(text, startIndex),
@@ -451,12 +476,13 @@   state: State,
   document: TextDocument,
   settings: Settings
   Diagnostic,
+} from 'vscode-languageserver'
 import {
   let severity = settings.lint.invalidTailwindDirective
   if (severity === 'ignore') return []
 
-import { State, Settings } from '../util/state'
   Diagnostic,
+            ? DiagnosticSeverity.Error
   let ranges: Range[] = []
 
   if (isCssDoc(state, document)) {
@@ -494,6 +520,7 @@         }
       }
 
       diagnostics.push({
+        code: DiagnosticKind.InvalidTailwindDirective,
         range: absoluteRange(
           {
             start: indexToPosition(
@@ -516,41 +543,67 @@
   return diagnostics
 }
 
-  TextDocument,
+  Diagnostic,
 } from 'vscode-languageserver'
-import { State, Settings } from '../util/state'
+  DiagnosticSeverity,
   state: State,
   TextDocument,
+  findClassNamesInRange,
+  only: DiagnosticKind[] = [
+    DiagnosticKind.UtilityConflicts,
+    DiagnosticKind.InvalidApply,
+  Diagnostic,
     .filter(Boolean)
-  TextDocument,
+  Diagnostic,
   return diagnostics
-  TextDocument,
+  Diagnostic,
 }
-
-  TextDocument,
+  Diagnostic,
 function getUtilityConflictDiagnostics(
-  TextDocument,
+  Diagnostic,
   let severity = settings.lint.utilityConflicts
-  TextDocument,
+  Diagnostic,
   let diagnostics: Diagnostic[] = []
 function getInvalidApplyDiagnostics(
+
+      const meta = getClassNameMeta(state, className)
   DiagnosticSeverity,
 function getInvalidApplyDiagnostics(
+  TextDocument,
+      const meta = getClassNameMeta(state, className)
   Range,
-  TextDocument,
+  Diagnostic,
     const classNames = getClassNamesInClassList(classList)
+          : []),
+        ...(only.includes(DiagnosticKind.InvalidApply)
+          ? getInvalidApplyDiagnostics(state, document, settings)
+          : []),
+        ...(only.includes(DiagnosticKind.InvalidScreen)
+          ? getInvalidScreenDiagnostics(state, document, settings)
+          : []),
+      if (!meta) return null
   TextDocument,
+          ? getInvalidVariantDiagnostics(state, document, settings)
+  Diagnostic,
     classNames.forEach((className, index) => {
-  TextDocument,
+        ...(only.includes(DiagnosticKind.InvalidConfigPath)
+          ? getInvalidConfigPathDiagnostics(state, document, settings)
+      const meta = getClassNameMeta(state, className)
 import { State, Settings } from '../util/state'
+  Diagnostic,
 import { isCssDoc } from '../util/css'
+} from 'vscode-languageserver'
+          ? getInvalidTailwindDirectiveDiagnostics(state, document, settings)
+          : []),
       ]
     : []
+}
 
+export async function provideDiagnostics(state: State, document: TextDocument) {
   state.editor.connection.sendDiagnostics({
     uri: document.uri,
-  state: State,
   Diagnostic,
+          !Array.isArray(otherMeta) &&
   })
 }
 
M src/lsp/server.ts -> src/lsp/server.ts
diff --git a/src/lsp/server.ts b/src/lsp/server.ts
index 6c928e68b9df731b3b77b24aa82e85621eb5f7f1..f4b8013534ea0de51cbb9c67f30c90d3187afb76 100644
--- a/src/lsp/server.ts
+++ b/src/lsp/server.ts
@@ -32,7 +32,7 @@ import {
   provideDiagnostics,
   updateAllDiagnostics,
   clearAllDiagnostics,
-} from './providers/diagnosticsProvider'
+} from './providers/diagnostics/diagnosticsProvider'
 import { createEmitter } from '../lib/emitter'
 import { provideCodeActions } from './providers/codeActionProvider'
 
I src/lsp/util/rangesEqual.ts
diff --git a/src/lsp/util/rangesEqual.ts b/src/lsp/util/rangesEqual.ts
new file mode 100644
index 0000000000000000000000000000000000000000..220cebd50e242933d666ee7581d68e4030dd321b
--- /dev/null
+++ b/src/lsp/util/rangesEqual.ts
@@ -0,0 +1,10 @@
+import { Range } from 'vscode-languageserver'
+
+export function rangesEqual(a: Range, b: Range): boolean {
+  return (
+    a.start.line === b.start.line &&
+    a.start.character === b.start.character &&
+    a.end.line === b.end.line &&
+    a.end.character === b.end.character
+  )
+}