public async Task <QuickInfoItem> GetQuickInfoItemAsync(IAsyncQuickInfoSession session, CancellationToken cancellationToken) { if (DebuggingService.CurrentFrame == null) { return(null); } if (window != null) { await Runtime.RunInMainThread(DestroyWindow); } var view = session.TextView; var textViewLines = view.TextViewLines; var snapshot = textViewLines.FormattedSpan.Snapshot; var triggerPoint = session.GetTriggerPoint(textBuffer); if (snapshot.TextBuffer != triggerPoint.TextBuffer) { return(null); } var point = triggerPoint.GetPoint(snapshot); foreach (var debugInfoProvider in provider.debugInfoProviders) { DataTipInfo debugInfo = default; if (!view.Selection.IsEmpty) { foreach (var span in view.Selection.SelectedSpans) { if (span.Contains(point)) { //debugInfo = new DataTipInfo (snapshot.CreateTrackingSpan (span, SpanTrackingMode.EdgeInclusive), snapshot.GetText (span)); debugInfo = await debugInfoProvider.Value.GetDebugInfoAsync(span, cancellationToken); break; } } } else { debugInfo = await debugInfoProvider.Value.GetDebugInfoAsync(point, cancellationToken); } if (!debugInfo.IsDefault) { await EvaluateAndShowTooltipAsync(session, view, point, debugInfo, cancellationToken); return(null); } } return(null); }
private async Task EvaluateAndShowTooltipAsync(IAsyncQuickInfoSession session, ITextView view, SnapshotPoint point, DataTipInfo debugInfo, CancellationToken cancellationToken) { var options = DebuggingService.DebuggerSession.EvaluationOptions.Clone(); options.AllowMethodEvaluation = true; options.AllowTargetInvoke = true; var val = DebuggingService.CurrentFrame.GetExpressionValue(debugInfo.Text, options); if (val.IsEvaluating) { await WaitOneAsync(val.WaitHandle, cancellationToken); } if (cancellationToken.IsCancellationRequested) { return; } if (val == null || val.IsUnknown || val.IsNotSupported) { return; } if (!view.Properties.TryGetProperty(typeof(Gtk.Widget), out Gtk.Widget gtkParent)) { return; } provider.textDocumentFactoryService.TryGetTextDocument(view.TextDataModel.DocumentBuffer, out var textDocument); // This is a bit hacky, since AsyncQuickInfo is designed to display multiple elements if multiple sources // return value, we don't want that for debugger value hovering, hence we dismiss AsyncQuickInfo // and do our own thing, notice VS does same thing await session.DismissAsync(); await provider.joinableTaskContext.Factory.SwitchToMainThreadAsync(); this.lastView = view; val.Name = debugInfo.Text; window = new DebugValueWindow((Gtk.Window)gtkParent.Toplevel, textDocument?.FilePath, textBuffer.CurrentSnapshot.GetLineNumberFromPosition(debugInfo.Span.GetStartPoint(textBuffer.CurrentSnapshot)), DebuggingService.CurrentFrame, val, null); Ide.IdeApp.CommandService.RegisterTopWindow(window); var bounds = view.TextViewLines.GetCharacterBounds(point); view.LayoutChanged += LayoutChanged; #if CLOSE_ON_FOCUS_LOST view.LostAggregateFocus += View_LostAggregateFocus; #endif RegisterForHiddenAsync(view).Ignore(); window.LeaveNotifyEvent += LeaveNotifyEvent; #if MAC var cocoaView = ((ICocoaTextView)view); var cgPoint = cocoaView.VisualElement.ConvertPointToView(new CoreGraphics.CGPoint(bounds.Left - view.ViewportLeft, bounds.Top - view.ViewportTop), cocoaView.VisualElement.Superview); cgPoint.Y = cocoaView.VisualElement.Superview.Frame.Height - cgPoint.Y; window.ShowPopup(gtkParent, new Gdk.Rectangle((int)cgPoint.X, (int)cgPoint.Y, (int)bounds.Width, (int)bounds.Height), Components.PopupPosition.TopLeft); #else throw new NotImplementedException(); #endif }
private async Task EvaluateAndShowTooltipAsync(IAsyncQuickInfoSession session, ITextView view, SnapshotPoint point, DataTipInfo debugInfo, CancellationToken cancellationToken) { var options = DebuggingService.DebuggerSession.EvaluationOptions.Clone(); options.AllowMethodEvaluation = true; options.AllowTargetInvoke = true; var val = DebuggingService.CurrentFrame.GetExpressionValue(debugInfo.Text, options); if (val.IsEvaluating) { await WaitOneAsync(val.WaitHandle, cancellationToken); } if (cancellationToken.IsCancellationRequested) { return; } if (val == null || val.IsUnknown || val.IsNotSupported) { return; } if (!view.Properties.TryGetProperty(typeof(Widget), out Widget gtkParent)) { return; } provider.textDocumentFactoryService.TryGetTextDocument(view.TextDataModel.DocumentBuffer, out var textDocument); // This is a bit hacky, since AsyncQuickInfo is designed to display multiple elements if multiple sources // return value, we don't want that for debugger value hovering, hence we dismiss AsyncQuickInfo // and do our own thing, notice VS does same thing await session.DismissAsync(); await provider.joinableTaskContext.Factory.SwitchToMainThreadAsync(); lastView = view; val.Name = debugInfo.Text; #if MAC var location = new PinnedWatchLocation(textDocument?.FilePath); var snapshot = view.TextDataModel.DocumentBuffer.CurrentSnapshot; int line, column; var start = debugInfo.Span.GetStartPoint(snapshot); snapshot.GetLineAndColumn(start, out line, out column); location.Column = column; location.Line = line; var end = debugInfo.Span.GetEndPoint(snapshot); snapshot.GetLineAndColumn(end, out line, out column); location.EndColumn = column; location.EndLine = line; window = new MacDebuggerTooltipWindow(location, DebuggingService.CurrentFrame, val, watch: null); view.LayoutChanged += LayoutChanged; #if CLOSE_ON_FOCUS_LOST view.LostAggregateFocus += View_LostAggregateFocus; #endif RegisterForHiddenAsync(view).Ignore(); var cocoaView = (ICocoaTextView)view; var bounds = view.TextViewLines.GetCharacterBounds(point); var rect = new CoreGraphics.CGRect(bounds.Left - view.ViewportLeft, bounds.Top - view.ViewportTop, bounds.Width, bounds.Height); window.Show(rect, cocoaView.VisualElement, AppKit.NSRectEdge.MaxXEdge); #else throw new NotImplementedException(); #endif }