提交 4a68d67e 编写于 作者: K Kevin Halverson

Avoid DataTip crash in .cshtml...

There are cases were a DataBuffer span may map to two zero-length spans in the _subjectBuffer.  In these cases, rather than throwing an Exception, we can simply try returning a DataTip from each one.
上级 851e4843
......@@ -61,49 +61,52 @@ public override int GetDataTipText(TextSpan[] pSpan, out string pbstrText)
return VSConstants.E_FAIL;
}
// We need to map the TextSpan from the DataBuffer to our subject buffer. We'll
// only consider spans whose length matches our input span (which we expect to
// always be zero). This is to address the case where the position is on a seam
// and maps to multiple source spans.
// If there is not exactly one matching span, just return.
// We need to map the TextSpan from the DataBuffer to our subject buffer.
var span = textViewModel.DataBuffer.CurrentSnapshot.GetSpan(pSpan[0]);
var spanLength = span.Length;
Debug.Assert(spanLength == 0, $"Expected zero length span (got '{spanLength}'.");
var subjectSpan = WpfTextView.BufferGraph.MapDownToBuffer(span, SpanTrackingMode.EdgeInclusive, _subjectBuffer)
.SingleOrDefault(x => x.Length == spanLength);
var subjectSpans = WpfTextView.BufferGraph.MapDownToBuffer(span, SpanTrackingMode.EdgeInclusive, _subjectBuffer);
if (subjectSpan == default(SnapshotSpan))
// The following loop addresses the case where the position is on a seam and maps to multiple source spans.
// In these cases, we assume it's okay to return the first span that successfully returns a DataTip.
// It's most likely that either only one will succeed or both with fail.
var expectedSpanLength = span.Length;
foreach (var candidateSpan in subjectSpans)
{
pbstrText = null;
return VSConstants.E_FAIL;
}
// First, we'll only consider spans whose length matches our input span.
if (candidateSpan.Length != expectedSpanLength)
{
continue;
}
pSpan[0] = subjectSpan.ToVsTextSpan();
// Next, we'll check to see if there is actually a DataTip for this candidate.
// If there is, we'll map this span back to the DataBuffer and return it.
pSpan[0] = candidateSpan.ToVsTextSpan();
int hr = base.GetDataTipText(pSpan, out pbstrText);
if (ErrorHandler.Succeeded(hr))
{
var subjectSpan = _subjectBuffer.CurrentSnapshot.GetSpan(pSpan[0]);
int hr = base.GetDataTipText(pSpan, out pbstrText);
// When mapping back up to the surface buffer, if we get more than one span,
// take the span that intersects with the input span, since that's probably
// the one we care about.
// If there are no such spans, just return.
var surfaceSpan = WpfTextView.BufferGraph.MapUpToBuffer(subjectSpan, SpanTrackingMode.EdgeInclusive, textViewModel.DataBuffer)
.SingleOrDefault(x => x.IntersectsWith(span));
// pSpan is an in/out parameter, so map it back to the Databuffer.
if (ErrorHandler.Succeeded(hr))
{
subjectSpan = _subjectBuffer.CurrentSnapshot.GetSpan(pSpan[0]);
if (surfaceSpan == default(SnapshotSpan))
{
pbstrText = null;
return VSConstants.E_FAIL;
}
// When mapping back up to the surface buffer, if we get more than one span,
// take the span that intersects with the input span, since that's probably
// the one we care about.
// If there are no such spans, just return.
var surfaceSpan = WpfTextView.BufferGraph.MapUpToBuffer(subjectSpan, SpanTrackingMode.EdgeInclusive, textViewModel.DataBuffer)
.SingleOrDefault(x => x.IntersectsWith(span));
// pSpan is an in/out parameter
pSpan[0] = surfaceSpan.ToVsTextSpan();
if (surfaceSpan == default(SnapshotSpan))
{
pbstrText = null;
return VSConstants.E_FAIL;
return hr;
}
pSpan[0] = surfaceSpan.ToVsTextSpan();
}
return hr;
pbstrText = null;
return VSConstants.E_FAIL;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册