-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Snippets: If snippet and use of LSP's SnippetExpander #60860
Snippets: If snippet and use of LSP's SnippetExpander #60860
Conversation
…to features/snippets_2
…to features/snippets_2
…to features/snippets_2
…to features/snippets_2
lspSnippetString.Append(str); | ||
|
||
// Skip past the entire identifier in the TextChange text | ||
i += placeholderInfo.identifier.Length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
something feels very funky here. in the above if check, you end with a ++... but then you lookup in this dictionary using that position that you mutated. so if you have a caretposition and placeholder at the same position, it seems like this will fail.
DO you have testws for that?
/// Preprocesses the list of placeholders into a dictionary that maps the insertion position | ||
/// in the string to the placeholder's identifier and the priority associated with it. | ||
/// </summary> | ||
private static void GetMapOfSpanStartsToLSPStringItem(ref PooledDictionary<int, (string identifier, int priority)> dictionary, ImmutableArray<SnippetPlaceholder> placeholders, int textChangeStart) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private static void GetMapOfSpanStartsToLSPStringItem(ref PooledDictionary<int, (string identifier, int priority)> dictionary, ImmutableArray<SnippetPlaceholder> placeholders, int textChangeStart) | |
private static void GetMapOfSpanStartsToLSPStringItem(Dictionary<int, (string identifier, int priority)> dictionary, ImmutableArray<SnippetPlaceholder> placeholders, int textChangeStart) |
{ | ||
if (textChanges.IsEmpty) | ||
{ | ||
throw new ArgumentException($"{ textChanges.Length } must not be empty"); | ||
throw new ArgumentException($"textChanges must not be empty"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw new ArgumentException($"textChanges must not be empty"); | |
throw new ArgumentException($"{nameof(textChanges)} must not be empty"); |
/// Example: | ||
/// For loop would have two placeholders: | ||
/// for (var {1:i} = 0; {1:i} < {2:length}; {i}++) | ||
/// Identifier: i, 3 associated positions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Identifier: i, 3 associated positions | |
/// Identifier: i, 3 associated positions |
/// For loop would have two placeholders: | ||
/// for (var {1:i} = 0; {1:i} < {2:length}; {i}++) | ||
/// Identifier: i, 3 associated positions | ||
/// IdentifierL length, 1 associated position |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something is weird here.
syntaxFacts.GetPartsOfArgumentList(argumentListNode, out var openParenToken, out _, out _); | ||
return openParenToken.Span.End; | ||
var openParenToken = GetOpenParenToken(caretTarget, syntaxFacts); | ||
Contract.ThrowIfNull(openParenToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we contract-throwing here? how do you know this must insert an open paren? (consdier VB, which would not have an open paren here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Actually, the VB comment applies to if-statements, not console.writeline) (though in VB the parens are optinoal there too :))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm creating the syntax, so I can ensure there are parentheses created. Not sure what you mean by it applying to if-statements, I don't get any open parentheses tokens in the if statement provider.
|
||
syntaxFacts.GetPartsOfArgumentList(argumentListNode, out var openParenToken, out _, out _); | ||
|
||
return openParenToken; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't get why this method is nullable just to have the caller throw if it gets null.
Done with pass. |
{ | ||
var lspSnippetText = change.Properties[SnippetCompletionItem.LSPSnippetKey]; | ||
|
||
_roslynLSPSnippetExpander.TryExpand(change.TextChange.Span, lspSnippetText, _textView, triggerSnapshot); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: if return value is not checked. consider just making "Expand" and not "TryExpand"
} | ||
} | ||
|
||
public void TryExpand(TextSpan textSpan, string lspSnippetText, ITextView textView, ITextSnapshot textSnapshot) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: as a void method, consider just namign 'Expand'.
if (expandMethodResult is null) | ||
{ | ||
throw new Exception("The result of the invoked LSP snippet expander is null."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (expandMethodResult is null) | |
{ | |
throw new Exception("The result of the invoked LSP snippet expander is null."); | |
} | |
if (expandMethodResult is not boolean resultValue) | |
{ | |
throw new Exception("The result of the invoked LSP snippet expander was not a boolean."); | |
} |
if (!(bool)expandMethodResult) | ||
{ | ||
throw new Exception("The invoked LSP snippet expander came back as false."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!(bool)expandMethodResult) | |
{ | |
throw new Exception("The invoked LSP snippet expander came back as false."); | |
} | |
if (!resultValue) | |
{ | |
throw new Exception("The invoked LSP snippet expander came back as false."); | |
} |
} | ||
|
||
return lspSnippetString.ToString(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
if (identifier.Length == 0) | ||
{ | ||
throw new ArgumentException($"{nameof(identifier)} must not be an empty string."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice.
@@ -119,7 +119,7 @@ private static async Task<TextChange> ExtendSnippetTextChangeAsync(Document docu | |||
|
|||
var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); | |||
var newString = documentText.ToString(extendedSpan); | |||
var newTextChange = new TextChange(new TextSpan(extendedSpan.Start, 0), newString); | |||
var newTextChange = new TextChange(TextSpan.FromBounds(extendedSpan.Start, extendedSpan.End), newString); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't TextSpan.FromBounds(extendedSpan.Start, extendedSpan.End)
exactly the same as extendedSpan
?
In this PR:
LanguageServerSnippetExpander
SnippetChange
SnippetChange
into an LSP formatted snippetLanguageServerSnippetExpander
to handleCreate
in theCompletionChange
that holds onto the LSP formatted snippet (internal)