private void CloseFormattingScope() { Debug.Assert(_tokens.CurrentToken.TokenType == RTokenType.CloseCurlyBrace); _tb.SoftLineBreak(); _tb.CloseIndentLevel(); _tb.SoftIndent(); if (_formattingScopes.Count > 1) { if (_formattingScopes.Peek().CloseBracePosition == _tokens.Position) { FormattingScope scope = _formattingScopes.Pop(); scope.Close(); } } AppendToken(leadingSpace: false, trailingSpace: false); if (SuppressLineBreakCount == 0 && !_tokens.IsEndOfStream()) { // We insert line break after } unless next token is comma // (scope is in the argument list) or a closing brace // (last parameter in a function or indexer) or it is followed by 'else' // so 'else' does not get separated from 'if'. if (!KeepCurlyAndElseTogether()) { if (!IsClosingToken(_tokens.CurrentToken) && !IsInArguments()) { _tb.SoftLineBreak(); } } } }
private void CloseFormattingScope() { Debug.Assert(_tokens.CurrentToken.TokenType == RTokenType.CloseCurlyBrace); if (!SingleLineScope) { _tb.SoftLineBreak(); _tb.CloseIndentLevel(); _tb.SoftIndent(); } var leadingSpace = SingleLineScope && _tokens.PreviousToken.TokenType != RTokenType.CloseCurlyBrace; if (_formattingScopes.Count > 1) { if (_formattingScopes.Peek().CloseBracePosition == _tokens.Position) { FormattingScope scope = _formattingScopes.Pop(); scope.Dispose(); } } AppendToken(leadingSpace: leadingSpace, trailingSpace: false); bool singleLineScopeJustClosed = false; if (_tokens.CurrentToken.Start >= _singleLineScopeEnd) { _singleLineScopeEnd = -1; singleLineScopeJustClosed = true; } if (SuppressLineBreakCount == 0 && !_tokens.IsEndOfStream()) { // We insert line break after } unless // a) Next token is comma (scope is in the argument list) or // b) Next token is a closing brace (last parameter in a function or indexer) or // c) Next token is by 'else' (so 'else' does not get separated from 'if') or // d) We are in a single-line scope sequence like if() {{ }} if (!KeepCurlyAndElseTogether()) { if (singleLineScopeJustClosed && !IsClosingToken(_tokens.CurrentToken) && !IsInArguments()) { SoftLineBreak(); } } } }
/// <summary> /// Appends statements inside scope that follows control block /// such as if() { } or a single statement that follows /// scope-less as in 'if() stmt' conditional. /// </summary> private void AppendStatementsInScope(string keyword) { // May or may not have curly braces if (_tokens.CurrentToken.TokenType == RTokenType.OpenCurlyBrace) { // Regular { } scope so just handle it normally AppendScopeContent(stopAtLineBreak: false); if (keyword == "if" && _tokens.CurrentToken.IsKeywordText(_textProvider, "else") && !_tokens.IsLineBreakAfter(_textProvider, _tokens.Position - 1)) { // if (FALSE) { // x <- 1 // } else // i.e. keep 'else' at the same line except when user did add line break as in // if (...) { 1 } // else { 2 } if (!_options.BracesOnNewLine && _tokens.PreviousToken.TokenType == RTokenType.CloseCurlyBrace) { while (_tb.LastCharacter.IsLineBreak()) { // Undo line break _tb.Remove(_tb.Length - 1, 1); } _tb.AppendPreformattedText(" "); } AppendKeyword(); } return; } // No curly braces: single statement block bool foundSameLineElse = false; if (keyword == "if") { // Per R language spec: // <quote> // The 'else' clause is optional. The statement if(any(x <= 0)) x <- x[x <= 0] // is valid. When the if statement is not in a block the else, if present, must // appear on the same line as the end of statement after if. Otherwise the new line // at the end of statement completes the if and yields a syntactically // complete statement that is evaluated. // </quote> // // So we have to be very careful here. If 'if' is not scoped then we need // to check if 'else' is on the same line and then keep the line as is // i.e. format but not break into multiple lines. On the other hand, // if there is no 'else' then we can insert break after the 'if(...)' foundSameLineElse = HasSameLineElse(); if (foundSameLineElse) { _formattingScopes.SuppressLineBreakCount++; AppendScopeContent(stopAtLineBreak: true); _formattingScopes.SuppressLineBreakCount--; return; } } if (_formattingScopes.SuppressLineBreakCount > 0) { AppendScopeContent(stopAtLineBreak: true); return; } bool addLineBreak = true; // Special case: preserve like break between 'else' and 'if' // if user put it there 'else if' remains on one line // if user didn't then add line break between them. if (_braceHandler.IsInArguments()) { addLineBreak = false; } else if (!_tokens.IsLineBreakAfter(_textProvider, _tokens.Position - 1)) { if (keyword.EqualsOrdinal("else") && _tokens.CurrentToken.IsKeywordText(_textProvider, "if")) { addLineBreak = false; } else if ((keyword.EqualsOrdinal("if") || keyword.EqualsOrdinal("else") || keyword.EqualsOrdinal("repeat")) && _tokens.CurrentToken.TokenType != RTokenType.OpenCurlyBrace) { // Preserve single-line conditionals like 'if (true) x <- 1' addLineBreak = false; } } if (addLineBreak) { _tb.SoftLineBreak(); _tb.NewIndentLevel(); // This scope-less 'if' so we have to stop at the end // of the line as in // if (TRUE) // x <- 1 // else { // } AppendScopeContent(stopAtLineBreak: true, stopAtElse: true); // if (TRUE) // repeat { // } // else // _tb.CloseIndentLevel(); } else { _tb.AppendSpace(); } }