diff --git a/src/lsp/providers/codeActionProvider/index.ts b/src/lsp/providers/codeActionProvider/index.ts index 5bced1dd72db162e0e77354f2d931bcdf89927a5..959411af30b8194c3b3cf7531771774e91424ead 100644 --- a/src/lsp/providers/codeActionProvider/index.ts +++ b/src/lsp/providers/codeActionProvider/index.ts @@ -11,7 +11,7 @@ import { isWithinRange } from '../../util/isWithinRange' import { getClassNameParts } from '../../util/getClassNameAtPosition' const dlv = require('dlv') import dset from 'dset' -import { removeRangesFromString } from '../../util/removeRangesFromString' +import { removeRangeFromString } from '../../util/removeRangeFromString' import detectIndent from 'detect-indent' import { cssObjToAst } from '../../util/cssObjToAst' import isObject from '../../../util/isObject' @@ -26,7 +26,6 @@ isUtilityConflictsDiagnostic, UtilityConflictsDiagnostic, } from '../diagnostics/types' import { flatten, dedupeBy } from '../../../util/array' -import { joinWithAnd } from '../../util/joinWithAnd' async function getDiagnosticsFromCodeActionParams( state: State, @@ -175,11 +174,25 @@ diagnostic: UtilityConflictsDiagnostic ): Promise { return [ { - title: `Delete ${joinWithAnd( - diagnostic.otherClassNames.map( - (otherClassName) => `'${otherClassName.className}'` - ) - )}`, + title: `Delete '${diagnostic.className.className}'`, + kind: CodeActionKind.QuickFix, + diagnostics: [diagnostic], + edit: { + changes: { + [params.textDocument.uri]: [ + { + range: diagnostic.className.classList.range, + newText: removeRangeFromString( + diagnostic.className.classList.classList, + diagnostic.className.relativeRange + ), + }, + ], + }, + }, + }, + { + title: `Delete '${diagnostic.otherClassName.className}'`, kind: CodeActionKind.QuickFix, diagnostics: [diagnostic], edit: { @@ -187,11 +200,9 @@ changes: { [params.textDocument.uri]: [ { range: diagnostic.className.classList.range, - newText: removeRangesFromString( + newText: removeRangeFromString( diagnostic.className.classList.classList, - diagnostic.otherClassNames.map( - (otherClassName) => otherClassName.relativeRange - ) + diagnostic.otherClassName.relativeRange ), }, ], @@ -312,7 +323,7 @@ ...(totalClassNamesInClassList > 1 ? [ { range: diagnostic.className.classList.range, - newText: removeRangesFromString( + newText: removeRangeFromString( diagnostic.className.classList.classList, diagnostic.className.relativeRange ), diff --git a/src/lsp/providers/diagnostics/diagnosticsProvider.ts b/src/lsp/providers/diagnostics/diagnosticsProvider.ts index 1c98a391dfe30bdfd994e1c474d0c5251b6fdc42..56362d5488cc8776715de6feac2096c57149f255 100644 --- a/src/lsp/providers/diagnostics/diagnosticsProvider.ts +++ b/src/lsp/providers/diagnostics/diagnosticsProvider.ts @@ -29,7 +29,6 @@ InvalidConfigPathDiagnostic, InvalidTailwindDirectiveDiagnostic, AugmentedDiagnostic, } from './types' -import { joinWithAnd } from '../../util/joinWithAnd' function getInvalidApplyDiagnostics( state: State, @@ -105,58 +104,45 @@ classLists.forEach((classList) => { const classNames = getClassNamesInClassList(classList) classNames.forEach((className, index) => { - let decls = getClassNameDecls(state, className.className) - if (!decls) return - - let properties = Object.keys(decls) - let meta = getClassNameMeta(state, className.className) - let otherClassNames = classNames.filter((_className, i) => i !== index) + otherClassNames.forEach((otherClassName) => { + let decls = getClassNameDecls(state, className.className) + if (!decls) return - let conflictingClassNames = otherClassNames.filter((otherClassName) => { let otherDecls = getClassNameDecls(state, otherClassName.className) - if (!otherDecls) return false + if (!otherDecls) return + let meta = getClassNameMeta(state, className.className) let otherMeta = getClassNameMeta(state, otherClassName.className) - return ( - equal(properties, Object.keys(otherDecls)) && + if ( + equal(Object.keys(decls), Object.keys(otherDecls)) && !Array.isArray(meta) && !Array.isArray(otherMeta) && equal(meta.context, otherMeta.context) && equal(meta.pseudo, otherMeta.pseudo) - ) - }) - - if (conflictingClassNames.length === 0) return - - diagnostics.push({ - code: DiagnosticKind.UtilityConflicts, - className, - otherClassNames: conflictingClassNames, - range: className.range, - severity: - severity === 'error' - ? DiagnosticSeverity.Error - : DiagnosticSeverity.Warning, - message: `'${className.className}' applies the same CSS ${ - properties.length === 1 ? 'property' : 'properties' - } as ${joinWithAnd( - conflictingClassNames.map( - (conflictingClassName) => `'${conflictingClassName.className}'` - ) - )}.`, - relatedInformation: conflictingClassNames.map( - (conflictingClassName) => { - return { - message: conflictingClassName.className, - location: { - uri: document.uri, - range: conflictingClassName.range, + ) { + diagnostics.push({ + code: DiagnosticKind.UtilityConflicts, + className, + otherClassName, + range: className.range, + severity: + severity === 'error' + ? DiagnosticSeverity.Error + : DiagnosticSeverity.Warning, + message: `'${className.className}' and '${otherClassName.className}' apply the same CSS properties.`, + relatedInformation: [ + { + message: otherClassName.className, + location: { + uri: document.uri, + range: otherClassName.range, + }, }, - } - } - ), + ], + }) + } }) }) }) diff --git a/src/lsp/providers/diagnostics/types.ts b/src/lsp/providers/diagnostics/types.ts index 00fc979386386abbad601bf15ba40c8be6cd12c0..684cda7c824aa7cc382c6ffed6b30010d31ddc97 100644 --- a/src/lsp/providers/diagnostics/types.ts +++ b/src/lsp/providers/diagnostics/types.ts @@ -13,7 +13,7 @@ export type UtilityConflictsDiagnostic = Diagnostic & { code: DiagnosticKind.UtilityConflicts className: DocumentClassName - otherClassNames: DocumentClassName[] + otherClassName: DocumentClassName } export function isUtilityConflictsDiagnostic( diff --git a/src/lsp/util/joinWithAnd.ts b/src/lsp/util/joinWithAnd.ts deleted file mode 100644 index 2b2efb716afd1394a91dd44fc6f16c05d053b438..0000000000000000000000000000000000000000 --- a/src/lsp/util/joinWithAnd.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function joinWithAnd(strings: string[]): string { - return strings.reduce((acc, cur, i) => { - if (i === 0) { - return cur - } - if (strings.length > 1 && i === strings.length - 1) { - return `${acc} and ${cur}` - } - return `${acc}, ${cur}` - }, '') -} diff --git a/src/lsp/util/removeRangeFromString.ts b/src/lsp/util/removeRangeFromString.ts new file mode 100644 index 0000000000000000000000000000000000000000..7479373ced8326e6a6429b1c0642560a13fc076a --- /dev/null +++ b/src/lsp/util/removeRangeFromString.ts @@ -0,0 +1,16 @@ +import { Range } from 'vscode-languageserver' +import lineColumn from 'line-column' + +export function removeRangeFromString(str: string, range: Range): string { + let finder = lineColumn(str + '\n', { origin: 0 }) + let start = finder.toIndex(range.start.line, range.start.character) + let end = finder.toIndex(range.end.line, range.end.character) + for (let i = start - 1; i >= 0; i--) { + if (/\s/.test(str.charAt(i))) { + start = i + } else { + break + } + } + return (str.substr(0, start) + str.substr(end)).trim() +} diff --git a/src/lsp/util/removeRangesFromString.ts b/src/lsp/util/removeRangesFromString.ts deleted file mode 100644 index f97d62b95b2aecae61c0e4195fba475af541a17e..0000000000000000000000000000000000000000 --- a/src/lsp/util/removeRangesFromString.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Range } from 'vscode-languageserver' -import lineColumn from 'line-column' -import { ensureArray } from '../../util/array' - -export function removeRangesFromString( - str: string, - rangeOrRanges: Range | Range[] -): string { - let ranges = ensureArray(rangeOrRanges) - let finder = lineColumn(str + '\n', { origin: 0 }) - let indexRanges: { start: number; end: number }[] = [] - - ranges.forEach((range) => { - let start = finder.toIndex(range.start.line, range.start.character) - let end = finder.toIndex(range.end.line, range.end.character) - for (let i = start - 1; i >= 0; i--) { - if (/\s/.test(str.charAt(i))) { - start = i - } else { - break - } - } - indexRanges.push({ start, end }) - }) - - indexRanges.sort((a, b) => a.start - b.start) - - let result = '' - let i = 0 - - indexRanges.forEach((indexRange) => { - result += str.substring(i, indexRange.start) - i = indexRange.end - }) - - result += str.substring(i) - - return result.trim() -}