Inheritance: AstNode
        public static bool FormatRange(ITextView textView, ITextBuffer textBuffer, ITextRange formatRange,
                                       AstRoot ast, RFormatOptions options, bool respectUserIndent = true) {
            ITextSnapshot snapshot = textBuffer.CurrentSnapshot;
            int start = formatRange.Start;
            int end = formatRange.End;

            // When user clicks editor margin to select a line, selection actually
            // ends in the beginning of the next line. In order to prevent formatting
            // of the next line that user did not select, we need to shrink span to
            // format and exclude the trailing line break.
            ITextSnapshotLine line = snapshot.GetLineFromPosition(formatRange.End);

            if (line.Start.Position == formatRange.End && formatRange.Length > 0) {
                if (line.LineNumber > 0) {
                    line = snapshot.GetLineFromLineNumber(line.LineNumber - 1);
                    end = line.End.Position;
                    start = Math.Min(start, end);
                }
            }

            // Expand span to include the entire line
            ITextSnapshotLine startLine = snapshot.GetLineFromPosition(start);
            ITextSnapshotLine endLine = snapshot.GetLineFromPosition(end);

            formatRange = TextRange.FromBounds(startLine.Start, endLine.End);
            return FormatRangeExact(textView, textBuffer, formatRange, ast, options, -1, respectUserIndent);
        }
Beispiel #2
0
        public string WriteTree(AstRoot ast) {
            _sb = new StringBuilder();
            _indent = 0;
            _ast = ast;

            foreach (IAstNode node in ast.Children) {
                WriteNode(node);
            }

            if (_ast.Errors.Count > 0) {
                _sb.AppendLine();

                foreach (var error in _ast.Errors) {
                    _sb.AppendFormat(CultureInfo.InvariantCulture,
                        "{0} {1} [{2}...{3})\r\n",
                        error.ErrorType.ToString(), error.Location.ToString(),
                        error.Start, error.End);
                }
            }

            string text = _sb.ToString();

            _sb = null;
            _ast = null;

            return text;
        }
        private static bool GetFunction(AstRoot astRoot, ref int position, out FunctionCall functionCall, out Variable functionVariable)
        {
            functionVariable = null;
            functionCall = astRoot.GetNodeOfTypeFromPosition<FunctionCall>(position);

            if (functionCall == null && position > 0)
            {
                // Retry in case caret is at the very end of function signature
                // that does not have final close brace yet.
                functionCall = astRoot.GetNodeOfTypeFromPosition<FunctionCall>(position - 1, includeEnd: true);
                if(functionCall != null)
                {
                    // But if signature does have closing brace and caret
                    // is beyond it, we are really otuside of the signature.
                    if(functionCall.CloseBrace != null && position >= functionCall.CloseBrace.End) {
                        return false;
                    }

                    if (position > functionCall.SignatureEnd) {
                        position = functionCall.SignatureEnd;
                    }
                }
            }

            if (functionCall != null && functionCall.Children.Count > 0)
            {
                functionVariable = functionCall.Children[0] as Variable;
                return functionVariable != null;
            }

            return false;
        }
 public RCompletionContext(ICompletionSession session, ITextBuffer textBuffer, AstRoot ast, int position)
 {
     Session = session;
     TextBuffer = textBuffer;
     Position = position;
     AstRoot = ast;
 }
        internal int ComputeCurrentParameter(ITextSnapshot snapshot, AstRoot ast, int position) {
            ParameterInfo parameterInfo = SignatureHelp.GetParametersInfoFromBuffer(ast, snapshot, position);
            int index = 0;

            if (parameterInfo != null) {
                index = parameterInfo.ParameterIndex;
                if (parameterInfo.NamedParameter) {
                    // A function f <- function(foo, bar) is said to have formal parameters "foo" and "bar", 
                    // and the call f(foo=3, ba=13) is said to have (actual) arguments "foo" and "ba".
                    // R first matches all arguments that have exactly the same name as a formal parameter. 
                    // Two identical argument names cause an error. Then, R matches any argument names that
                    // partially matches a(yet unmatched) formal parameter. But if two argument names partially 
                    // match the same formal parameter, that also causes an error. Also, it only matches 
                    // formal parameters before ... So formal parameters after ... must be specified using 
                    // their full names. Then the unnamed arguments are matched in positional order to 
                    // the remaining formal arguments.

                    int argumentIndexInSignature = _signatureInfo.GetArgumentIndex(parameterInfo.ParameterName, REditorSettings.PartialArgumentNameMatch);
                    if (argumentIndexInSignature >= 0) {
                        index = argumentIndexInSignature;
                    }
                }
            }
            return index;
        }
Beispiel #6
0
 public ParseContext(ITextProvider textProvider, ITextRange range, TokenStream<RToken> tokens, IReadOnlyList<RToken> comments, IExpressionTermFilter filter = null) {
     AstRoot = new AstRoot(textProvider);
     TextProvider = textProvider;
     Tokens = tokens;
     TextRange = range;
     Scopes = new Stack<IScope>();
     Expressions = new Stack<Expression>();
     Comments = comments;
     ExpressionTermFilter = filter ?? new DefaultExpressionTermFilter();
 }
Beispiel #7
0
        public static void CompareTrees(string expected, AstRoot actualTree)
        {
            AstWriter astWriter = new AstWriter();
            string actual = astWriter.WriteTree(actualTree);
            
            string expectedLine, actualLine;
            int index;
            int result = BaselineCompare.CompareLines(expected, actual, out expectedLine, out actualLine, out index);

            result.Should().Be(0, "Line at {0} should be {1}, but found {2}, different at position {3}", result, expectedLine, actualLine, index);
        }
        internal static Task AugmentSignatureHelpSessionAsync(this SignatureHelpSource signatureHelpSource, ISignatureHelpSession session, IList<ISignature> signatures, AstRoot ast) {
            var tcs = new TaskCompletionSource<object>();

            var ready = signatureHelpSource.AugmentSignatureHelpSession(session, signatures, ast, (o, p) => {
                signatureHelpSource.AugmentSignatureHelpSession(session, signatures, ast, null);
                tcs.TrySetResult(null);
            });

            if (ready) {
                tcs.TrySetResult(null);
            }

            return tcs.Task;
        }
        /// <summary>
        /// Given position in a text buffer finds method name.
        /// </summary>
        public static string GetFunctionNameFromBuffer(AstRoot astRoot, ref int position, out int signatureEnd)
        {
            FunctionCall functionCall;
            Variable functionVariable;

            signatureEnd = -1;

            if (GetFunction(astRoot, ref position, out functionCall, out functionVariable))
            {
                signatureEnd = functionCall.End;
                return functionVariable.Name;
            }

            return null;
        }
Beispiel #10
0
        public static void CompareTrees(EditorTree editorTree, AstRoot tree2)
        {
#if ___DEBUG
            var cc1 = editorTree.ParseTree.CommentCollection;
            var cc2 = tree2.CommentCollection;

            Debug.Assert(cc1.Count == cc2.Count);
            for (int i = 0; i < cc1.Count; i++)
            {
                Debug.Assert(cc1[i].Start == cc2[i].Start);
                Debug.Assert(cc1[i].Length == cc2[i].Length);
            }

            CompareNodes(editorTree, editorTree.ParseTree.RootNode, tree2.RootNode);
#endif
        }
        internal static Task<ITrackingSpan> AugmentQuickInfoSessionAsync(this QuickInfoSource quickInfoSource, AstRoot ast, int caretPosition, IQuickInfoSession quickInfoSession, IList<object> quickInfoContent) {
            var tcs = new TaskCompletionSource<ITrackingSpan>();

            ITrackingSpan applicableSpan;
            var ready = quickInfoSource.AugmentQuickInfoSession(ast, caretPosition, quickInfoSession, quickInfoContent, out applicableSpan, (o, p) => {
                ITrackingSpan result;
                quickInfoSource.AugmentQuickInfoSession(ast, caretPosition, quickInfoSession, quickInfoContent, out result, null, p);
                tcs.TrySetResult(result);
            }, null);

            if (ready) {
                tcs.TrySetResult(applicableSpan);
            }

            return tcs.Task;
        }
Beispiel #12
0
        internal bool AugmentQuickInfoSession(AstRoot ast, int position, IQuickInfoSession session,
                                              IList<object> quickInfoContent, out ITrackingSpan applicableToSpan,
                                              Action<object, string> retriggerAction, string packageName) {
            int signatureEnd = position;
            applicableToSpan = null;

            string functionName = SignatureHelp.GetFunctionNameFromBuffer(ast, ref position, out signatureEnd);
            if (!string.IsNullOrEmpty(functionName)) {
                ITextSnapshot snapshot = session.TextView.TextBuffer.CurrentSnapshot;

                position = Math.Min(signatureEnd, position);
                int start = Math.Min(position, snapshot.Length);
                int end = Math.Min(signatureEnd, snapshot.Length);

                applicableToSpan = snapshot.CreateTrackingSpan(Span.FromBounds(start, end), SpanTrackingMode.EdgeInclusive);
                packageName = packageName ?? _packageName;
                _packageName = null;

                var functionInfo = FunctionIndex.GetFunctionInfo(functionName, packageName, retriggerAction, session);

                if (functionInfo != null && functionInfo.Signatures != null) {
                    foreach (ISignatureInfo sig in functionInfo.Signatures) {
                        string signatureString = sig.GetSignatureString(functionName);
                        int wrapLength = Math.Min(SignatureInfo.MaxSignatureLength, signatureString.Length);
                        string text;

                        if (string.IsNullOrWhiteSpace(functionInfo.Description)) {
                            text = string.Empty;
                        } else {
                            /// VS may end showing very long tooltip so we need to keep 
                            /// description reasonably short: typically about
                            /// same length as the function signature.
                            text = signatureString + "\r\n" + functionInfo.Description.Wrap(wrapLength);
                        }

                        if (text.Length > 0) {
                            quickInfoContent.Add(text);
                            return true;
                        }
                    }
                }
            }

            return false;
        }
Beispiel #13
0
        /// <summary>
        /// Attempts to insert Roxygen documentation block based
        /// on the user function signature.
        /// </summary>
        public static bool TryInsertBlock(ITextBuffer textBuffer, AstRoot ast, int position) {
            // First determine if position is right before the function declaration
            var snapshot = textBuffer.CurrentSnapshot;
            ITextSnapshotLine line = null;
            var lineNumber = snapshot.GetLineNumberFromPosition(position);
            for (int i = lineNumber; i < snapshot.LineCount; i++) {
                line = snapshot.GetLineFromLineNumber(i);
                if (line.Length > 0) {
                    break;
                }
            }

            if (line == null || line.Length == 0) {
                return false;
            }

            Variable v;
            int offset = line.Length - line.GetText().TrimStart().Length + 1;
            if (line.Start + offset >= snapshot.Length) {
                return false;
            }

            IFunctionDefinition fd = FunctionDefinitionExtensions.FindFunctionDefinition(textBuffer, ast, line.Start + offset, out v);
            if (fd != null && v != null && !string.IsNullOrEmpty(v.Name)) {

                int definitionStart = Math.Min(v.Start, fd.Start);
                Span? insertionSpan = GetRoxygenBlockPosition(snapshot, definitionStart);
                if (insertionSpan.HasValue) {
                    string lineBreak = snapshot.GetLineFromPosition(position).GetLineBreakText();
                    if (string.IsNullOrEmpty(lineBreak)) {
                        lineBreak = "\n";
                    }
                    string block = GenerateRoxygenBlock(v.Name, fd, lineBreak);
                    if (block.Length > 0) {
                        if (insertionSpan.Value.Length == 0) {
                            textBuffer.Insert(insertionSpan.Value.Start, block + lineBreak);
                        } else {
                            textBuffer.Replace(insertionSpan.Value, block);
                        }
                        return true;
                    }
                }
            }
            return false;
        }
        public static bool FormatRangeExact(ITextView textView, ITextBuffer textBuffer, ITextRange formatRange,
                                            AstRoot ast, RFormatOptions options, 
                                            int scopeStatementPosition, bool respectUserIndent = true) {
            ITextSnapshot snapshot = textBuffer.CurrentSnapshot;
            Span spanToFormat = new Span(formatRange.Start, formatRange.Length);
            string spanText = snapshot.GetText(spanToFormat.Start, spanToFormat.Length);
            string trimmedSpanText = spanText.Trim();

            if (trimmedSpanText == "}") {
                // Locate opening { and its statement
                var scopeNode = ast.GetNodeOfTypeFromPosition<IAstNodeWithScope>(spanToFormat.Start);
                if (scopeNode != null) {
                    scopeStatementPosition = scopeNode.Start;
                }
            }

            RFormatter formatter = new RFormatter(options);
            string formattedText = formatter.Format(trimmedSpanText);

            formattedText = formattedText.Trim(); // there may be inserted line breaks after {
            formattedText = IndentLines(textBuffer, spanToFormat.Start, ast, formattedText, options, scopeStatementPosition, respectUserIndent);

            if (!spanText.Equals(formattedText, StringComparison.Ordinal)) {
                var selectionTracker = new RSelectionTracker(textView, textBuffer);
                RTokenizer tokenizer = new RTokenizer();
                IReadOnlyTextRangeCollection<RToken> oldTokens = tokenizer.Tokenize(spanText);
                IReadOnlyTextRangeCollection<RToken> newTokens = tokenizer.Tokenize(formattedText);
                IncrementalTextChangeApplication.ApplyChangeByTokens(
                    textBuffer,
                    new TextStream(spanText), new TextStream(formattedText),
                    oldTokens, newTokens,
                    formatRange,
                    Resources.AutoFormat, selectionTracker);
                return true;
            }

            return false;
        }
Beispiel #15
0
        public bool AugmentSignatureHelpSession(ISignatureHelpSession session, IList<ISignature> signatures, AstRoot ast, Action<object, string> triggerSession) {
            ITextSnapshot snapshot = _textBuffer.CurrentSnapshot;
            int position = session.GetTriggerPoint(_textBuffer).GetPosition(snapshot);

            // Retrieve parameter positions from the current text buffer snapshot
            ParameterInfo parametersInfo = SignatureHelp.GetParametersInfoFromBuffer(ast, snapshot, position);
            if (parametersInfo != null) {
                position = Math.Min(parametersInfo.SignatureEnd, position);
                int start = Math.Min(position, snapshot.Length);
                int end = Math.Min(parametersInfo.SignatureEnd, snapshot.Length);

                ITrackingSpan applicableToSpan = snapshot.CreateTrackingSpan(Span.FromBounds(start, end), SpanTrackingMode.EdgeInclusive);
                IFunctionInfo functionInfo = null;

                // First try user-defined function
                functionInfo = ast.GetUserFunctionInfo(parametersInfo.FunctionName, position);
                if (functionInfo == null) {
                    var functionIndex = _shell.ExportProvider.GetExportedValue<IFunctionIndex>();
                    // Then try package functions
                    var packageName = _packageName;
                    _packageName = null;
                    // Get collection of function signatures from documentation (parsed RD file)
                    functionInfo = functionIndex.GetFunctionInfo(parametersInfo.FunctionName, packageName, triggerSession, session);
                }

                if (functionInfo != null && functionInfo.Signatures != null) {
                    foreach (ISignatureInfo signatureInfo in functionInfo.Signatures) {
                        ISignature signature = CreateSignature(session, parametersInfo.FunctionName, functionInfo, signatureInfo, applicableToSpan, ast, position);
                        signatures.Add(signature);
                    }

                    session.Properties["functionInfo"] = functionInfo;
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Given position in a text buffer finds method name, 
        /// parameter index as well as where method signature ends.
        /// </summary>
        public static ParameterInfo GetParametersInfoFromBuffer(AstRoot astRoot, ITextSnapshot snapshot, int position)
        {
            FunctionCall functionCall;
            Variable functionVariable;
            int parameterIndex = -1;
            string parameterName;
            bool namedParameter = false;

            if (!GetFunction(astRoot, ref position, out functionCall, out functionVariable))
            {
                return null;
            }

            parameterIndex = functionCall.GetParameterIndex(position);
            parameterName = functionCall.GetParameterName(parameterIndex, out namedParameter);

            if (!string.IsNullOrEmpty(functionVariable.Name) && functionCall != null && parameterIndex >= 0)
            {
                return new ParameterInfo(functionVariable.Name, functionCall, parameterIndex, parameterName, namedParameter);
            }

            return null;
        }
Beispiel #17
0
        /// <summary>
        /// Populates R completion list for a given position
        /// </summary>
        /// <param name="position">Position in R text buffer</param>
        /// <param name="session">Completion session</param>
        /// <param name="completionSets">Completion sets to add to</param>
        /// <param name="ast">Document abstract syntax tree</param>
        internal void PopulateCompletionList(int position, ICompletionSession session, IList<CompletionSet> completionSets, AstRoot ast) {
            RCompletionContext context = new RCompletionContext(session, _textBuffer, ast, position);

            bool autoShownCompletion = true;
            if (session.TextView.Properties.ContainsProperty(CompletionController.AutoShownCompletion))
                autoShownCompletion = session.TextView.Properties.GetProperty<bool>(CompletionController.AutoShownCompletion);

            IReadOnlyCollection<IRCompletionListProvider> providers =
                RCompletionEngine.GetCompletionForLocation(context, autoShownCompletion, _shell);

            // Position is in R as is the applicable spa, so no need to map down
            Span? applicableSpan = GetApplicableSpan(position, session);
            if (applicableSpan.HasValue) {
                ITrackingSpan trackingSpan = context.TextBuffer.CurrentSnapshot.CreateTrackingSpan(applicableSpan.Value, SpanTrackingMode.EdgeInclusive);
                List<RCompletion> completions = new List<RCompletion>();
                bool sort = true;

                foreach (IRCompletionListProvider provider in providers) {
                    IReadOnlyCollection<RCompletion> entries = provider.GetEntries(context);
                    Debug.Assert(entries != null);

                    if (entries.Count > 0) {
                        completions.AddRange(entries);
                    }
                    sort &= provider.AllowSorting;
                }

                if (sort) {
                    completions.Sort(RCompletion.CompareOrdinal);
                    completions.RemoveDuplicates(RCompletion.CompareOrdinal);
                }

                CompletionSet completionSet = new RCompletionSet(session.TextView.TextBuffer, trackingSpan, completions);
                completionSets.Add(completionSet);
            }
        }
Beispiel #18
0
        private ISignature CreateSignature(ISignatureHelpSession session,
                                       string functionName, IFunctionInfo functionInfo, ISignatureInfo signatureInfo,
                                       ITrackingSpan span, AstRoot ast, int position) {
            SignatureHelp sig = new SignatureHelp(session, _textBuffer, functionName, string.Empty, signatureInfo, _shell);
            List<IParameter> paramList = new List<IParameter>();

            // Locus points in the pretty printed signature (the one displayed in the tooltip)
            var locusPoints = new List<int>();
            string signatureString = signatureInfo.GetSignatureString(functionName, locusPoints);
            sig.Content = signatureString;
            sig.ApplicableToSpan = span;

            sig.Documentation = functionInfo.Description?.Wrap(Math.Min(SignatureInfo.MaxSignatureLength, sig.Content.Length));

            Debug.Assert(locusPoints.Count == signatureInfo.Arguments.Count + 1);
            for (int i = 0; i < signatureInfo.Arguments.Count; i++) {
                IArgumentInfo p = signatureInfo.Arguments[i];
                if (p != null) {
                    int locusStart = locusPoints[i];
                    int locusLength = locusPoints[i + 1] - locusStart;

                    Debug.Assert(locusLength >= 0);
                    Span locus = new Span(locusStart, locusLength);

                    /// VS may end showing very long tooltip so we need to keep 
                    /// description reasonably short: typically about
                    /// same length as the function signature.
                    paramList.Add(
                        new SignatureParameter(
                            p.Description.Wrap(
                                Math.Min(SignatureInfo.MaxSignatureLength, sig.Content.Length)),
                                locus, locus, p.Name, sig));
                }
            }

            sig.Parameters = new ReadOnlyCollection<IParameter>(paramList);
            sig.ComputeCurrentParameter(ast, position);

            return sig;
        }
Beispiel #19
0
 public static IAstNode GetIndentDefiningNode(AstRoot ast, int position) {
     IScope scope = ast.GetNodeOfTypeFromPosition<IScope>(position);
     // Scope indentation is defined by its parent statement.
     IAstNodeWithScope parentStatement = scope.Parent as IAstNodeWithScope;
     if (parentStatement != null && parentStatement.Scope == scope) {
         return parentStatement;
     }
     return scope;
 }
 public TextChangeProcessor(EditorTree editorTree, AstRoot astRoot, Func<bool> cancelCallback = null) {
     _editorTree = editorTree;
     _astRoot = astRoot;
     _cancelCallback = cancelCallback;
 }
Beispiel #21
0
        /// <summary>
        /// Outlines comments that define sections such as
        /// # NAME ---
        /// </summary>
        /// <returns>True if names changed and outline regions need to be rebuilt</returns>
        private void OutlineSections(AstRoot ast, OutliningContext context) {
            // Collect comments that define sections
            var snapshot = EditorTree.TextSnapshot;
            var sections = ast.Comments.Where(c => {
                var text = snapshot.GetText(new Span(c.Start, c.Length));
                // Section looks like # [NAME] --------
                return text.TrimEnd().EndsWithOrdinal("---") && text.IndexOfAny(CharExtensions.LineBreakChars) < 0;
            }).ToArray();

            // Construct collapsible regions
            var ranges = new List<ITextRange>();
            for (int i = 0; i < sections.Length; i++) {
                var startLine = snapshot.GetLineFromPosition(sections[i].Start);
                int end = -1;

                var text = snapshot.GetText(new Span(sections[i].Start, sections[i].Length));
                var displayText = text.Substring(0, text.IndexOfOrdinal("---")).Trim();

                if (i < sections.Length - 1) {
                    var endLineNumber = snapshot.GetLineNumberFromPosition(sections[i + 1].Start);
                    if (endLineNumber > startLine.LineNumber) {
                        end = snapshot.GetLineFromLineNumber(endLineNumber - 1).End;
                    }
                } else {
                    end = snapshot.Length;
                }

                if (end > startLine.Start) {
                    ranges.Add(sections[i]);

                    // Trim trailing whitespace in user-defined regions
                    var range = TextRange.FromBounds(startLine.Start, end);
                    text = snapshot.GetText(new Span(range.Start, range.Length));
                    var trimBy = text.Length - text.TrimEnd().Length;
                    range = TextRange.FromBounds(range.Start, range.End - trimBy);

                    context.Regions.Add(new ROutlineRegion(EditorDocument.TextBuffer, range, displayText));
                }
            }

            // Track changes in section names
            _forceRegionsChange = _sections != null && _sections.Changed;

            _sections?.Dispose();
            _sections = new RSectionsCollection(EditorTree, ranges);
        }
Beispiel #22
0
 public static ITextView MakeTextView(string content, int caretPosition, out AstRoot ast) {
     ast = RParser.Parse(content);
     ITextBuffer textBuffer = new TextBufferMock(content, RContentTypeDefinition.ContentType);
     return new TextViewMock(textBuffer, caretPosition);
 }
Beispiel #23
0
        public virtual void ComputeCurrentParameter(AstRoot ast, int position) {
            if (Parameters == null || Parameters.Count == 0 || SubjectBuffer == null) {
                this.CurrentParameter = null;
                return;
            }

            var parameterIndex = ComputeCurrentParameter(SubjectBuffer.CurrentSnapshot, ast, position);
            if (parameterIndex < Parameters.Count) {
                this.CurrentParameter = Parameters[parameterIndex];
            } else {
                //too many commas, so use the last parameter as the current one.
                this.CurrentParameter = Parameters[Parameters.Count - 1];
            }
        }
Beispiel #24
0
        private bool IsClosingToken(RToken token, AstRoot ast = null) {
            switch (token.TokenType) {
                case RTokenType.Comma:
                case RTokenType.CloseBrace:
                case RTokenType.CloseSquareBracket:
                case RTokenType.CloseDoubleSquareBracket:
                case RTokenType.Semicolon:
                    return true;
            }

            return false;
        }
Beispiel #25
0
        /// <summary>
        /// Appends indentation to each line so formatted text appears properly 
        /// indented inside the host document (script block in HTML page).
        /// </summary>
        private static void IndentLines(ITextView textView, ITextBuffer textBuffer,
                                        ITextRange range, AstRoot ast,
                                        RFormatOptions options, int originalIndentSizeInSpaces) {
            ITextSnapshot snapshot = textBuffer.CurrentSnapshot;
            ITextSnapshotLine firstLine = snapshot.GetLineFromPosition(range.Start);
            ITextSnapshotLine lastLine = snapshot.GetLineFromPosition(range.End);

            IREditorDocument document = REditorDocument.TryFromTextBuffer(textBuffer);

            for (int i = firstLine.LineNumber; i <= lastLine.LineNumber; i++) {
                // Snapshot is updated after each insertion so do not cache
                ITextSnapshotLine line = textBuffer.CurrentSnapshot.GetLineFromLineNumber(i);
                int indent = SmartIndenter.GetSmartIndent(line, ast, originalIndentSizeInSpaces, formatting: true);
                if (indent > 0 && line.Length > 0 && line.Start >= range.Start) {
                    // Check current indentation and correct for the difference
                    int currentIndentSize = IndentBuilder.TextIndentInSpaces(line.GetText(), options.TabSize);
                    indent = Math.Max(0, indent - currentIndentSize);
                    if (indent > 0) {
                        string indentString = IndentBuilder.GetIndentString(indent, options.IndentType, options.TabSize);
                        textBuffer.Insert(line.Start, indentString);
                        if (document == null) {
                            // Typically this is a test scenario only. In the real editor
                            // instance document is available and automatically updates AST
                            // when whitespace inserted, not no manual update is necessary.
                            ast.ReflectTextChange(line.Start, 0, indentString.Length, new TextProvider(textBuffer.CurrentSnapshot));
                        }
                    }
                }
            }
        }
Beispiel #26
0
 private static IKeywordScopeStatement GetFormatScope(ITextView textView, ITextBuffer textBuffer, AstRoot ast) {
     SnapshotPoint? caret = REditorDocument.MapCaretPositionFromView(textView);
     if (caret.HasValue) {
         try {
             int lineNumber = textBuffer.CurrentSnapshot.GetLineNumberFromPosition(caret.Value.Position);
             ITextSnapshotLine line = textBuffer.CurrentSnapshot.GetLineFromLineNumber(lineNumber);
             string lineText = line.GetText();
             if (lineText.TrimEnd().EndsWith("}", StringComparison.Ordinal)) {
                 IKeywordScopeStatement scopeStatement = ast.GetNodeOfTypeFromPosition<IKeywordScopeStatement>(caret.Value);
                 return scopeStatement;
             }
         } catch (Exception) { }
     }
     return null;
 }
 public static IFunctionDefinition FindFunctionDefinition(ITextBuffer textBuffer, AstRoot ast, int position, out Variable v) {
     v = null;
     var exp = ast.GetNodeOfTypeFromPosition<IExpressionStatement>(position);
     return exp?.GetVariableOrFunctionDefinition(out v);
 }
Beispiel #28
0
 public RSignatureHelpContext(ISignatureHelpSession session, ITextBuffer textBuffer, AstRoot ast, int position) {
     Session = session;
     TextBuffer = textBuffer;
     Position = position;
     AstRoot = ast;
 }
Beispiel #29
0
 public static ITextView MakeTextView(string content, out AstRoot ast) {
     return MakeTextView(content, 0, out ast);
 }
Beispiel #30
0
        public static int GetSmartIndent(ITextSnapshotLine line, AstRoot ast = null) {
            ITextBuffer textBuffer = line.Snapshot.TextBuffer;

            if (ast == null) {
                IREditorDocument document = REditorDocument.TryFromTextBuffer(textBuffer);
                if (document == null) {
                    return 0;
                }
                ast = document.EditorTree.AstRoot;
            }

            if (line.LineNumber > 0) {
                ITextSnapshotLine prevLine = line.Snapshot.GetLineFromLineNumber(line.LineNumber - 1);

                string prevLineText = prevLine.GetText();
                int nonWsPosition = prevLine.Start + (prevLineText.Length - prevLineText.TrimStart().Length) + 1;

                IAstNodeWithScope scopeStatement = ast.GetNodeOfTypeFromPosition<IAstNodeWithScope>(nonWsPosition);
                if (scopeStatement != null) {
                    if (scopeStatement.Scope == null) {
                        // No scope of any kind, use block indent
                        return GetBlockIndent(line) + REditorSettings.IndentSize;
                    }

                    if (scopeStatement.Scope is SimpleScope) {
                        // There is statement with a simple scope above. We need to check 
                        // if the line that is being formatted is actually part of this scope.
                        if (line.Start < scopeStatement.Scope.End) {
                            // Indent line one level deeper that the statement
                            return GetBlockIndent(line) + REditorSettings.IndentSize;
                        }
                        
                        // Line is not part of the scope, hence regular indent
                        return OuterIndentSizeFromNode(textBuffer, scopeStatement, REditorSettings.FormatOptions);
                    }

                    // Check if line is the last line in scope and if so, 
                    // it should be indented at the outer indent
                    if (scopeStatement.Scope.CloseCurlyBrace != null) {
                        int endOfScopeLine = textBuffer.CurrentSnapshot.GetLineNumberFromPosition(scopeStatement.Scope.CloseCurlyBrace.Start);
                        if (endOfScopeLine == line.LineNumber) {
                            return OuterIndentSizeFromNode(textBuffer, scopeStatement, REditorSettings.FormatOptions);
                        }
                    }

                    return InnerIndentSizeFromNode(textBuffer, scopeStatement, REditorSettings.FormatOptions);
                }
            }

            IAstNodeWithScope node = ast.GetNodeOfTypeFromPosition<IAstNodeWithScope>(line.Start);
            if (node != null && node.Scope != null && node.Scope.OpenCurlyBrace != null) {
                return InnerIndentSizeFromNode(textBuffer, node, REditorSettings.FormatOptions);
            }

            // See if we are in function arguments and indent at the function level
            var fc = ast.GetNodeOfTypeFromPosition<FunctionCall>(line.Start);
            if(fc != null && fc.Arguments != null && fc.OpenBrace != null && line.Start >= fc.OpenBrace.End) {
                return InnerIndentSizeFromNode(textBuffer, fc, REditorSettings.FormatOptions);
            }

            // If nothing is found, default to block indent
            return GetBlockIndent(line);
        }
Beispiel #31
0
 /// <summary>
 /// Locates deepest node of a particular type
 /// </summary>
 public static T GetNodeOfTypeFromPosition <T>(this AstRoot ast, int position, bool includeEnd = false) where T : class
 {
     return(GetSpecificNodeFromPosition <T>(ast, position, (IAstNode n) => { return n is T; }, includeEnd) as T);
 }
Beispiel #32
0
 public static bool IsPositionInsideString(this AstRoot ast, int position)
 {
     // We don't want to auto-format inside strings
     return(ast.NodeFromPosition(position) is TokenNode node && node.Token.TokenType == RTokenType.String);
 }