예제 #1
0
        public static bool IsSyntaxCheckEnabled(IEditorBuffer editorBuffer, IREditorSettings settings, out bool lintEnabled)
        {
            var document = editorBuffer.GetEditorDocument <IREditorDocument>();

            lintEnabled = !document.IsRepl && settings.LintOptions.Enabled;
            return(document.IsRepl ? settings.SyntaxCheckInRepl : settings.SyntaxCheckEnabled);
        }
예제 #2
0
        /// <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);
                        }
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Formats statement that the caret is at
        /// </summary>
        public void FormatCurrentStatement(bool limitAtCaret = false, int caretOffset = 0)
        {
            var caretPoint = _editorView.GetCaretPosition(_editorBuffer);

            if (caretPoint == null)
            {
                return;
            }
            var document = _editorBuffer.GetEditorDocument <IREditorDocument>();

            if (document != null)
            {
                var ast  = document.EditorTree.AstRoot;
                var node = ast.GetNodeOfTypeFromPosition <IStatement>(Math.Max(0, caretPoint.Position + caretOffset)) as IAstNode;
                FormatNode(node, limit: caretPoint.Position);
            }
        }
예제 #4
0
        private AstRoot UpdateAst(IEditorBuffer editorBuffer)
        {
            var document = editorBuffer.GetEditorDocument <IREditorDocument>();

            if (document != null)
            {
                document.EditorTree.EnsureTreeReady();
                return(document.EditorTree.AstRoot);
            }
            return(RParser.Parse(editorBuffer.CurrentSnapshot));
        }
예제 #5
0
        public static bool IsSyntaxCheckEnabled(IEditorBuffer editorBuffer, IREditorSettings settings)
        {
            var document = editorBuffer.GetEditorDocument <IREditorDocument>();

            if (document != null)
            {
                var view = document.PrimaryView;
                return(view != null && view.IsRepl() ? settings.SyntaxCheckInRepl : settings.SyntaxCheckEnabled);
            }
            return(false);
        }
예제 #6
0
        public static bool IsSyntaxCheckEnabled(IEditorBuffer editorBuffer, IREditorSettings settings, out bool lintEnabled, out bool projectedBuffer)
        {
            var document = editorBuffer.GetEditorDocument <IREditorDocument>();

            if (document != null)
            {
                var view = document.PrimaryView;
                lintEnabled     = view != null && !view.IsRepl();
                projectedBuffer = view != null && view.EditorBuffer != editorBuffer;
                return(view != null && view.IsRepl() ? settings.SyntaxCheckInRepl : settings.SyntaxCheckEnabled);
            }
            projectedBuffer = false;
            lintEnabled     = false;
            return(false);
        }
예제 #7
0
        public static void FormatCurrentScope(IEditorView editorView, IEditorBuffer textBuffer, IServiceContainer services, bool indentCaret)
        {
            // Figure out caret position in the document text buffer
            var document = textBuffer.GetEditorDocument <IREditorDocument>();

            if (document == null)
            {
                return;
            }
            var caretPoint = editorView.GetCaretPosition(textBuffer);

            if (caretPoint == null)
            {
                return;
            }

            // Make sure AST is up to date
            document.EditorTree.EnsureTreeReady();
            var ast = document.EditorTree.AstRoot;
            // Find scope to format
            var scope = ast.GetNodeOfTypeFromPosition <IScope>(caretPoint.Position);

            var es = services.GetService <IEditorSupport>();

            using (var undoAction = es.CreateUndoAction(editorView)) {
                var settings = services.GetService <IREditorSettings>();
                undoAction.Open(Resources.AutoFormat);
                // Now format the scope
                var formatter = new RangeFormatter(services);
                var changed   = formatter.FormatRange(editorView, textBuffer, scope);
                if (indentCaret)
                {
                    // Formatting may change AST and the caret position so we need to reacquire both
                    caretPoint = editorView.GetCaretPosition(textBuffer);
                    if (caretPoint != null)
                    {
                        document.EditorTree.EnsureTreeReady();
                        ast   = document.EditorTree.AstRoot;
                        scope = ast.GetNodeOfTypeFromPosition <IScope>(caretPoint.Position);
                        IndentCaretInNewScope(editorView, scope, caretPoint, settings.FormatOptions);
                    }
                }
                if (changed)
                {
                    undoAction.Commit();
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Formats statement that the caret is at
        /// </summary>
        public static void FormatCurrentStatement(IEditorView editorView, IEditorBuffer textBuffer, IServiceContainer services, bool limitAtCaret = false, int caretOffset = 0)
        {
            var caretPoint = editorView.GetCaretPosition(textBuffer);

            if (caretPoint == null)
            {
                return;
            }
            var document = textBuffer.GetEditorDocument <IREditorDocument>();

            if (document != null)
            {
                var ast  = document.EditorTree.AstRoot;
                var node = ast.GetNodeOfTypeFromPosition <IStatement>(Math.Max(0, caretPoint.Position + caretOffset)) as IAstNode;
                FormatNode(editorView, textBuffer, services, node, limit: caretPoint.Position);
            }
        }
예제 #9
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);
        }
예제 #10
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);
            }
        }
예제 #11
0
        private static bool IsProjectedBuffer(IEditorBuffer editorBuffer)
        {
            var document = editorBuffer.GetEditorDocument <IREditorDocument>();

            return(document.IsRepl || document.PrimaryView?.EditorBuffer != editorBuffer);
        }