mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:48:25 +00:00
Completion. Rework KeywordSuggestion to better constructors.
As requested in https://dart-review.googlesource.com/c/sdk/+/359240 Change-Id: I5047afaddfd74310303001669177f725aac9c02c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/359261 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
291051e02d
commit
5a65760042
|
@ -288,13 +288,6 @@ final class KeywordSuggestion extends CandidateSuggestion {
|
|||
/// should be positioned.
|
||||
final int selectionOffset;
|
||||
|
||||
/// Initialize a newly created candidate suggestion to suggest the [keyword].
|
||||
factory KeywordSuggestion.fromKeyword({required Keyword keyword}) {
|
||||
var lexeme = keyword.lexeme;
|
||||
return KeywordSuggestion._(
|
||||
completion: lexeme, selectionOffset: lexeme.length);
|
||||
}
|
||||
|
||||
/// Initialize a newly created candidate suggestion to suggest the [keyword].
|
||||
///
|
||||
/// If [annotatedText] is provided. The annotated text is used in cases where
|
||||
|
@ -306,41 +299,36 @@ final class KeywordSuggestion extends CandidateSuggestion {
|
|||
/// be used as the selection offset. If the text doesn't contain a caret, then
|
||||
/// the insert text will be the annotated text and the selection offset will
|
||||
/// be at the end of the text.
|
||||
factory KeywordSuggestion.fromKeywordAndText({
|
||||
required Keyword? keyword,
|
||||
factory KeywordSuggestion.fromKeyword({
|
||||
required Keyword keyword,
|
||||
required String? annotatedText,
|
||||
}) {
|
||||
assert(keyword != null || annotatedText != null);
|
||||
|
||||
var completion = '';
|
||||
int? selectionOffset;
|
||||
|
||||
if (keyword != null) {
|
||||
completion = keyword.lexeme;
|
||||
}
|
||||
var completion = keyword.lexeme;
|
||||
var selectionOffset = completion.length;
|
||||
|
||||
if (annotatedText != null) {
|
||||
var caretIndex = annotatedText.indexOf('^');
|
||||
if (caretIndex < 0) {
|
||||
completion += annotatedText;
|
||||
} else {
|
||||
selectionOffset = completion.length + caretIndex;
|
||||
completion += annotatedText.substring(0, caretIndex) +
|
||||
annotatedText.substring(caretIndex + 1);
|
||||
}
|
||||
var (rawText, caretIndex) = annotatedText.withoutCaret;
|
||||
completion += rawText;
|
||||
selectionOffset += caretIndex ?? rawText.length;
|
||||
}
|
||||
|
||||
selectionOffset ??= completion.length;
|
||||
return KeywordSuggestion._(
|
||||
completion: completion,
|
||||
selectionOffset: selectionOffset,
|
||||
);
|
||||
}
|
||||
|
||||
/// Initialize a newly created candidate suggestion to suggest the [keyword].
|
||||
factory KeywordSuggestion.fromPseudoKeyword({required String keyword}) {
|
||||
/// If [annotatedText] contains a caret (`^`), then the completion will use
|
||||
/// the annotated text with the caret removed and the index of the caret will
|
||||
/// be used as the selection offset. If the text doesn't contain a caret, then
|
||||
/// the insert text will be the annotated text and the selection offset will
|
||||
/// be at the end of the text.
|
||||
factory KeywordSuggestion.fromText(String annotatedText) {
|
||||
var (rawText, caretIndex) = annotatedText.withoutCaret;
|
||||
return KeywordSuggestion._(
|
||||
completion: keyword, selectionOffset: keyword.length);
|
||||
completion: rawText,
|
||||
selectionOffset: caretIndex ?? rawText.length,
|
||||
);
|
||||
}
|
||||
|
||||
/// Initialize a newly created candidate suggestion to suggest a keyword.
|
||||
|
@ -632,6 +620,18 @@ final class UriSuggestion extends CandidateSuggestion {
|
|||
String get completion => uriStr;
|
||||
}
|
||||
|
||||
extension on String {
|
||||
(String, int?) get withoutCaret {
|
||||
var caretIndex = indexOf('^');
|
||||
if (caretIndex < 0) {
|
||||
return (this, null);
|
||||
} else {
|
||||
var rawText = substring(0, caretIndex) + substring(caretIndex + 1);
|
||||
return (rawText, caretIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SuggestionBuilderExtension on SuggestionBuilder {
|
||||
// TODO(brianwilkerson): Move these to `SuggestionBuilder`, possibly as part
|
||||
// of splitting it into a legacy builder and an LSP builder.
|
||||
|
|
|
@ -1064,7 +1064,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
if (name != null && offset <= name.end) {
|
||||
keywordHelper.addKeyword(Keyword.ON);
|
||||
if (featureSet.isEnabled(Feature.inline_class)) {
|
||||
keywordHelper.addPseudoKeyword('type');
|
||||
keywordHelper.addText('type');
|
||||
}
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
return;
|
||||
|
@ -2296,10 +2296,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
void visitSwitchDefault(SwitchDefault node) {
|
||||
if (offset <= node.keyword.offset) {
|
||||
keywordHelper.addKeyword(Keyword.CASE);
|
||||
keywordHelper.addKeywordFromText(Keyword.DEFAULT, ':');
|
||||
keywordHelper.addKeywordAndText(Keyword.DEFAULT, ':');
|
||||
} else if (offset <= node.keyword.end) {
|
||||
if (node.colon.isSynthetic) {
|
||||
keywordHelper.addKeywordFromText(Keyword.DEFAULT, ':');
|
||||
keywordHelper.addKeywordAndText(Keyword.DEFAULT, ':');
|
||||
} else {
|
||||
keywordHelper.addKeyword(Keyword.DEFAULT);
|
||||
}
|
||||
|
@ -2377,7 +2377,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
collector.completionLocation = 'SwitchMember_statement';
|
||||
if (node.statements.isEmpty || offset <= node.statements.first.offset) {
|
||||
keywordHelper.addKeyword(Keyword.CASE);
|
||||
keywordHelper.addKeywordFromText(Keyword.DEFAULT, ':');
|
||||
keywordHelper.addKeywordAndText(Keyword.DEFAULT, ':');
|
||||
}
|
||||
_forStatement(node);
|
||||
}
|
||||
|
@ -2397,10 +2397,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
collector.completionLocation = 'SwitchMember_statement';
|
||||
var members = node.members;
|
||||
keywordHelper.addKeyword(Keyword.CASE);
|
||||
keywordHelper.addKeywordFromText(Keyword.DEFAULT, ':');
|
||||
keywordHelper.addKeywordAndText(Keyword.DEFAULT, ':');
|
||||
if (members.isNotEmpty) {
|
||||
if (!members.any((element) => element is SwitchDefault)) {
|
||||
keywordHelper.addKeywordFromText(Keyword.DEFAULT, ':');
|
||||
keywordHelper.addKeywordAndText(Keyword.DEFAULT, ':');
|
||||
}
|
||||
var element = members.elementBefore(offset);
|
||||
if (element != null) {
|
||||
|
|
|
@ -205,16 +205,11 @@ class KeywordHelper {
|
|||
if (before == null && !unit.directives.any((d) => d is LibraryDirective)) {
|
||||
addKeyword(Keyword.LIBRARY);
|
||||
}
|
||||
addKeywordFromText(Keyword.IMPORT, " '^';");
|
||||
addKeywordFromText(Keyword.EXPORT, " '^';");
|
||||
addKeywordFromText(Keyword.PART, " '^';");
|
||||
addKeywordAndText(Keyword.IMPORT, " '^';");
|
||||
addKeywordAndText(Keyword.EXPORT, " '^';");
|
||||
addKeywordAndText(Keyword.PART, " '^';");
|
||||
if (unit.directives.isEmpty) {
|
||||
collector.addSuggestion(
|
||||
KeywordSuggestion.fromKeywordAndText(
|
||||
keyword: null,
|
||||
annotatedText: "${Keyword.PART.lexeme} ${Keyword.OF.lexeme} '^';",
|
||||
),
|
||||
);
|
||||
addText("${Keyword.PART.lexeme} ${Keyword.OF.lexeme} '^';");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,7 +321,7 @@ class KeywordHelper {
|
|||
if (node.onKeyword.isSynthetic) {
|
||||
addKeyword(Keyword.ON);
|
||||
if (node.name == null && featureSet.isEnabled(Feature.inline_class)) {
|
||||
addPseudoKeyword('type');
|
||||
addText('type');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -430,8 +425,8 @@ class KeywordHelper {
|
|||
if (_isAbsentOrIn(body?.keyword)) {
|
||||
addKeyword(Keyword.ASYNC);
|
||||
if (body is! ExpressionFunctionBody) {
|
||||
addKeywordFromText(Keyword.ASYNC, '*');
|
||||
addKeywordFromText(Keyword.SYNC, '*');
|
||||
addKeywordAndText(Keyword.ASYNC, '*');
|
||||
addKeywordAndText(Keyword.SYNC, '*');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +441,7 @@ class KeywordHelper {
|
|||
if (firstCombinator == null || offset < firstCombinator.offset) {
|
||||
if (deferredKeyword == null) {
|
||||
if (asKeyword == null) {
|
||||
addKeywordFromText(Keyword.DEFERRED, ' as');
|
||||
addKeywordAndText(Keyword.DEFERRED, ' as');
|
||||
addKeyword(Keyword.AS);
|
||||
addKeyword(Keyword.HIDE);
|
||||
addKeyword(Keyword.SHOW);
|
||||
|
@ -473,7 +468,12 @@ class KeywordHelper {
|
|||
|
||||
/// Add a keyword suggestion to suggest the [keyword].
|
||||
void addKeyword(Keyword keyword) {
|
||||
collector.addSuggestion(KeywordSuggestion.fromKeyword(keyword: keyword));
|
||||
collector.addSuggestion(
|
||||
KeywordSuggestion.fromKeyword(
|
||||
keyword: keyword,
|
||||
annotatedText: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add a keyword suggestion to suggest the [keyword] followed by the
|
||||
|
@ -485,9 +485,13 @@ class KeywordHelper {
|
|||
/// be used as the selection offset. If the text doesn't contain a caret, then
|
||||
/// the insert text will be the annotated text and the selection offset will
|
||||
/// be at the end of the text.
|
||||
void addKeywordFromText(Keyword keyword, String annotatedText) {
|
||||
collector.addSuggestion(KeywordSuggestion.fromKeywordAndText(
|
||||
keyword: keyword, annotatedText: annotatedText));
|
||||
void addKeywordAndText(Keyword keyword, String annotatedText) {
|
||||
collector.addSuggestion(
|
||||
KeywordSuggestion.fromKeyword(
|
||||
keyword: keyword,
|
||||
annotatedText: annotatedText,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add the keywords that are appropriate when the selection is in a mixin
|
||||
|
@ -538,12 +542,6 @@ class KeywordHelper {
|
|||
addVariablePatternKeywords();
|
||||
}
|
||||
|
||||
/// Add a keyword suggestion to suggest the [keyword].
|
||||
void addPseudoKeyword(String keyword) {
|
||||
collector
|
||||
.addSuggestion(KeywordSuggestion.fromPseudoKeyword(keyword: keyword));
|
||||
}
|
||||
|
||||
/// Add the keywords that are appropriate when the selection is at the
|
||||
/// beginning of a statement. The [node] provides context to determine which
|
||||
/// keywords to include.
|
||||
|
@ -553,7 +551,7 @@ class KeywordHelper {
|
|||
} else if (node.inAsyncStarOrSyncStarMethodOrFunction) {
|
||||
addKeyword(Keyword.AWAIT);
|
||||
addKeyword(Keyword.YIELD);
|
||||
addKeywordFromText(Keyword.YIELD, '*');
|
||||
addKeywordAndText(Keyword.YIELD, '*');
|
||||
}
|
||||
if (node.inLoop) {
|
||||
addKeyword(Keyword.BREAK);
|
||||
|
@ -585,11 +583,18 @@ class KeywordHelper {
|
|||
addKeyword(Keyword.WHILE);
|
||||
if (node.inAsyncStarOrSyncStarMethodOrFunction) {
|
||||
addKeyword(Keyword.YIELD);
|
||||
addKeywordFromText(Keyword.YIELD, '*');
|
||||
addKeywordAndText(Keyword.YIELD, '*');
|
||||
}
|
||||
addKeyword(Keyword.LATE);
|
||||
}
|
||||
|
||||
/// Add a keyword suggestion to suggest the [annotatedText].
|
||||
void addText(String annotatedText) {
|
||||
collector.addSuggestion(
|
||||
KeywordSuggestion.fromText(annotatedText),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add the keywords that are appropriate when the selection is after the
|
||||
/// end of a `try` statement. [canHaveFinally] indicates whether it's valid to
|
||||
/// suggest a `finally` clause.
|
||||
|
|
Loading…
Reference in a new issue