mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[code-completion] Add a new custom completion context for a for-each sequence
For normal completions it behaves the same as PostfixExprBeginning, but it provides a hook for clients to provide a custom completion for this position. For example, you might want to a x ..< y snippet in this position. rdar://problem/29910383
This commit is contained in:
@@ -501,6 +501,7 @@ enum class CompletionKind {
|
|||||||
AssignmentRHS,
|
AssignmentRHS,
|
||||||
CallArg,
|
CallArg,
|
||||||
ReturnStmtExpr,
|
ReturnStmtExpr,
|
||||||
|
ForEachSequence,
|
||||||
AfterPound,
|
AfterPound,
|
||||||
GenericParams,
|
GenericParams,
|
||||||
SwiftKeyPath,
|
SwiftKeyPath,
|
||||||
|
|||||||
@@ -151,6 +151,10 @@ public:
|
|||||||
/// by user.
|
/// by user.
|
||||||
virtual void completePostfixExprBeginning(CodeCompletionExpr *E) = 0;
|
virtual void completePostfixExprBeginning(CodeCompletionExpr *E) = 0;
|
||||||
|
|
||||||
|
/// \brief Complete the beginning of expr-postfix in a for-each loop sequqence
|
||||||
|
/// -- no tokens provided by user.
|
||||||
|
virtual void completeForEachSequenceBeginning(CodeCompletionExpr *E) = 0;
|
||||||
|
|
||||||
/// \brief Complete a given expr-postfix.
|
/// \brief Complete a given expr-postfix.
|
||||||
virtual void completePostfixExpr(Expr *E, bool hasSpace) = 0;
|
virtual void completePostfixExpr(Expr *E, bool hasSpace) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1440,6 +1440,7 @@ public:
|
|||||||
void completeDotExpr(Expr *E, SourceLoc DotLoc) override;
|
void completeDotExpr(Expr *E, SourceLoc DotLoc) override;
|
||||||
void completeStmtOrExpr() override;
|
void completeStmtOrExpr() override;
|
||||||
void completePostfixExprBeginning(CodeCompletionExpr *E) override;
|
void completePostfixExprBeginning(CodeCompletionExpr *E) override;
|
||||||
|
void completeForEachSequenceBeginning(CodeCompletionExpr *E) override;
|
||||||
void completePostfixExpr(Expr *E, bool hasSpace) override;
|
void completePostfixExpr(Expr *E, bool hasSpace) override;
|
||||||
void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override;
|
void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override;
|
||||||
void completeExprSuper(SuperRefExpr *SRE) override;
|
void completeExprSuper(SuperRefExpr *SRE) override;
|
||||||
@@ -4479,6 +4480,14 @@ void CodeCompletionCallbacksImpl::completePostfixExprBeginning(CodeCompletionExp
|
|||||||
CodeCompleteTokenExpr = E;
|
CodeCompleteTokenExpr = E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeCompletionCallbacksImpl::completeForEachSequenceBeginning(
|
||||||
|
CodeCompletionExpr *E) {
|
||||||
|
assert(P.Tok.is(tok::code_complete));
|
||||||
|
Kind = CompletionKind::ForEachSequence;
|
||||||
|
CurDeclContext = P.CurDeclContext;
|
||||||
|
CodeCompleteTokenExpr = E;
|
||||||
|
}
|
||||||
|
|
||||||
void CodeCompletionCallbacksImpl::completePostfixExpr(Expr *E, bool hasSpace) {
|
void CodeCompletionCallbacksImpl::completePostfixExpr(Expr *E, bool hasSpace) {
|
||||||
assert(P.Tok.is(tok::code_complete));
|
assert(P.Tok.is(tok::code_complete));
|
||||||
|
|
||||||
@@ -4840,6 +4849,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
|
|||||||
case CompletionKind::AssignmentRHS:
|
case CompletionKind::AssignmentRHS:
|
||||||
case CompletionKind::ReturnStmtExpr:
|
case CompletionKind::ReturnStmtExpr:
|
||||||
case CompletionKind::PostfixExprBeginning:
|
case CompletionKind::PostfixExprBeginning:
|
||||||
|
case CompletionKind::ForEachSequence:
|
||||||
addSuperKeyword(Sink);
|
addSuperKeyword(Sink);
|
||||||
addLetVarKeywords(Sink);
|
addLetVarKeywords(Sink);
|
||||||
addExprKeywords(Sink);
|
addExprKeywords(Sink);
|
||||||
@@ -5191,6 +5201,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
|
|||||||
DoPostfixExprBeginning();
|
DoPostfixExprBeginning();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CompletionKind::ForEachSequence:
|
||||||
case CompletionKind::PostfixExprBeginning: {
|
case CompletionKind::PostfixExprBeginning: {
|
||||||
::CodeCompletionTypeContextAnalyzer Analyzer(CurDeclContext,
|
::CodeCompletionTypeContextAnalyzer Analyzer(CurDeclContext,
|
||||||
CodeCompleteTokenExpr);
|
CodeCompleteTokenExpr);
|
||||||
|
|||||||
@@ -2098,6 +2098,15 @@ ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc,
|
|||||||
SourceLoc LBraceLoc = Tok.getLoc();
|
SourceLoc LBraceLoc = Tok.getLoc();
|
||||||
diagnose(LBraceLoc, diag::expected_foreach_container);
|
diagnose(LBraceLoc, diag::expected_foreach_container);
|
||||||
Container = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
|
Container = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
|
||||||
|
} else if (Tok.is(tok::code_complete)) {
|
||||||
|
Container =
|
||||||
|
makeParserResult(new (Context) CodeCompletionExpr(Tok.getLoc()));
|
||||||
|
Container.setHasCodeCompletion();
|
||||||
|
Status |= Container;
|
||||||
|
if (CodeCompletion)
|
||||||
|
CodeCompletion->completeForEachSequenceBeginning(
|
||||||
|
cast<CodeCompletionExpr>(Container.get()));
|
||||||
|
consumeToken(tok::code_complete);
|
||||||
} else {
|
} else {
|
||||||
Container = parseExprBasic(diag::expected_foreach_container);
|
Container = parseExprBasic(diag::expected_foreach_container);
|
||||||
if (Container.isNull())
|
if (Container.isNull())
|
||||||
|
|||||||
@@ -24,6 +24,13 @@
|
|||||||
source.lang.swift.stmt,
|
source.lang.swift.stmt,
|
||||||
source.lang.swift.type
|
source.lang.swift.type
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key.name: "customForEach",
|
||||||
|
key.kind: myuid.customForEach,
|
||||||
|
key.context: [
|
||||||
|
source.lang.swift.foreach.sequence,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ func test() {
|
|||||||
// stmt
|
// stmt
|
||||||
()
|
()
|
||||||
let foo: // type
|
let foo: // type
|
||||||
|
for x in { } // foreach.sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===--- Errors
|
// ===--- Errors
|
||||||
@@ -62,6 +63,14 @@ func test() {
|
|||||||
// TYPE-NEXT: key.name: "customType"
|
// TYPE-NEXT: key.name: "customType"
|
||||||
// TYPE-NOT: myuid
|
// TYPE-NOT: myuid
|
||||||
|
|
||||||
|
// RUN: %sourcekitd-test -json-request-path %S/Inputs/custom-completion/custom.json == \
|
||||||
|
// RUN: -req=complete.open -pos=5:12 %s -- %s | %FileCheck %s -check-prefix=FOREACH
|
||||||
|
|
||||||
|
// FOREACH-NOT: myuid
|
||||||
|
// FOREACH: myuid.customForEach
|
||||||
|
// FOREACH-NEXT: key.name: "customForEach"
|
||||||
|
// FOREACH-NOT: myuid
|
||||||
|
|
||||||
// ===--- Filtering.
|
// ===--- Filtering.
|
||||||
|
|
||||||
// RUN: %sourcekitd-test -json-request-path %S/Inputs/custom-completion/custom.json == \
|
// RUN: %sourcekitd-test -json-request-path %S/Inputs/custom-completion/custom.json == \
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ struct CustomCompletionInfo {
|
|||||||
Stmt = 1 << 0,
|
Stmt = 1 << 0,
|
||||||
Expr = 1 << 1,
|
Expr = 1 << 1,
|
||||||
Type = 1 << 2,
|
Type = 1 << 2,
|
||||||
|
ForEachSequence = 1 << 3,
|
||||||
};
|
};
|
||||||
swift::OptionSet<Context> Contexts;
|
swift::OptionSet<Context> Contexts;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ KIND(ObjectLiteral, "source.lang.swift.syntaxtype.objectliteral")
|
|||||||
KIND(Expr, "source.lang.swift.expr")
|
KIND(Expr, "source.lang.swift.expr")
|
||||||
KIND(Stmt, "source.lang.swift.stmt")
|
KIND(Stmt, "source.lang.swift.stmt")
|
||||||
KIND(Type, "source.lang.swift.type")
|
KIND(Type, "source.lang.swift.type")
|
||||||
|
KIND(ForEachSequence, "source.lang.swift.foreach.sequence")
|
||||||
|
|
||||||
KIND(DiagNote, "source.diagnostic.severity.note")
|
KIND(DiagNote, "source.diagnostic.severity.note")
|
||||||
KIND(DiagWarning, "source.diagnostic.severity.warning")
|
KIND(DiagWarning, "source.diagnostic.severity.warning")
|
||||||
|
|||||||
@@ -184,6 +184,12 @@ bool SourceKit::CodeCompletion::addCustomCompletions(
|
|||||||
addCompletion(custom);
|
addCompletion(custom);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CompletionKind::ForEachSequence:
|
||||||
|
if (custom.Contexts.contains(CustomCompletionInfo::ForEachSequence)) {
|
||||||
|
changed = true;
|
||||||
|
addCompletion(custom);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CompletionKind::TypeSimpleBeginning:
|
case CompletionKind::TypeSimpleBeginning:
|
||||||
if (custom.Contexts.contains(CustomCompletionInfo::Type)) {
|
if (custom.Contexts.contains(CustomCompletionInfo::Type)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|||||||
@@ -593,6 +593,8 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
|
|||||||
CCInfo.Contexts |= CustomCompletionInfo::Stmt;
|
CCInfo.Contexts |= CustomCompletionInfo::Stmt;
|
||||||
} else if (context == KindType) {
|
} else if (context == KindType) {
|
||||||
CCInfo.Contexts |= CustomCompletionInfo::Type;
|
CCInfo.Contexts |= CustomCompletionInfo::Type;
|
||||||
|
} else if (context == KindForEachSequence) {
|
||||||
|
CCInfo.Contexts |= CustomCompletionInfo::ForEachSequence;
|
||||||
} else {
|
} else {
|
||||||
err = createErrorRequestInvalid("invalid value for 'key.context'");
|
err = createErrorRequestInvalid("invalid value for 'key.context'");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user