From 8cc378822b3fe4e582eb51fcd8fb78d383aa5b20 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 21 Apr 2024 23:14:27 +0300 Subject: [PATCH] fix: fix invalid linked editing ranges sometimes feat: Add custom code action to fix closing/opening tag name from the current location --- .../codeActions/custom/fixClosingTagName.ts | 25 +++++++++++++++++++ .../extended/declareMissingProperties.ts | 13 ---------- typescript/src/codeActions/getCodeActions.ts | 2 ++ typescript/src/decorateLinkedEditing.ts | 11 ++++++-- 4 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 typescript/src/codeActions/custom/fixClosingTagName.ts diff --git a/typescript/src/codeActions/custom/fixClosingTagName.ts b/typescript/src/codeActions/custom/fixClosingTagName.ts new file mode 100644 index 0000000..0748017 --- /dev/null +++ b/typescript/src/codeActions/custom/fixClosingTagName.ts @@ -0,0 +1,25 @@ +import { matchParents } from '../../utils' +import { CodeAction } from '../getCodeActions' + +export default { + id: 'fixOppositeTagName', + kind: 'quickfix', + name: 'Fix opposite tag name', + tryToApply(sourceFile, position, range, node) { + const elem = matchParents(node, ['Identifier', 'JsxOpeningElement']) ?? matchParents(node, ['Identifier', 'JsxClosingElement']) + if (!elem) return + const tagNamesDiffers = elem.parent.openingElement.tagName.getText() !== elem.parent.closingElement.tagName.getText() + if (tagNamesDiffers) { + const isCurrentlyAtOpening = elem.parent.openingElement === elem + const oppositeElem = isCurrentlyAtOpening ? elem.parent.closingElement.tagName : elem.parent.openingElement.tagName + return [ + { + start: oppositeElem.getStart(), + length: oppositeElem.getWidth(), + newText: elem.tagName.getText(), + }, + ] + } + return + }, +} satisfies CodeAction diff --git a/typescript/src/codeActions/extended/declareMissingProperties.ts b/typescript/src/codeActions/extended/declareMissingProperties.ts index 5471ad7..57ef306 100644 --- a/typescript/src/codeActions/extended/declareMissingProperties.ts +++ b/typescript/src/codeActions/extended/declareMissingProperties.ts @@ -83,16 +83,3 @@ export default { return }, } as ExtendedCodeAction - -const testCode = () => { - const tester = (code: string) => { - // ^ - problem location in which quickfix needs to be tested (applied) - // | - cursor position after quickfix is applied - // [[...]] - applied part of the code - /* TODO */ - } - - tester(/* ts */ ` - const b = ({ b, ^a }: { b[[, a/*|*/]] }) => {} - `) -} diff --git a/typescript/src/codeActions/getCodeActions.ts b/typescript/src/codeActions/getCodeActions.ts index c6ffe52..e69509f 100644 --- a/typescript/src/codeActions/getCodeActions.ts +++ b/typescript/src/codeActions/getCodeActions.ts @@ -10,6 +10,7 @@ import declareMissingProperties from './extended/declareMissingProperties' import { renameParameterToNameFromType, renameAllParametersToNameFromType } from './custom/renameParameterToNameFromType' import addDestructure_1 from './custom/addDestructure/addDestructure' import fromDestructure_1 from './custom/fromDestructure/fromDestructure' +import fixClosingTagName from './custom/fixClosingTagName' const codeActions: CodeAction[] = [ addDestructure_1, @@ -19,6 +20,7 @@ const codeActions: CodeAction[] = [ splitDeclarationAndInitialization, renameParameterToNameFromType, renameAllParametersToNameFromType, + fixClosingTagName, ] const extendedCodeActions: ExtendedCodeAction[] = [declareMissingProperties] diff --git a/typescript/src/decorateLinkedEditing.ts b/typescript/src/decorateLinkedEditing.ts index e262a11..244d8d7 100644 --- a/typescript/src/decorateLinkedEditing.ts +++ b/typescript/src/decorateLinkedEditing.ts @@ -23,10 +23,17 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, lastLinkedEditingRangeRequest.fileName === fileName ) { lastLinkedEditingRangeRequest.pos = position - lastLinkedEditingRangeRequest.result.ranges[0]!.length++ + const startRange = lastLinkedEditingRangeRequest.result.ranges[0]! + const endRange = lastLinkedEditingRangeRequest.result.ranges[1]! + startRange.length++ lastLinkedEditingRangeRequest.result.ranges[1]!.start++ + lastLinkedEditingRangeRequest.result.ranges[1]!.length++ - return lastLinkedEditingRangeRequest.result + const leadingText = fileContent.slice(startRange.start, startRange.start + startRange.length) + const endingText = fileContent.slice(endRange.start, endRange.start + endRange.length) + if (leadingText === endingText) { + return lastLinkedEditingRangeRequest.result + } } lastLinkedEditingRangeRequest = undefined