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); }
/// <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); } } } } }
/// <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); } }
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)); }
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); }
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); }
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(); } } }
/// <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); } }
/// <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); }
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); } }
private static bool IsProjectedBuffer(IEditorBuffer editorBuffer) { var document = editorBuffer.GetEditorDocument <IREditorDocument>(); return(document.IsRepl || document.PrimaryView?.EditorBuffer != editorBuffer); }