diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index dea0ebc4c43e1..f060940454132 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -175,7 +175,7 @@ registerRefactor(refactorNameForMoveToFile, { } /** If the start/end nodes of the selection are inside a block like node do not show the `Move to file` code action * This condition is used in order to show less often the `Move to file` code action */ - if (context.endPosition !== undefined) { + if (context.triggerReason === "implicit" && context.endPosition !== undefined) { const startNodeAncestor = findAncestor(getTokenAtPosition(file, context.startPosition), isBlockLike); const endNodeAncestor = findAncestor(getTokenAtPosition(file, context.endPosition), isBlockLike); if (startNodeAncestor && !isSourceFile(startNodeAncestor) && endNodeAncestor && !isSourceFile(endNodeAncestor)) { diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index 2665239e10483..37cdd35d07019 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -5,9 +5,13 @@ import { Debug, Diagnostics, emptyArray, + findAncestor, getLineAndCharacterOfPosition, getLocaleSpecificMessage, + getTokenAtPosition, hostGetCanonicalFileName, + isBlockLike, + isSourceFile, LanguageServiceHost, last, ModuleKind, @@ -40,6 +44,16 @@ registerRefactor(refactorName, { kinds: [moveToNewFileAction.kind], getAvailableActions: function getRefactorActionsToMoveToNewFile(context): readonly ApplicableRefactorInfo[] { const statements = getStatementsToMove(context); + + const file = context.file; + if (context.triggerReason === "implicit" && context.endPosition !== undefined) { + const startNodeAncestor = findAncestor(getTokenAtPosition(file, context.startPosition), isBlockLike); + const endNodeAncestor = findAncestor(getTokenAtPosition(file, context.endPosition), isBlockLike); + if (startNodeAncestor && !isSourceFile(startNodeAncestor) && endNodeAncestor && !isSourceFile(endNodeAncestor)) { + return emptyArray; + } + } + if (context.preferences.allowTextChangesInNewFiles && statements) { const file = context.file; const affectedTextRange = { diff --git a/tests/cases/fourslash/moveToNewFile_prologueDirectives4.ts b/tests/cases/fourslash/moveToNewFile_prologueDirectives4.ts index d30090bbe3df3..bfadbfd3e2e7a 100644 --- a/tests/cases/fourslash/moveToNewFile_prologueDirectives4.ts +++ b/tests/cases/fourslash/moveToNewFile_prologueDirectives4.ts @@ -5,15 +5,4 @@ //// [|"use strict";|] ////} -verify.moveToNewFile({ - newFileContents: { - "/a.ts": -``, - - "/foo.ts": -`function foo() { - "use strict"; -} -`, - }, -}); +verify.noMoveToNewFile(); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailable1.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailable1.ts new file mode 100644 index 0000000000000..ab0689f481304 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailable1.ts @@ -0,0 +1,18 @@ +/// + +////namespace ns { +//// /*a*/export function fn() { +//// } +//// fn(); +//// /*b*/ +////} + +goTo.select("a", "b"); +verify.not.refactorAvailable("Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailable2.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailable2.ts new file mode 100644 index 0000000000000..3b191a7c6df85 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailable2.ts @@ -0,0 +1,20 @@ +/// + +/////*a*/ +////namespace ns { +//// export function fn() { +//// } +//// fn(); +////} +/////*b*/ + +goTo.select("a", "b"); +verify.refactorAvailable("Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); + diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit1.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit1.ts new file mode 100644 index 0000000000000..cb552982f9c49 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit1.ts @@ -0,0 +1,19 @@ +/// + + +//// export /*a*//*b*/function fn() { +//// console.log('Hello') +//// } +//// fn(); + + + +goTo.select("a", "b"); +verify.refactorAvailableForTriggerReason("implicit", "Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit2.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit2.ts new file mode 100644 index 0000000000000..7391bbe48ef70 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit2.ts @@ -0,0 +1,16 @@ +/// + +//// export function fn(){ +//// console.log('Hello')/*a*//*b*/ +//// } +//// fn(); + +goTo.select("a", "b"); +verify.not.refactorAvailableForTriggerReason("implicit", "Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit3.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit3.ts new file mode 100644 index 0000000000000..d1b5606214842 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailableImplicit3.ts @@ -0,0 +1,23 @@ +/// + + +////class ns /*a*//*b*/extends ap{ +//// constructor() {} +//// +//// export function fn() { +//// console.log("Hello"); +//// } +//// fn(); +//// +////} + + +goTo.select("a", "b"); +verify.refactorAvailableForTriggerReason("implicit", "Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked1.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked1.ts new file mode 100644 index 0000000000000..2e360588fb510 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked1.ts @@ -0,0 +1,16 @@ +/// + +//// export function fn(){ +//// console.log('Hello')/*a*//*b*/ +//// } +//// fn(); + +goTo.select("a", "b"); +verify.refactorAvailableForTriggerReason("invoked", "Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked2.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked2.ts new file mode 100644 index 0000000000000..904e6cf96f351 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked2.ts @@ -0,0 +1,23 @@ +/// + + +////class ns extends ap{ +//// constructor() {} +//// +//// export function fn() { +//// console.log("Hello"); /*a*//*b*/ +//// } +//// fn(); +//// +////} + + +goTo.select("a", "b"); +verify.refactorAvailableForTriggerReason("invoked", "Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true); diff --git a/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked3.ts b/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked3.ts new file mode 100644 index 0000000000000..7476fe09db6e9 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_refactorAvailableInvoked3.ts @@ -0,0 +1,20 @@ +/// + + + +//// export function fn() { +//// /*a*/console.log("Hello"); /*b*/ +//// } +//// fn(); + + + +goTo.select("a", "b"); +verify.refactorAvailableForTriggerReason("invoked", "Move to a new file", +/*actionName*/ undefined, +/*actionDescription*/ undefined, +/*kind*/ undefined, + { + allowTextChangesInNewFiles: true + }, +/*includeInteractiveActions*/ true);