Example #1
0
        public void Refresh(MethodTipMiscellany methodTipMiscellany)
        {
            var wpfTextView = SourceImpl.GetWpfTextViewFromVsTextView(textView);
            var ranges = methods.GetParameterRanges();
            Debug.Assert(ranges != null && ranges.Length > 0);

            // Don't do anything for open parens and commas that aren't intrinsic to a method call
            if (!this.displayed && methodTipMiscellany == MethodTipMiscellany.JustPressedCloseParen)
            {
                return;  // close paren must never cause it to appear
            }
            if (!this.displayed && methodTipMiscellany == MethodTipMiscellany.JustPressedOpenParen)
            {
                // the only good open paren is the start of the first param, don't want to cause a tip to be displayed $here$:  foo(x, $($y+z), w)
                if (!ranges[0].GetSpan(wpfTextView.TextSnapshot).Start.Equals(wpfTextView.Caret.Position.BufferPosition))
                    return;
            }
            if (!this.displayed && methodTipMiscellany == MethodTipMiscellany.JustPressedComma)
            {
                // the only good commas will be, interestingly, at the start of the following param span
                // this by virtue of fact that we assume comma is one character after where the previous parameter range ends (and thus the first character of the next range)
                var ok = false;
                for (int i = 1; i < ranges.Length; ++i)
                {
                    if (ranges[i].GetSpan(wpfTextView.TextSnapshot).Start.Equals(wpfTextView.Caret.Position.BufferPosition))
                    {
                        ok = true;
                        break;
                    }
                }
                if (!ok)
                    return;
            }

            // Figure out which parameter we are in based on location of caret within the parse
            var caretPoint = wpfTextView.Caret.Position.BufferPosition;
            var endOfLinePoint = wpfTextView.Caret.ContainingTextViewLine.End;
            bool caretIsAtEndOfLine = caretPoint == endOfLinePoint;
            this.currentParameter = -1;
            for (int i = ranges.Length - 1; i >= 0; --i) // need to traverse backwards, so that "f(1," at end of line sets curParam to 1, not 0
            {
                if (ranges[i].GetSpan(wpfTextView.TextSnapshot).Contains(caretPoint)
                    // ranges are half-open [...), so end-of-line is a special case...
                    || caretIsAtEndOfLine
                       && ranges[i].GetSpan(wpfTextView.TextSnapshot).End == caretPoint
                       && !(i == ranges.Length - 1 && this.methods.IsThereACloseParen())) // ...except on the closing paren (when caret at close paren, should dismiss tip, even if at EOL)
                {
                    this.currentParameter = i;
                    break;
                }
            }
            if (this.currentParameter == -1)
            {
                // a bit of a kludge; if they just backspaced over the last comma and there's no close parenthesis, the caret is just to the right of all the param
                // ranges, but we don't want to dismiss the tip.  so look just left of the caret and see if that would be inside the final param
                if (methodTipMiscellany == MethodTipMiscellany.JustPressedBackspace
                    && ranges[ranges.Length - 1].GetSpan(wpfTextView.TextSnapshot).Contains(wpfTextView.Caret.Position.BufferPosition.Subtract(1)))
                {
                    this.currentParameter = ranges.Length - 1;
                }
                else
                {
                    // the caret moved left of the open parenthesis or right of the close parenthesis
                    this.currentParameter = 0;
                    this.Dismiss();
                }
            }
            // possibly select a method from overload list based on current num of params the user has
            if (methodTipMiscellany == MethodTipMiscellany.ExplicitlyInvokedViaCtrlShiftSpace
                || methodTipMiscellany == MethodTipMiscellany.JustPressedComma)
            {
                Debug.Assert(this.methods != null, "this can happen if we just called Dismiss() because we erroneously decided the caret moves outside the parens");

                var actualParamNames = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(this.methods.GetParameterNames(), s => null != s));

                int numOfParamsUserHasSoFar = methods.GetNoteworthyParamInfoLocations().Length - 3; // -3 because first 3 ranges are [LID.start, LID.end, Paren], rest are params
                // however note that this is never zero, "foo(" and "foo(x"  both report 1

                int curMeth = this.currentMethod;  // start wherever the user already is.  the methods are already ordered in increasing order-of-params; only can increase of user has longer param list.
                while (curMeth < this.methods.GetCount()
                       && this.methods.GetParameterCount(curMeth) < numOfParamsUserHasSoFar
                       // if we're on a zero-arg overload, don't go past it when user has one arg; be like C#, good for e.g. Console.WriteLine(
                       && !(numOfParamsUserHasSoFar == 1 && this.methods.GetParameterCount(curMeth) == 0))
                {
                    curMeth++;
                }
                if (curMeth == this.methods.GetCount())
                {
                    // if they have 'too many' parameters, always just start at the beginning of the list
                    curMeth = 0;
                }
                else if (actualParamNames.Count > 0)
                {
                    // there are named parameters, additionally ensure the selected overload has those names, or keep advancing until it does
                    while (curMeth < this.methods.GetCount()
                           && !FormalParamNames(this.methods, curMeth).IsSupersetOf(actualParamNames))
                    {
                        curMeth++;
                    }
                }
                this.currentMethod = curMeth;
            }
            else
            {
                // in other cases, don't update which overload we're on, the user is in control
            }
            this.UpdateView();
        }
Example #2
0
        public BackgroundRequest BeginBackgroundRequest(int line, int idx, TokenInfo info, BackgroundRequestReason reason, IVsTextView view, RequireFreshResults requireFreshResults, BackgroundRequestResultHandler callback, MethodTipMiscellany methodTipMiscellany = 0)
        {
            var wpfTextView = GetWpfTextViewFromVsTextView(view);
            var snapshot = wpfTextView.TextSnapshot;

            if (this.disposed) return null;
            string fname = this.GetFilePath();

            Debug.Assert(snapshot != null);
            Debug.Assert(callback != null);

            // Check if we can shortcut executing the background request and just fill in the latest
            // cached scope for the active view from this.service.RecentFullTypeCheckResults.
            //
            // This must only kick in if ExecuteBackgroundRequest is equivalent to fetching a recent,
            // perhaps out-of-date scope.
            if (!this.NeedsVisualRefresh &&
                this.service.IsRecentScopeSufficientForBackgroundRequest(reason) &&
                (this.service.RecentFullTypeCheckResults != null) &&
                this.service.RecentFullTypeCheckFile.Equals(fname) &&
                requireFreshResults != RequireFreshResults.Yes)
            {
                BackgroundRequest request = this.service.CreateBackgroundRequest(this, line, idx, info, null, snapshot, methodTipMiscellany, fname, reason, view);
                request.ResultScope = this.service.RecentFullTypeCheckResults;
                request.ResultClearsDirtinessOfFile = false;
                request.Timestamp = this.ChangeCount;
                request.IsSynchronous = true;
                callback(request);
                return request;
            }
            else
            {

                string text = this.GetText(); // get all the text
                BackgroundRequest request = this.service.CreateBackgroundRequest(this, line, idx, info, text, snapshot, methodTipMiscellany, fname, reason, view);
                request.Timestamp = this.ChangeCount;
                request.DirtySpan = this.dirtySpan;
                request.RequireFreshResults = requireFreshResults;

                if (!this.LanguageService.Preferences.EnableAsyncCompletion)
                {
                    request.IsSynchronous = true; //unless registry value indicates that sync ops always prefer async 
                }
                if (request.IsSynchronous)
                {
                    this.service.ExecuteBackgroundRequest(request);
                    callback(request);
                }
                else
                {
                    request.result = this.service.BeginBackgroundRequest(request, callback);
                }
                return request;
            }
        }
Example #3
0
 public void Refresh(IVsTextView textView, MethodListForAMethodTip methods, TextSpan context, MethodTipMiscellany methodTipMiscellany)
 {
     bool needToDismissNow = false;
     if (this.displayed && methodTipMiscellany == MethodTipMiscellany.JustPressedBackspace
         && MethodsSeemToDiffer(this.methods, methods))
     {
         // We just hit backspace, and apparently the 'set of methods' changed.  This most commonly happens in a case like
         //     foo(42, bar(    // in a tip for bar(), now press backspace
         //     foo(42, bar     // now we're in a location where we'd be in a tip for foo()
         // and we want to dismiss the tip.
         needToDismissNow = true;
     }
     this.methods = methods;
     if (nativeStringsCacheForOverloads != null)
     {
         nativeStringsCacheForOverloads.Free();
     }
     nativeStringsCacheForOverloads = new NativeStringsCacheForOverloads(methods.GetCount(), this);
     this.context = context;
     this.textView = textView;
     if (needToDismissNow)
     {
         this.Dismiss();
     }
     else
     {
         this.Refresh(methodTipMiscellany);
     }
 }
Example #4
0
 public void MatchBracesAndMethodTip(IVsTextView textView, int line, int index, MethodTipMiscellany misc, TokenInfo info)
 {
     this.BeginBackgroundRequest(
         line, 
         index, 
         info, 
         BackgroundRequestReason.MatchBracesAndMethodTip, 
         textView, 
         RequireFreshResults.No, 
         req =>
             {
                 HandleMatchBracesResponse(req);
                 HandleMethodTipResponse(req);
             }
         );
 }
Example #5
0
 public void MethodTip(IVsTextView textView, int line, int index, TokenInfo info, MethodTipMiscellany methodTipMiscellany, RequireFreshResults requireFreshResults)
 {
     this.BeginBackgroundRequest(line, index, info, BackgroundRequestReason.MethodTip, textView, requireFreshResults, new BackgroundRequestResultHandler(this.HandleMethodTipResponse), methodTipMiscellany);
 }
Example #6
0
 // Implemented in servicem.fs
 internal abstract BackgroundRequest CreateBackgroundRequest(int line, int col, TokenInfo info, string sourceText, ITextSnapshot snapshot, MethodTipMiscellany methodTipMiscellany, string fname,
                          BackgroundRequestReason reason, IVsTextView view,
                          AuthoringSink sink, ISource source, int timestamp, bool synchronous);
Example #7
0
 internal BackgroundRequest CreateBackgroundRequest(SourceImpl s, int line, int idx, TokenInfo info, string sourceText, ITextSnapshot snapshot, MethodTipMiscellany methodTipMiscellany,
                                                    string fname, BackgroundRequestReason reason, IVsTextView view)
 {
     // We set this to "false" because we are effectively abandoning any currently executing background request, e.g. an OnIdle request
     this.isServingBackgroundRequest = false;
     bool sync = false;
     if (!this.Preferences.EnableAsyncCompletion)
     {
         sync = true; //unless registry value indicates that sync ops always prefer async 
     }
     return CreateBackgroundRequest(line, idx, info, sourceText, snapshot, methodTipMiscellany, fname, reason, view, s.CreateAuthoringSink(reason, line, idx), s, s.ChangeCount, sync);
 }
Example #8
0
        internal BackgroundRequest(int line, int col, TokenInfo info, string src, ITextSnapshot snapshot, MethodTipMiscellany methodTipMiscellany, string fname,
                                 BackgroundRequestReason reason, IVsTextView view,
                                 AuthoringSink sink, ISource source, int timestamp, bool synchronous)
        {
            this.Source = source;
            this.Timestamp = timestamp;
            this.Line = line;
            this.Col = col;
            this.FileName = fname;
            this.Text = src;
            this.Reason = reason;
            this.View = view;
            this.Snapshot = snapshot;
            this.MethodTipMiscellany = methodTipMiscellany;
            this.ResultSink = sink;
            this.TokenInfo = info;
            this.isSynchronous = synchronous;

            this.ResultScope = null;
            this.ResultClearsDirtinessOfFile = false;
        }