Inline Hints: Added double click on hint to insert text#55737
Inline Hints: Added double click on hint to insert text#55737akhera99 merged 29 commits intodotnet:mainfrom
Conversation
|
Edited behavior: ConsoleApp7.-.Microsoft.Visual.Studio.Int.Preview.2021-08-20.15-30-56.mp4 |
JoeRobich
left a comment
There was a problem hiding this comment.
Looks good. I am excited to try this out
do we need an option for this? why not always support this? what's the use case for a user double-clicking on the hint and not inserting it? |
|
|
||
| result.Add(new InlineHint( | ||
| new TextSpan(position, 0), | ||
| ImmutableArray.Create(new TaggedText(TextTags.Text, parameter.Name + ": ")), |
There was a problem hiding this comment.
isn't the replacement text exactly the same as this string here? why not just compute it here and just add to the hint?
There was a problem hiding this comment.
confused. you still generate parameter.Name + ": " here.
There was a problem hiding this comment.
right, for C# and VB we generated "parameter:" for the hint itself, which I thought should remain the same. It only matters to generate the parameter:= for VB when you double click and replace the hint, which is why I added the "inlineHintText" var on line 94.
There was a problem hiding this comment.
interesting. it's arguable that the VB hint is wrong and should be foo:= to indicate the actual VB implied text... can you try that out and show me what it looks like? if it's not hideous, we could mvoe to that. If it's awful, then your solution is a good workaround.
| => _getDescriptionAsync?.Invoke(document, cancellationToken) ?? SpecializedTasks.EmptyImmutableArray<TaggedText>(); | ||
|
|
||
| public string? GetReplacementText() | ||
| => _getReplacementText?.Invoke() ?? null; |
There was a problem hiding this comment.
why do we need an indirection here? it should be practically free to just store the TextChange struct.
There was a problem hiding this comment.
At that point, why would you need the TextChange struct as well?
There was a problem hiding this comment.
to know what text change to make :)
There was a problem hiding this comment.
isn't it easier to use the ITextBuffer.Replace instead of worrying about TextChange etc? We already have the IWpfTextView stored so calling Replace on the underlying buffer is trivial
There was a problem hiding this comment.
hints are data, and should work cross process. we would not want them making any changes themselves.
CyrusNajmabadi
left a comment
There was a problem hiding this comment.
i think there's a bit of overkill in this :)
| { | ||
| e.Handled = true; | ||
| var replacementValue = _hint.ReplacementTextChange!.Value; | ||
| _ = _textView.TextBuffer.Replace(new VisualStudio.Text.Span(replacementValue.Span.Start, replacementValue.Span.Length), replacementValue.NewText); |
There was a problem hiding this comment.
still wont' work in any projection scenario.
| // a space after it to make things feel less cramped. | ||
| var trailingSpace = span.Length == 0; | ||
| return new TypeHint(type, span, trailingSpace: trailingSpace); | ||
| return new TypeHint(type, span, new TextChange(displayAllSpan.Span, type.ToDisplayString(s_minimalTypeStyle)), trailingSpace: trailingSpace); |
There was a problem hiding this comment.
it would be good to have a test to ensure that double clickong on a non-overwrite hint overwrites teh right text.
There was a problem hiding this comment.
How would you go about testing that? The testing suite we currently have has access to the InlineHInts, but not the tags themselves. If we had access to the tags we could invoke a double click on the adornment, but is there an easier way to do it? @CyrusNajmabadi
There was a problem hiding this comment.
well, we can have two sorts of tests. Unit tests that would validate our internal API and hte data it returns. Then an integration test that actually loads this into VS and interacts with the real tags on the editor side.
We should likely have both. Most tests should be at teh unit level, but we should have a couple of tests that actually do the full end to end validation at the editor level.
There was a problem hiding this comment.
this code feels like it should be in the constructor of TypeHint. Pass both spans.
|
Retarget this to main because 17.1 branch is not used and main is 17.1 now |
| { | ||
| var parameterHintUITag = InlineHintsTag.Create( | ||
| _cache[i].mappingTagSpan.Tag.Hint, Format, _textView, tagSpan, _taggerProvider, _formatMap, classify); | ||
| _cache[i].mappingTagSpan.Tag.Hint, Format, _textView, tagSpan, _taggerProvider, _formatMap, snapshot.TextBugger, classify); |
There was a problem hiding this comment.
| _cache[i].mappingTagSpan.Tag.Hint, Format, _textView, tagSpan, _taggerProvider, _formatMap, snapshot.TextBugger, classify); | |
| _cache[i].mappingTagSpan.Tag.Hint, Format, _textView, tagSpan, _taggerProvider, _formatMap, snapshot.TextBuffer, classify); |
| { | ||
| e.Handled = true; | ||
| var replacementValue = _hint.ReplacementTextChange!.Value; | ||
| _ = _subjectBuffer.Replace(new VisualStudio.Text.Span(replacementValue.Span.Start, replacementValue.Span.Length), replacementValue.NewText); |
There was a problem hiding this comment.
this span may be computed against a different snapshot version of hte buffer than the one currently displayed. it woudl be probably hard to hit, but this could cause a crash. You should validate that the span is still within the bounds of the buffer's current snapshot prior to making this change.
| { | ||
| e.Handled = true; | ||
| var replacementValue = _hint.ReplacementTextChange!.Value; | ||
| _ = _subjectBuffer.Replace(new VisualStudio.Text.Span(replacementValue.Span.Start, replacementValue.Span.Length), replacementValue.NewText); |
There was a problem hiding this comment.
| _ = _subjectBuffer.Replace(new VisualStudio.Text.Span(replacementValue.Span.Start, replacementValue.Span.Length), replacementValue.NewText); | |
| _subjectBuffer.Replace(new VisualStudio.Text.Span(replacementValue.Span.Start, replacementValue.Span.Length), replacementValue.NewText); | |
| adornment.MouseLeftButtonDown -= Adornment_MouseLeftButtonDown; |
| End Using | ||
| End Function | ||
|
|
||
| 'Protected Async Function VerifyTypeHintsDoubleClick(test As XElement, Optional optionIsEnabled As Boolean = True, Optional ephemeral As Boolean = False) As Task |
| IsValidType(parameter?.Type)) | ||
| { | ||
| return new(parameter.Type, new TextSpan(parameterNode.Identifier.SpanStart, 0), trailingSpace: true); | ||
| if (parameterNode.Parent!.Parent.IsKind(SyntaxKind.ParenthesizedLambdaExpression)) |
There was a problem hiding this comment.
Would we everr have a null Parent in this case?
There was a problem hiding this comment.
i would jsut write this as:
var textChange = parameterNode.Parent?.Parent?.Kind is SyntaxKind.ParenthesizedLambdaExpression
? new TextChange(...)
: null;then just return once.
| private InlineHintsTag( | ||
| FrameworkElement adornment, | ||
| ITextView textView, | ||
| ITextBuffer subjectBuffer, |
There was a problem hiding this comment.
this feels a bit redundant. the snapshot span already points at this right? perhaps just use that so there's no chance of this being out of date?
CyrusNajmabadi
left a comment
There was a problem hiding this comment.
approved, but have some small sgugestions on cleanup :)
Fixes: #55519
Added functionality in for parameter and type hints to be double-clicked and inserted into the text. Type hints replace var