Example #1
0
        /// <summary>
        /// Iterates over tokens in the current scope and constructs formatted text
        /// </summary>
        /// <param name="stopAtLineBreak">
        /// If true scope stops at the nearest line break. Used when formatting
        /// simple conditional statements like 'if() stmt1 else stmt1' that
        /// should not be broken into multiple lines.
        /// </param>
        private void AppendScopeContent(bool stopAtLineBreak, bool stopAtElse = false)
        {
            while (!_tokens.IsEndOfStream())
            {
                if (ShouldAppendTextBeforeToken())
                {
                    AppendTextBeforeToken();

                    // If scope is simple (no curly braces) then stopAtLineBreak is true.
                    // If there is a line break before start of the simple scope content
                    // as in 'if(true)\nx<-1' we need to add indent
                    if (stopAtLineBreak && _tb.IsAtNewLine)
                    {
                        _tb.AppendPreformattedText(IndentBuilder.GetIndentString(_options.IndentSize, _options.IndentType, _options.TabSize));
                    }
                }

                AppendNextToken();

                if (stopAtLineBreak && _tokens.IsLineBreakAfter(_textProvider, _tokens.Position))
                {
                    break;
                }
                if (_tokens.PreviousToken.TokenType == RTokenType.CloseCurlyBrace)
                {
                    break;
                }
                if (stopAtElse && _tokens.CurrentToken.IsKeywordText(_textProvider, "else"))
                {
                    break;
                }
            }
        }
Example #2
0
        /// <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"))
                {
                    // if (FALSE) {
                    //   x <- 1
                    // } else
                    // i.e. keep 'else' at the same line.
                    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)
                {
                    SuppressLineBreakCount++;
                    AppendScopeContent(stopAtLineBreak: true);
                    SuppressLineBreakCount--;

                    return;
                }
            }

            if (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 (IsInArguments() ||
                (keyword == "else" && _tokens.CurrentToken.IsKeywordText(_textProvider, "if") &&
                 !_tokens.IsLineBreakAfter(_textProvider, _tokens.Position - 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();
            }
        }
Example #3
0
        private void CloseFormattingScope()
        {
            Debug.Assert(_tokens.CurrentToken.TokenType == RTokenType.CloseCurlyBrace);

            // if it is not single line scope like { } add linke break before }
            if (!SingleLineScope)
            {
                _tb.SoftLineBreak();
            }

            var leadingSpace = SingleLineScope && _tokens.PreviousToken.TokenType != RTokenType.CloseCurlyBrace;

            // Close formatting scope and remember if it was based on the user-supplied indent.
            _formattingScopes.TryCloseScope(_tokens.Position);

            // Closing curly indentation is defined by the line that either holds the opening curly brace
            // or the line that holds keyword that defines the expression that the curly belongs to.
            // Examples:
            //
            //      x <-
            //          function(a) {
            //          }
            //
            //      x <- function(a) {
            //      }
            //
            if (!SingleLineScope)
            {
                int lineIndentSize = _braceHandler.GetCloseCurlyBraceIndentSize(_tokens.CurrentToken, _tb, _options);
                if (lineIndentSize > 0)
                {
                    var indentString = IndentBuilder.GetIndentString(lineIndentSize, _options.IndentType, _options.TabSize);
                    _tb.AppendPreformattedText(indentString);
                    leadingSpace = false;
                }
                else
                {
                    _tb.SoftIndent();
                }
            }

            AppendToken(leadingSpace: leadingSpace, trailingSpace: false);

            bool singleLineScopeJustClosed = false;

            if (_tokens.CurrentToken.Start >= _singleLineScopeEnd)
            {
                _singleLineScopeEnd       = -1;
                singleLineScopeJustClosed = true;
            }

            if (_formattingScopes.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) &&
                        !_braceHandler.IsInArguments())
                    {
                        SoftLineBreak();
                    }
                }
            }
        }