Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ import {
isAwaitExpression,
isBigIntLiteral,
isBinaryExpression,
isBlock,
isBindingElement,
isBindingPattern,
isBreakOrContinueStatement,
Expand Down Expand Up @@ -592,15 +593,16 @@ export type SymbolSortTextMap = (SortText | undefined)[];

// dprint-ignore
const enum KeywordCompletionFilters {
None, // No keywords
All, // Every possible keyword (TODO: This is never appropriate)
ClassElementKeywords, // Keywords inside class body
InterfaceElementKeywords, // Keywords inside interface body
ConstructorParameterKeywords, // Keywords at constructor parameter
FunctionLikeBodyKeywords, // Keywords at function like body
None, // No keywords
All, // Every possible keyword (TODO: This is never appropriate)
ClassElementKeywords, // Keywords inside class body
InterfaceElementKeywords, // Keywords inside interface body
ConstructorParameterKeywords, // Keywords at constructor parameter
FunctionLikeBodyKeywords, // Keywords at function like body (block body)
FunctionLikeExpressionBodyKeywords, // Keywords at expression-bodied function (no `default`)
TypeAssertionKeywords,
TypeKeywords,
TypeKeyword, // Literally just `type`
TypeKeyword, // Literally just `type`
Last = TypeKeyword,
}

Expand Down Expand Up @@ -3982,7 +3984,15 @@ function getCompletionData(
}

function getGlobalCompletions(): void {
keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All;
const functionLikeContainer = tryGetFunctionLikeBodyCompletionContainer(contextToken);
if (functionLikeContainer) {
keywordFilters = functionLikeContainer.body && !isBlock(functionLikeContainer.body)
? KeywordCompletionFilters.FunctionLikeExpressionBodyKeywords
: KeywordCompletionFilters.FunctionLikeBodyKeywords;
}
else {
keywordFilters = KeywordCompletionFilters.All;
}

// Get all entities in the current scope.
completionKind = CompletionKind.Global;
Expand Down Expand Up @@ -4816,6 +4826,19 @@ function getCompletionData(

function tryGetFunctionLikeBodyCompletionContainer(contextToken: Node): FunctionLikeDeclaration | undefined {
if (contextToken) {
// When completing the expression body of an arrow function (e.g. `(x) => x|`
// or `(x) => |`), `getRelevantTokens` sets contextToken to the `=>` token
// (the preceding token before the identifier or keyword being typed). The
// findAncestor loop below starts at contextToken.parent (the ArrowFunction)
// and never matches because `prev` is undefined on the first iteration.
// Detect this case directly so callers can use the right keyword filter.
if (
contextToken.kind === SyntaxKind.EqualsGreaterThanToken
&& isArrowFunction(contextToken.parent)
&& !isBlock(contextToken.parent.body)
) {
return contextToken.parent;
}
let prev: Node;
const container = findAncestor(contextToken.parent, (node: Node) => {
if (isClassLike(node)) {
Expand Down Expand Up @@ -5488,6 +5511,8 @@ function getTypescriptKeywordCompletions(keywordFilter: KeywordCompletionFilters
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
case KeywordCompletionFilters.FunctionLikeBodyKeywords:
return isFunctionLikeBodyKeyword(kind);
case KeywordCompletionFilters.FunctionLikeExpressionBodyKeywords:
return isFunctionLikeBodyKeyword(kind) && kind !== SyntaxKind.DefaultKeyword;
case KeywordCompletionFilters.ClassElementKeywords:
return isClassMemberCompletionKeyword(kind);
case KeywordCompletionFilters.InterfaceElementKeywords:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

verify.completions({
marker: "1",
// TODO: should not include 'default' keyword at an expression location
includes: [
"d",
"defaultIsAnInvalidParameterName",
{ name: "default", sortText: completion.SortText.GlobalsOrKeywords }
]
],
excludes: [
"default",
],
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ verify.completions({
marker: "1",
includes: [
"defaultIsAnInvalidParameterName",
// This should probably stop working in the future.
{ name: "default", text: "default", kind: "keyword", sortText: completion.SortText.GlobalsOrKeywords },
],
excludes: [
"default",
],
});