diff --git a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts index 309b3800b..f4b7c8aee 100644 --- a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts +++ b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts @@ -401,6 +401,10 @@ export class SvelteSnapshotFragment implements SnapshotFragment { return this.parent.moduleScriptInfo; } + get originalText() { + return this.parent.getText(); + } + getOriginalPosition(pos: Position): Position { return this.mapper.getOriginalPosition(pos); } diff --git a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts index 8f1647631..2aa6f3771 100644 --- a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts @@ -139,6 +139,13 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { edit.span.length -= 1; range = mapRangeToOriginal(fragment, convertRange(fragment, edit.span)); range.end.character += 1; + if ( + fragment instanceof SvelteSnapshotFragment && + getLineAtPosition(range.end, fragment.originalText).length <= range.end.character + ) { + range.end.line += 1; + range.end.character = 0; + } } return range; diff --git a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts index c1d9632ab..874deb7a6 100644 --- a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts @@ -317,8 +317,8 @@ describe('CodeActionsProvider', () => { line: 4 }, end: { - character: 21, - line: 4 + character: 0, + line: 5 } } } @@ -392,8 +392,8 @@ describe('CodeActionsProvider', () => { character: 2 }, end: { - line: 7, - character: 23 + line: 8, + character: 0 } } } @@ -475,13 +475,13 @@ describe('CodeActionsProvider', () => { { newText: '', range: { - end: { - character: 37, - line: 7 - }, start: { character: 2, line: 7 + }, + end: { + character: 0, + line: 8 } } } @@ -499,6 +499,116 @@ describe('CodeActionsProvider', () => { ]); }); + it('organizes imports which changes nothing (one import)', async () => { + const { provider, document } = setup('organize-imports-unchanged1.svelte'); + + const codeActions = await provider.getCodeActions( + document, + Range.create(Position.create(1, 4), Position.create(1, 5)), // irrelevant + { + diagnostics: [], + only: [CodeActionKind.SourceOrganizeImports] + } + ); + (codeActions[0]?.edit?.documentChanges?.[0])?.edits.forEach( + (edit) => (edit.newText = harmonizeNewLines(edit.newText)) + ); + + assert.deepStrictEqual(codeActions, [ + { + edit: { + documentChanges: [ + { + edits: [ + { + newText: "import { c } from './c';\n", + range: { + end: { + character: 0, + line: 2 + }, + start: { + character: 2, + line: 1 + } + } + } + ], + textDocument: { + uri: getUri('organize-imports-unchanged1.svelte'), + version: null + } + } + ] + }, + kind: 'source.organizeImports', + title: 'Organize Imports' + } + ]); + }); + + it('organizes imports which changes nothing (two imports)', async () => { + const { provider, document } = setup('organize-imports-unchanged2.svelte'); + + const codeActions = await provider.getCodeActions( + document, + Range.create(Position.create(1, 4), Position.create(1, 5)), // irrelevant + { + diagnostics: [], + only: [CodeActionKind.SourceOrganizeImports] + } + ); + (codeActions[0]?.edit?.documentChanges?.[0])?.edits.forEach( + (edit) => (edit.newText = harmonizeNewLines(edit.newText)) + ); + + assert.deepStrictEqual(codeActions, [ + { + edit: { + documentChanges: [ + { + edits: [ + { + newText: + "import { c } from './c';\n import { d } from './d';\n", + range: { + end: { + character: 0, + line: 2 + }, + start: { + character: 2, + line: 1 + } + } + }, + { + newText: '', + range: { + end: { + character: 0, + line: 3 + }, + start: { + character: 0, + line: 2 + } + } + } + ], + textDocument: { + uri: getUri('organize-imports-unchanged2.svelte'), + version: null + } + } + ] + }, + kind: 'source.organizeImports', + title: 'Organize Imports' + } + ]); + }); + it('should do extract into const refactor', async () => { const { provider, document } = setup('codeactions.svelte'); diff --git a/packages/language-server/test/plugins/typescript/testfiles/code-actions/organize-imports-unchanged1.svelte b/packages/language-server/test/plugins/typescript/testfiles/code-actions/organize-imports-unchanged1.svelte new file mode 100644 index 000000000..741a2895c --- /dev/null +++ b/packages/language-server/test/plugins/typescript/testfiles/code-actions/organize-imports-unchanged1.svelte @@ -0,0 +1,6 @@ + + +{c} diff --git a/packages/language-server/test/plugins/typescript/testfiles/code-actions/organize-imports-unchanged2.svelte b/packages/language-server/test/plugins/typescript/testfiles/code-actions/organize-imports-unchanged2.svelte new file mode 100644 index 000000000..a90a5852f --- /dev/null +++ b/packages/language-server/test/plugins/typescript/testfiles/code-actions/organize-imports-unchanged2.svelte @@ -0,0 +1,7 @@ + + +{c}{d}