Exemple #1
0
        /// <summary>
        /// Determines if current caret position is in the same function
        /// argument list as before or is it a different one and signature
        /// help session should be dismissed and re-triggered. This is helpful
        /// when user types nested function calls such as 'a(b(c(...), d(...)))'
        /// </summary>
        public static bool IsSameSignatureContext(this IEditorView editorView, IEditorBuffer editorBuffer, IServiceContainer services)
        {
            var broker   = services.GetService <IViewSignatureBroker>();
            var sessions = broker.GetSessions(editorView);

            Debug.Assert(sessions.Count < 2);
            if (sessions.Count == 1)
            {
                sessions[0].Properties.TryGetProperty("functionInfo", out IFunctionInfo sessionFunctionInfo);
                if (sessionFunctionInfo != null)
                {
                    try {
                        var document = editorBuffer.GetEditorDocument <IREditorDocument>();
                        document.EditorTree.EnsureTreeReady();

                        var parametersInfo = document.EditorTree.AstRoot.GetSignatureInfoFromBuffer(editorBuffer.CurrentSnapshot, editorView.Caret.Position.Position);
                        return(parametersInfo != null && parametersInfo.FunctionName == sessionFunctionInfo.Name);
                    } catch (ArgumentException) { }
                }
            }
            return(false);
        }
 /// <summary>
 /// Incrementally applies whitespace change to the buffer
 /// having old and new tokens produced from the 'before formatting'
 /// and 'after formatting' versions of the same text.
 /// </summary>
 /// <param name="editorBuffer">Text buffer to apply changes to</param>
 /// <param name="oldTextProvider">Text provider of the text fragment before formatting</param>
 /// <param name="newTextProvider">Text provider of the formatted text</param>
 /// <param name="oldTokens">Tokens from the 'before' text fragment</param>
 /// <param name="newTokens">Tokens from the 'after' text fragment</param>
 /// <param name="formatRange">Range that is being formatted in the text buffer</param>
 /// <param name="transactionName">Name of the undo transaction to open</param>
 /// <param name="selectionTracker">
 /// Selection tracker object that will save,
 /// track and restore selection after changes have been applied.</param>
 /// <param name="additionalAction">
 /// Action to perform after changes are applies by undo unit is not yet closed.
 /// </param>
 public void ApplyChange(
     IEditorBuffer editorBuffer,
     ITextProvider oldTextProvider,
     ITextProvider newTextProvider,
     IReadOnlyList <ITextRange> oldTokens,
     IReadOnlyList <ITextRange> newTokens,
     ITextRange formatRange,
     string transactionName,
     ISelectionTracker selectionTracker,
     Action additionalAction = null)
 {
     Debug.Assert(oldTokens.Count == newTokens.Count);
     if (oldTokens.Count == newTokens.Count)
     {
         using (CreateSelectionUndo(selectionTracker, _services, transactionName)) {
             var textBuffer = editorBuffer.As <ITextBuffer>();
             using (var edit = textBuffer.CreateEdit()) {
                 var edits = CalculateChanges(oldTextProvider, newTextProvider, oldTokens, newTokens, formatRange);
                 foreach (var e in edits)
                 {
                     if (string.IsNullOrEmpty(e.NewText))
                     {
                         edit.Delete(e.Range.ToSpan());
                     }
                     else if (e.Range.Length > 0)
                     {
                         edit.Replace(e.Range.ToSpan(), e.NewText);
                     }
                     else
                     {
                         edit.Insert(e.Range.Start, e.NewText);
                     }
                 }
                 edit.Apply();
                 additionalAction?.Invoke();
             }
         }
     }
 }
Exemple #3
0
 public static int InnerIndentSizeFromNode(IEditorBuffer editorBuffer, IAstNode node, RFormatOptions options)
 {
     if (node != null)
     {
         // Scope indentation is based on the scope defining node i.e.
         // x <- function(a) {
         //      |
         // }
         // caret indent is based on the function definition and not
         // on the position of the opening {
         var scope = node as IScope;
         if (scope != null)
         {
             if (node.Parent is IAstNodeWithScope scopeDefiningNode && scopeDefiningNode.Scope == scope)
             {
                 node = scopeDefiningNode;
             }
         }
         var startLine = editorBuffer.CurrentSnapshot.GetLineFromPosition(node.Start);
         return(InnerIndentSizeFromLine(startLine, options));
     }
     return(0);
 }
Exemple #4
0
        private static Hover ToHover(IReadOnlyList <IRFunctionQuickInfo> e, IEditorBuffer buffer)
        {
            if (e == null || e.Count == 0)
            {
                return(new Hover());
            }
            var info    = e[0];
            var content = info.Content?.FirstOrDefault();

            if (!string.IsNullOrEmpty(content))
            {
                var snapshot = buffer.CurrentSnapshot;
                var start    = info.ApplicableToRange.GetStartPoint(snapshot);
                var end      = info.ApplicableToRange.GetEndPoint(snapshot);
                return(new Hover {
                    contents = new MarkupContent {
                        value = content
                    },
                    range = buffer.ToLineRange(start, end)
                });
            }
            return(new Hover());
        }
Exemple #5
0
        private bool CanFormatRange(IEditorView editorView, IEditorBuffer editorBuffer, ITextRange formatRange)
        {
            // Make sure we are not formatting damaging the projected range in R Markdown
            // which looks like ```{r. 'r' should not separate from {.
            var locator  = _services.GetService <IContentTypeServiceLocator>();
            var provider = locator.GetService <IContainedLanguageHostProvider>("R");
            var host     = provider?.GetContainedLanguageHost(editorView, editorBuffer);

            if (host != null)
            {
                var snapshot  = editorBuffer.CurrentSnapshot;
                var startLine = snapshot.GetLineNumberFromPosition(formatRange.Start);
                var endLine   = snapshot.GetLineNumberFromPosition(formatRange.End);
                for (var i = startLine; i <= endLine; i++)
                {
                    if (!host.CanFormatLine(editorView, editorBuffer, i))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
        /// <summary>
        /// Incrementally applies whitespace change to the buffer
        /// having old and new tokens produced from the 'before formatting'
        /// and 'after formatting' versions of the same text.
        /// </summary>
        /// <param name="editorBuffer">Text buffer to apply changes to</param>
        /// <param name="oldTextProvider">Text provider of the text fragment before formatting</param>
        /// <param name="newTextProvider">Text provider of the formatted text</param>
        /// <param name="oldTokens">Tokens from the 'before' text fragment</param>
        /// <param name="newTokens">Tokens from the 'after' text fragment</param>
        /// <param name="formatRange">Range that is being formatted in the text buffer</param>
        /// <param name="transactionName">Not used in VS Code</param>
        /// <param name="selectionTracker">Not used in VS Code</param>
        /// <param name="additionalAction">
        /// Action to perform after changes are applies by undo unit is not yet closed.
        /// </param>
        public void ApplyChange(
            IEditorBuffer editorBuffer,
            ITextProvider oldTextProvider,
            ITextProvider newTextProvider,
            IReadOnlyList <ITextRange> oldTokens,
            IReadOnlyList <ITextRange> newTokens,
            ITextRange formatRange,
            string transactionName,
            ISelectionTracker selectionTracker,
            Action additionalAction = null)
        {
            Debug.Assert(oldTokens.Count == newTokens.Count);
            if (oldTokens.Count != newTokens.Count)
            {
                return;
            }

            var edits = CalculateChanges(oldTextProvider, newTextProvider, oldTokens, newTokens, formatRange);

            foreach (var e in edits)
            {
                if (string.IsNullOrEmpty(e.NewText))
                {
                    editorBuffer.Delete(e.Range);
                }
                else if (e.Range.Length > 0)
                {
                    editorBuffer.Replace(e.Range, e.NewText);
                }
                else
                {
                    editorBuffer.Insert(e.Range.Start, e.NewText);
                }
            }

            additionalAction?.Invoke();
        }
        private bool FormatRangeExact(IEditorView editorView, IEditorBuffer editorBuffer, ITextRange formatRange)
        {
            var snapshot        = editorBuffer.CurrentSnapshot;
            var spanText        = snapshot.GetText(formatRange);
            var trimmedSpanText = spanText.Trim();

            var formatter     = new RFormatter(_settings.FormatOptions);
            var formattedText = formatter.Format(trimmedSpanText);

            formattedText = formattedText.Trim(); // There may be inserted line breaks after {
                                                  // Extract existing indent before applying changes. Existing indent
                                                  // may be used by the smart indenter for function argument lists.
            var startLine = snapshot.GetLineFromPosition(formatRange.Start);
            var originalIndentSizeInSpaces = IndentBuilder.TextIndentInSpaces(startLine.GetText(), _settings.IndentSize);

            var selectionTracker = GetSelectionTracker(editorView, editorBuffer, formatRange);
            var tokenizer        = new RTokenizer();
            var oldTokens        = tokenizer.Tokenize(spanText);
            var newTokens        = tokenizer.Tokenize(formattedText);

            var wsChangeHandler = _services.GetService <IIncrementalWhitespaceChangeHandler>();

            wsChangeHandler.ApplyChange(
                editorBuffer,
                new TextStream(spanText), new TextStream(formattedText),
                oldTokens, newTokens,
                formatRange,
                Microsoft.R.Editor.Resources.AutoFormat, selectionTracker,
                () => {
                var ast = UpdateAst(editorBuffer);
                // Apply indentation
                IndentLines(editorBuffer, new TextRange(formatRange.Start, formattedText.Length), ast, originalIndentSizeInSpaces);
            });

            return(true);
        }
Exemple #8
0
 public static ITextSnapshot TextSnapshot(this IEditorBuffer buffer) => buffer.CurrentSnapshot.As <ITextSnapshot>();
Exemple #9
0
 public EditorBufferSnapshot(IEditorBuffer editorBuffer, string content, int version)
 {
     EditorBuffer = editorBuffer;
     _content     = content;
     Version      = version;
 }
Exemple #10
0
 public static Range ToLineRange(this ITextRange textRange, IEditorBuffer editorBuffer)
 => new Range
 {
     Start = editorBuffer.CurrentSnapshot.ToLinePosition(textRange.Start),
     End   = editorBuffer.CurrentSnapshot.ToLinePosition(textRange.End)
 };
Exemple #11
0
 public static int ToStreamPosition(this IEditorBuffer editorBuffer, Position position)
 => editorBuffer.CurrentSnapshot.ToStreamPosition(position.Line, position.Character);
Exemple #12
0
 /// <summary>
 /// Adds service to this instance of the text buffer
 /// </summary>
 public static void AddService <T>(this IEditorBuffer editorBuffer, T service) where T : class => editorBuffer.Services.AddService <T>(service);
 /// <summary>
 /// Removes service from this instance of the text buffer
 /// </summary>
 public static void RemoveService(this IEditorBuffer editorBuffer, object service)
 => editorBuffer.Services.RemoveService(service);
Exemple #14
0
 public RIntellisenseContext(IEditorIntellisenseSession session, IEditorBuffer editorBuffer, AstRoot ast, int position, bool autoShown = true) :
     base(session, editorBuffer, position)
 {
     AstRoot             = ast;
     AutoShownCompletion = autoShown;
 }
Exemple #15
0
        public void HandleTyping(char typedChar, int position, IEditorBuffer editorBuffer = null, IIncrementalWhitespaceChangeHandler changeHandler = null)
        {
            if (!Settings.AutoFormat || (!Settings.FormatScope && typedChar == '}'))
            {
                return;
            }

            EditorBuffer = editorBuffer ?? EditorBuffer;
            var document = EditorBuffer.GetEditorDocument <IREditorDocument>();
            // AST may or may not be ready. Upto the caller to decide if it is worth waiting.
            var ast = document.EditorTree.AstRoot;

            // Make sure we are not formatting damaging the projected range in R Markdown
            // which looks like ```{r. 'r' should not separate from {.
            if (!CanFormatContainedLanguageLine(position, typedChar))
            {
                return;
            }

            // We don't want to auto-format inside strings
            if (ast.IsPositionInsideString(position))
            {
                return;
            }

            var fo = new FormatOperations(Services, EditorView, EditorBuffer, _changeHandler);

            if (typedChar.IsLineBreak())
            {
                // Special case for hitting caret after } and before 'else'. We do want to format
                // the construct as '} else {' but if user types Enter after } and we auto-format
                // it will look as if the editor just eats the Enter. Instead, we will not be
                // autoformatting in this specific case. User can always format either the document
                // or select the block and reformat it.
                if (!IsBetweenCurlyAndElse(position))
                {
                    var scopeStatement = GetFormatScope(position, ast);
                    // Do not format large scope blocks for performance reasons
                    if (scopeStatement != null && scopeStatement.Length < 200)
                    {
                        fo.FormatNode(scopeStatement);
                    }
                    else if (CanFormatLine(position, -1))
                    {
                        fo.FormatViewLine(-1);
                    }
                }
            }
            else if (typedChar == ';')
            {
                // Verify we are at the end of the string and not in a middle
                // of another string or inside a statement.
                var line           = EditorBuffer.CurrentSnapshot.GetLineFromPosition(position);
                var positionInLine = position - line.Start;
                var lineText       = line.GetText();
                if (positionInLine >= lineText.TrimEnd().Length)
                {
                    fo.FormatViewLine(0);
                }
            }
            else if (typedChar == '}')
            {
                fo.FormatCurrentStatement(limitAtCaret: true, caretOffset: -1);
            }
        }
Exemple #16
0
 public IEnumerable <IEditorView> GetAllViews(IEditorBuffer editorBuffer)
 => TextViewConnectionListener.GetViewsForBuffer(editorBuffer.As <ITextBuffer>()).Select(v => v.ToEditorView()).Where(v => v != null);
Exemple #17
0
        private static bool IsProjectedBuffer(IEditorBuffer editorBuffer)
        {
            var document = editorBuffer.GetEditorDocument <IREditorDocument>();

            return(document.IsRepl || document.PrimaryView?.EditorBuffer != editorBuffer);
        }
Exemple #18
0
 public IEditorView GetPrimaryView(IEditorBuffer editorBuffer)
 => GetAllViews(editorBuffer).FirstOrDefault();
Exemple #19
0
 public EditorTreeMock(IEditorBuffer editorBuffer, AstRoot ast)
 {
     EditorBuffer = editorBuffer;
     AstRoot      = ast;
 }
 /// <summary>
 /// Adds service to this instance of the text buffer
 /// </summary>
 public static void AddService(this IEditorBuffer editorBuffer, object service)
 => editorBuffer.Services.AddService(service);
Exemple #21
0
 public static SnapshotPoint?GetCaretPosition(this ITextView textView, IEditorBuffer editorBuffer = null)
 => textView.GetCaretPosition(editorBuffer?.As <ITextBuffer>());
Exemple #22
0
 public ISnapshotPoint GetCaretPosition(IEditorBuffer buffer = null)
 => new SnapshotPoint(EditorBuffer.CurrentSnapshot, Caret.Position.Position);
Exemple #23
0
        /// <summary>
        /// Attempts to insert Roxygen documentation block based
        /// on the user function signature.
        /// </summary>
        public static bool TryInsertBlock(IEditorBuffer editorBuffer, AstRoot ast, int position)
        {
            // First determine if position is right before the function declaration
            var linePosition = DeterminePosition(editorBuffer, position);

            if (linePosition < 0)
            {
                return(false);
            }


            if (!DetermineFunction(ast, linePosition, out IFunctionDefinition fd, out IVariable v, out FunctionCall fc))
            {
                return(false);
            }

            int definitionStart;

            if (fd != null && v != null)
            {
                definitionStart = Math.Min(v.Start, fd.Start);
            }
            else if (fc != null)
            {
                definitionStart = fc.Start;
            }
            else
            {
                return(false);
            }

            var insertionSpan = GetRoxygenBlockPosition(editorBuffer.CurrentSnapshot, definitionStart);

            if (insertionSpan == null)
            {
                return(false);
            }

            var lineBreak = editorBuffer.CurrentSnapshot.GetLineFromPosition(position).LineBreak;

            if (string.IsNullOrEmpty(lineBreak))
            {
                lineBreak = "\n";
            }

            var block = fd != null
                ? GenerateRoxygenBlock(v.Name, fd, lineBreak)
                : GenerateRoxygenBlock(fc, lineBreak);

            if (block.Length == 0)
            {
                return(false);
            }

            if (insertionSpan.Length == 0)
            {
                editorBuffer.Insert(insertionSpan.Start, block + lineBreak);
            }
            else
            {
                editorBuffer.Replace(insertionSpan, block);
            }
            return(true);
        }
Exemple #24
0
 public static Position ToLinePosition(this IEditorBuffer editorBuffer, int position)
 => editorBuffer.CurrentSnapshot.ToLinePosition(position);
Exemple #25
0
 /// <summary>
 /// Uncomments selected lines or current line if range has zero length.
 /// Only removes single comment. ### -> ## -> # and so on. Matches C# behavior.
 /// </summary>
 public static void UncommentBlock(IEditorView editorView, IEditorBuffer editorBuffer, ITextRange range, IEditorSupport es)
 {
     DoActionOnLines(editorView, editorBuffer, range, es, UncommentLine, Resources.UncommentSelection);
 }
Exemple #26
0
 public static Range ToLineRange(this IEditorBuffer editorBuffer, int start, int end)
 => new Range
 {
     Start = editorBuffer.CurrentSnapshot.ToLinePosition(start),
     End   = editorBuffer.CurrentSnapshot.ToLinePosition(end)
 };
Exemple #27
0
 public IntellisenseContext(IEditorIntellisenseSession session, IEditorBuffer editorBuffer, int position)
 {
     Session      = session;
     EditorBuffer = editorBuffer;
     Position     = position;
 }
 /// <summary>
 /// Retrieves service from the service container attached to the buffer
 /// </summary>
 public static T GetService <T>(this IEditorBuffer editorBuffer) where T : class
 => editorBuffer.Services.GetService <T>();
Exemple #29
0
 public static int ToStreamPosition(this IEditorBuffer editorBuffer, int lineNumber, int charNumber)
 => editorBuffer.CurrentSnapshot.ToStreamPosition(lineNumber, charNumber);
Exemple #30
0
 public EditorView(IEditorBuffer editorBuffer, int caretPosition)
 {
     EditorBuffer = editorBuffer;
     Caret        = new ViewCaret(this, caretPosition);
 }