public static void HandleAutoformat(ITextView textView, IEditorShell editorShell, char typedChar) { if (!REditorSettings.AutoFormat) { return; } if (!REditorSettings.FormatScope && typedChar == '}') { return; } SnapshotPoint?rPoint = GetCaretPointInBuffer(textView); if (!rPoint.HasValue) { return; } var document = REditorDocument.FromTextBuffer(textView.TextBuffer); 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 {. var host = ContainedLanguageHost.GetHost(textView, document.TextBuffer, editorShell); if (host != null && !host.CanFormatLine(textView, document.TextBuffer, document.TextBuffer.CurrentSnapshot.GetLineNumberFromPosition(rPoint.Value))) { return; } // We don't want to auto-format inside strings if (ast.IsPositionInsideString(rPoint.Value.Position)) { return; } ITextBuffer subjectBuffer = rPoint.Value.Snapshot.TextBuffer; 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(subjectBuffer, rPoint.Value.Position)) { var scopeStatement = GetFormatScope(textView, subjectBuffer, ast); // Do not format large scope blocks for performance reasons if (scopeStatement != null && scopeStatement.Length < 200) { FormatOperations.FormatNode(textView, subjectBuffer, editorShell, scopeStatement); } else if (CanFormatLine(textView, subjectBuffer, -1)) { FormatOperations.FormatViewLine(textView, subjectBuffer, -1, editorShell); } } } else if (typedChar == ';') { // Verify we are at the end of the string and not in a middle // of another string or inside a statement. ITextSnapshotLine line = subjectBuffer.CurrentSnapshot.GetLineFromPosition(rPoint.Value.Position); int positionInLine = rPoint.Value.Position - line.Start; string lineText = line.GetText(); if (positionInLine >= lineText.TrimEnd().Length) { FormatOperations.FormatViewLine(textView, subjectBuffer, 0, editorShell); } } else if (typedChar == '}') { FormatOperations.FormatCurrentStatement(textView, subjectBuffer, editorShell, limitAtCaret: true, caretOffset: -1); } }
public static void HandleAutoformat(ITextView textView, char typedChar) { if (!REditorSettings.AutoFormat || IgnoreOnce) { IgnoreOnce = false; return; } SnapshotPoint?rPoint = GetCaretPointInBuffer(textView); if (!rPoint.HasValue) { return; } var document = REditorDocument.FromTextBuffer(textView.TextBuffer); var et = document.EditorTree; var ast = et.GetCurrentRootOrPreviousIfNotReady(); // We don't want to auto-format inside strings if (ast.IsPositionInsideString(rPoint.Value.Position)) { return; } ITextBuffer subjectBuffer = rPoint.Value.Snapshot.TextBuffer; 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(subjectBuffer, rPoint.Value.Position)) { var scopeStatement = GetFormatScope(textView, subjectBuffer, ast, -1); // Do not format large scope blocks for performance reasons if (scopeStatement != null && scopeStatement.Length < 200) { FormatOperations.FormatNode(textView, subjectBuffer, scopeStatement); } else { FormatOperations.FormatLine(textView, subjectBuffer, -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. ITextSnapshotLine line = subjectBuffer.CurrentSnapshot.GetLineFromPosition(rPoint.Value.Position); int positionInLine = rPoint.Value.Position - line.Start; string lineText = line.GetText(); if (positionInLine >= lineText.TrimEnd().Length) { FormatOperations.FormatLine(textView, subjectBuffer, 0); } } else if (typedChar == '}') { FormatOperations.FormatCurrentStatement(textView, subjectBuffer); } }
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); } }
public static void HandleAutoformat(ITextView textView, char typedChar) { if (!REditorSettings.AutoFormat || IgnoreOnce) { IgnoreOnce = false; return; } IEditorTree tree; SnapshotPoint?rPoint = GetCaretPointInBuffer(textView, out tree); if (!rPoint.HasValue) { return; } // We don't want to auto-format inside strings if (tree.AstRoot.IsPositionInsideString(rPoint.Value.Position)) { return; } ITextBuffer subjectBuffer = rPoint.Value.Snapshot.TextBuffer; 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(subjectBuffer, rPoint.Value.Position)) { bool formatScope = ShouldFormatScope(textView, subjectBuffer, -1); if (formatScope) { FormatOperations.FormatCurrentNode <IStatement>(textView, subjectBuffer); } else { FormatOperations.FormatLine(textView, subjectBuffer, tree.AstRoot, -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. ITextSnapshotLine line = subjectBuffer.CurrentSnapshot.GetLineFromPosition(rPoint.Value.Position); int positionInLine = rPoint.Value.Position - line.Start; string lineText = line.GetText(); if (positionInLine >= lineText.TrimEnd().Length) { FormatOperations.FormatLine(textView, subjectBuffer, tree.AstRoot, 0); } } else if (typedChar == '}') { FormatOperations.FormatNode <IStatement>(textView, subjectBuffer, Math.Max(rPoint.Value - 1, 0)); } }