void HandleGotoResponse(BackgroundRequest req) { if (req == null || req.Source == null || req.Source.IsClosed) return; // Make sure caret hasn't moved since we kicked this off. TextSpan[] aSpan = new TextSpan[1]; int line, col; NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col)); if (req.Line != line || req.Col != col) return; // caret has moved. string url = null; TextSpan span; IntellisenseInfo scope = req.ResultIntellisenseInfo; if (scope != null && gotoCmd == VSConstants.VSStd97CmdID.GotoDefn) { var gotoResult = scope.Goto(textView, line, col); if (!gotoResult.Success) { ShowErrorMessageBox(gotoResult.ErrorDescription); return; } url = gotoResult.Url; span = gotoResult.Span; } else { return; } if (url == null || url.Trim().Length == 0) { // nothing to show return; } // Open the referenced document, and scroll to the given location. IVsUIHierarchy hierarchy; uint itemID; IVsWindowFrame frame; IVsTextView view; VsShell.OpenDocument(this.service.Site, url, NativeMethods.LOGVIEWID_Code, out hierarchy, out itemID, out frame, out view); if (view != null) { TextSpanHelper.MakePositive(ref span); NativeMethods.ThrowOnFailure(view.SendExplicitFocus()); NativeMethods.ThrowOnFailure(view.EnsureSpanVisible(span)); NativeMethods.ThrowOnFailure(view.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex)); } }
private void HandleMethodTipResponse(BackgroundRequest req) { try { if (this.service == null) return; // Don't do anything if the buffer is out of sync if (req.Timestamp != this.ChangeCount) return; HandleResponseHelper(req); if (req.Timestamp != this.ChangeCount) { // The user has been typing since we sent off the snapshot to be parsed // TODO maybe this gets into infinite loop of wasted work if something goes wrong this.MethodTip(req.View, req.Line, req.Col, req.TokenInfo, req.MethodTipMiscellany, RequireFreshResults.No); // try again, need up-to-date parse } else { MethodListForAMethodTip methods = req.ResultScope.GetMethodListForAMethodTip(true); if (methods != null) { TextSpan spanNotToObscureWithTipPopup = new TextSpan(); spanNotToObscureWithTipPopup.iStartLine = methods.GetNoteworthyParamInfoLocations()[0].Item1 - 1; // is 1-based, need 0-based spanNotToObscureWithTipPopup.iStartIndex = methods.GetNoteworthyParamInfoLocations()[0].Item2 - 1; // is 1-based, need 0-based spanNotToObscureWithTipPopup.iEndLine = req.Line; spanNotToObscureWithTipPopup.iEndIndex = req.Col; this.methodData.Refresh(req.View, methods, spanNotToObscureWithTipPopup, req.MethodTipMiscellany); } else if (req.MethodTipMiscellany == MethodTipMiscellany.JustPressedOpenParen && req.Timestamp != req.ResultTimestamp) { // Second-chance param info: we didn't get any result and the basis typecheck was stale. We need to retrigger the completion. this.MethodTip(req.View, req.Line, req.Col, req.TokenInfo, req.MethodTipMiscellany, RequireFreshResults.Yes); } else { DismissCompletor(); } } #if LANGTRACE } catch (Exception e) { Trace.WriteLine("HandleMethodTipResponse exception: " + e.Message); #endif } catch { } }
internal void GetDataTipResponse(BackgroundRequest req) { if (req == null || req.Source == null || req.Source.IsClosed) return; if ((req.ResultQuickInfoText != null) && TextSpanHelper.ContainsInclusive(req.ResultQuickInfoSpan, this.quickInfoRequestLine, this.quickInfoRequestCol)) { this.quickInfoText = req.ResultQuickInfoText; this.gotQuickInfo = true; this.quickInfoSpan = req.ResultQuickInfoSpan; } }
void HandleQuickInfoResponse(BackgroundRequest req){ if (req == null || req.Source == null || req.Source.IsClosed) return; int line; int col; // Get the caret position NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col)); string text = null; if (req.ResultIntellisenseInfo != null) { text = req.ResultQuickInfoText; if (text == null || !TextSpanHelper.ContainsInclusive(req.ResultQuickInfoSpan, line, col)) { return; // caret has moved. } } else { return; } string fullText; TextSpan ts = new TextSpan(); ts.iStartLine = ts.iEndLine = line; ts.iStartIndex = ts.iEndIndex = col; NativeMethods.ThrowOnFailure(GetFullDataTipText(text, ts, out fullText)); if (String.IsNullOrEmpty(fullText)) { return; } int iPos, iSpace, iLength; // Calculate the stream position NativeMethods.ThrowOnFailure(textView.GetNearestPosition(ts.iStartLine, ts.iStartIndex, out iPos, out iSpace)); iLength = 0; // Tear down the method tip window if it's there this.source.DismissCompletor(); // Update the text tip window TextTipData textTipData = this.TextTipData; textTipData.Update(fullText, iPos, iLength, this.textView); }
internal BackgroundRequestAsyncResult(BackgroundRequest req, ManualResetEvent globalRequestCompletedEvent) { this.globalRequestCompletedEvent = globalRequestCompletedEvent; this.req = req; }
/// <summary>Override this method if you need to do any post-parse work on the main UI thread. /// Be sure to call this base method in order to get the dynamic help context updated.</summary> internal virtual void OnUntypedParseOrFullTypeCheckComplete(BackgroundRequest req) { if (req == null || req.Source == null || req.Source.IsClosed) return; SetUserContextDirty(req.FileName); RefreshUI(); }
private static RequestType GetRequestType(BackgroundRequest r) { switch (r.Reason) { case BackgroundRequestReason.UntypedParse: case BackgroundRequestReason.FullTypeCheck: return RequestType.NonUi; default: return RequestType.Ui; } }
public void HandleResponseHelper(BackgroundRequest req) { try { if (this.service == null) return; // If the request is out of sync with the buffer, then the error spans // and hidden regions could be wrong, so we ignore this parse and wait // for the next OnIdle parse. if (req.ResultClearsDirtinessOfFile && req.Timestamp == this.ChangeCount) { this.RecordViewRefreshed(); if (req.ResultScope != null) { int end = Environment.TickCount; if (req.StartTimeForOnIdleRequest != 0 && end > req.StartTimeForOnIdleRequest) { #if LANGTRACE Trace.WriteLine("BackgroundRequest in " + (end - start) + " ticks"); #endif this.lastOnIdleRequestDuration = end - req.StartTimeForOnIdleRequest; // for OnIdle loop } if (req.View == this.service.LastActiveTextView) { this.service.RecentFullTypeCheckResults = req.ResultScope; this.service.RecentFullTypeCheckFile = req.FileName; } ReportTasks(req.ResultSink.errors); } this.service.OnUntypedParseOrFullTypeCheckComplete(req); } } catch { } }
/// <summary> /// Gets request from queue /// </summary> /// <returns></returns> public BackgroundRequest Dequeue() { lock (syncRoot) { Debug.Assert(first != null); var tmp = first; first = second; second = null; return tmp; } }
/// <summary> /// Discards all requests added so far and enqueues specified request. /// </summary> public void Set(BackgroundRequest r) { lock (syncRoot) { first = null; second = null; Enqueue(r); } }
internal abstract void ExecuteBackgroundRequest(BackgroundRequest req);
/// <summary> /// Checks if request queue contains request similar to the given one. /// </summary> public bool ContainsSimilarRequest(BackgroundRequest request) { var requestType = GetRequestType(request); lock (syncRoot) { if (first == null) { // 0 items return false; } else if (second == null) { // 1 item return requestType == GetRequestType(first); } else { // 2 items (both Ui and non-Ui) return true; } } }
public void Enqueue(BackgroundRequest newRequest) { if (newRequest == null) throw new ArgumentNullException("newRequest"); lock (syncRoot) { if (first == null) { // 0-items // just add request to the queue first = newRequest; } else if (second == null) { // 1-item var currentType = GetRequestType(newRequest); var previousType = GetRequestType(first); if (currentType == RequestType.Ui || (currentType == previousType)) { // - Ui requests discard everything // - non-Ui request discard non-Ui request first = newRequest; } else { // we got here if current type is non-Ui and prev type is Ui second = newRequest; } } else { // 2 items // the only situation with we can have 2 requests in queue is [Ui; Non-Ui] Debug.Assert(GetRequestType(first) == RequestType.Ui); Debug.Assert(GetRequestType(second) == RequestType.NonUi); var requestType = GetRequestType(newRequest); if (requestType == RequestType.Ui) { // discard both old requests first = newRequest; second = null; } else { // replace non-Ui request with a new one second = newRequest; } } } }
public void HandleMatchBracesResponse(BackgroundRequest req) { try { if (this.service == null || req.Timestamp != this.ChangeCount) return; // save request so it can later be reused in GetPairExtent HandleGetPairExtentResponse(req); #if LANGTRACE Trace.WriteLine("HandleMatchBracesResponse"); #endif // Filter matching braces and find spans to highlight - we want to highlight // matches only before opening and after closing brace int line; int idx; NativeMethods.ThrowOnFailure(req.View.GetCaretPos(out line, out idx)); // Get all braces from language service and filter them List<BraceMatch> braces = new List<BraceMatch>(); foreach (BraceMatch m in req.ResultSink.Braces) braces.Add(m); braces.RemoveAll(delegate(BraceMatch match) { if (match.a.iStartLine == line && match.a.iStartIndex == idx) return false; if (match.b.iEndLine == line && match.b.iEndIndex == idx) return false; return true; }); // Transform collection of braces into an array of spans List<TextSpan> spans = new List<TextSpan>(); foreach (BraceMatch m in braces) { spans.Add(m.a); spans.Add(m.b); } // Highlight if (spans.Count == 0) return; NativeMethods.ThrowOnFailure(req.View.HighlightMatchingBrace((uint)this.service.Preferences.HighlightMatchingBraceFlags, (uint)spans.Count, spans.ToArray())); //try to show the matching line in the statusbar if (spans.Count > 0 && this.service.Preferences.EnableShowMatchingBrace) { IVsStatusbar statusBar = (IVsStatusbar)service.Site.GetService(typeof(SVsStatusbar)); if (statusBar != null) { TextSpan span = spans[0]; bool found = false; // Gather up the other side of the brace match so we can // display the text in the status bar. There could be more than one // if MatchTriple was involved, in which case we merge them. for (int i = 0, n = spans.Count; i < n; i++) { TextSpan brace = spans[i]; if (brace.iStartLine != req.Line) { if (brace.iEndLine != brace.iStartLine) { brace.iEndLine = brace.iStartLine; brace.iEndIndex = this.GetLineLength(brace.iStartLine); } if (!found) { span = brace; } else if (brace.iStartLine == span.iStartLine) { span = TextSpanHelper.Merge(span, brace); } found = true; } } if (found) { Debug.Assert(TextSpanHelper.IsPositive(span)); string text = this.GetText(span); int start; int len = text.Length; for (start = 0; start < len && Char.IsWhiteSpace(text[start]); start++) ; if (start < span.iEndIndex) { if (text.Length > 80) { text = String.Format(CultureInfo.CurrentUICulture, SR.GetString(SR.Truncated), text.Substring(0, 80)); } text = String.Format(CultureInfo.CurrentUICulture, SR.GetString(SR.BraceMatchStatus), text); NativeMethods.ThrowOnFailure(statusBar.SetText(text)); } } } } #if LANGTRACE } catch (Exception e) { Trace.WriteLine("HandleMatchBracesResponse exception: " + e.Message); #endif } catch { } }
internal void HandleUpdateLanguageContextResponse(BackgroundRequest req) { }
void HandleGetPairExtentResponse(BackgroundRequest request) { if (this.service == null) { return; } this.lastBraceMatchRequest = request; }
internal BackgroundRequestAsyncResult BeginBackgroundRequest(BackgroundRequest request, BackgroundRequestResultHandler handler) { EnsureBackgroundThreadStarted(); lock (this) { request.Callback = handler; this.requests.Enqueue(request); this.isServingBackgroundRequest = true; this.backgroundRequestPending.Set(); this.backgroundRequestDone.Reset(); // Return a capability to wait on the completion of the background request return new BackgroundRequestAsyncResult(request, this.backgroundRequestDone); } }
public void HandleUntypedParseOrFullTypeCheckResponse(BackgroundRequest req) { if (this.service == null) return; try { Debug.Assert((req.Reason == BackgroundRequestReason.UntypedParse || req.Reason == BackgroundRequestReason.FullTypeCheck), "this callback is being used for the wrong type of parse request"); #if LANGTRACE Trace.WriteLine("HandleUntypedParseOrFullTypeCheckResponse:" + req.Timestamp); #endif if (this.service == null) return; HandleResponseHelper(req); #if LANGTRACE } catch (Exception e) { Trace.WriteLine("HandleUntypedParseOrFullTypeCheckResponse exception: " + e.Message); #endif } catch { } }
// Implemented in FSharpLanguageService.fs internal abstract void OnParseFileOrCheckFileComplete(BackgroundRequest req);