/// <summary>
        /// Appends indentation to each line so formatted text appears properly
        /// indented inside the host document (script block in HTML page).
        /// </summary>
        private void IndentLines(IEditorBuffer textBuffer, ITextRange range, AstRoot ast, int originalIndentSizeInSpaces)
        {
            var snapshot  = textBuffer.CurrentSnapshot;
            var firstLine = snapshot.GetLineFromPosition(range.Start);
            var lastLine  = snapshot.GetLineFromPosition(range.End);
            var document  = textBuffer.GetEditorDocument <IREditorDocument>();

            for (var i = firstLine.LineNumber; i <= lastLine.LineNumber; i++)
            {
                // Snapshot is updated after each insertion so do not cache
                var line   = textBuffer.CurrentSnapshot.GetLineFromLineNumber(i);
                var indent = SmartIndenter.GetSmartIndent(line, _settings, 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(), _settings.TabSize);
                    indent = Math.Max(0, indent - currentIndentSize);
                    if (indent > 0)
                    {
                        var indentString = IndentBuilder.GetIndentString(indent, _settings.IndentType, _settings.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, textBuffer.CurrentSnapshot);
                        }
                    }
                }
            }
        }
Exemple #2
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         snapshot   = editorBuffer.CurrentSnapshot;
            IEditorLine 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);
            }

            var fd = ast.FindFunctionDefinition(line.Start + offset, out v);

            if (fd != null && v != null && !string.IsNullOrEmpty(v.Name))
            {
                int definitionStart = Math.Min(v.Start, fd.Start);
                var insertionSpan   = GetRoxygenBlockPosition(snapshot, definitionStart);
                if (insertionSpan != null)
                {
                    string lineBreak = snapshot.GetLineFromPosition(position).LineBreak;
                    if (string.IsNullOrEmpty(lineBreak))
                    {
                        lineBreak = "\n";
                    }
                    string block = GenerateRoxygenBlock(v.Name, fd, lineBreak);
                    if (block.Length > 0)
                    {
                        if (insertionSpan.Length == 0)
                        {
                            editorBuffer.Insert(insertionSpan.Start, block + lineBreak);
                        }
                        else
                        {
                            editorBuffer.Replace(insertionSpan, block);
                        }
                        return(true);
                    }
                }
            }
            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">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();
        }
Exemple #4
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);
        }