Exemple #1
0
        public static CodeBlock CalculateIndentation(string code, int offset)
        {
            if (offset >= code.Length)
            {
                offset = code.Length - 1;
            }

            CodeBlock block = null;

            var parserEndLocation = DocumentHelper.OffsetToLocation(code, offset);

            var lex = new Lexer(new StringReader(code));

            lex.NextToken();

            DToken t              = null;
            DToken la             = null;
            bool   isTheoreticEOF = false;

            while (!lex.IsEOF)
            {
                lex.NextToken();

                t  = lex.CurrentToken;
                la = lex.LookAhead;

                if (la.line == 4)
                {
                }

                isTheoreticEOF = la.Location >= parserEndLocation;
                // Ensure one token after the caret offset becomes parsed
                if (t != null && t.Location >= parserEndLocation)
                {
                    break;
                }

                // Handle case: or default: occurences
                if (t != null && (t.Kind == DTokens.Case || t.Kind == DTokens.Default))
                {
                    if (block != null && block.IsNonClampBlock)
                    {
                        block = block.Parent;
                    }

                    // On e.g. case myEnum.A:
                    if (la.Kind != DTokens.Colon)
                    {
                        // To prevent further issues, skip the expression
                        var psr = new DParser(lex);
                        psr.AssignExpression();
                        // FIXME: What if cursor is somewhere between case and ':'??
                    }

                    // lex.LookAhead should be ':' now
                    if (lex.LookAhead.EndLocation >= parserEndLocation)
                    {
                        break;
                    }
                    else
                    {
                        block = new CodeBlock
                        {
                            InitialToken  = DTokens.Case,
                            StartLocation = t.EndLocation,

                            Parent = block
                        }
                    };
                }

                // If in a single-statement scope, unindent by 1 if semicolon found

                /*
                 * Note: On multiple single-sub-statemented statements: for instance
                 * if(..)
                 *		if(...)
                 *			if(...)
                 *				foo();
                 *	// No indentation anymore!
                 */
                else if (block != null && (block.IsSingleLineIndentation) && la.Kind == DTokens.Semicolon)
                {
                    block = block.Parent;
                }

                // New block is opened by (,[,{
                else if (
                    !isTheoreticEOF &&
                    (la.Kind == DTokens.OpenParenthesis ||
                     la.Kind == DTokens.OpenSquareBracket ||
                     la.Kind == DTokens.OpenCurlyBrace))
                {
                    block = new CodeBlock
                    {
                        LastPreBlockIdentifier = t,
                        InitialToken           = la.Kind,
                        StartLocation          = la.Location,

                        Parent = block
                    };
                }

                // Open block is closed by ),],}
                else if (block != null && (
                             la.Kind == DTokens.CloseParenthesis ||
                             la.Kind == DTokens.CloseSquareBracket ||
                             la.Kind == DTokens.CloseCurlyBrace))
                {
                    // If EOF reached, only 'decrement' indentation if code line consists of the closing bracket only
                    // --> Return immediately if there's been another token on the same line
                    if (isTheoreticEOF && t.line == la.line)
                    {
                        return(block);
                    }

                    // Statements that contain only one sub-statement -> indent by 1
                    if (((block.InitialToken == DTokens.OpenParenthesis && la.Kind == DTokens.CloseParenthesis &&
                          IsPreStatementToken(block.LastPreBlockIdentifier.Kind)) ||
                         la.Kind == DTokens.Do)                      // 'Do'-Statements allow single statements inside

                        && lex.Peek().Kind != DTokens.OpenCurlyBrace /* Ensure that no block statement follows */)
                    {
                        block = new CodeBlock
                        {
                            LastPreBlockIdentifier  = t,
                            IsSingleLineIndentation = true,
                            StartLocation           = t.Location,

                            Parent = block.Parent
                        };
                    }

                    /*
                     * Do unindent if the watched code is NOT about to end OR if
                     * the next token is a '}' (which normally means the end of a class body/block statement etc.)
                     * AND if no line-break was entered (so unindent the finalizing '}' but not the block's statements)
                     */
                    else if (!isTheoreticEOF ||
                             (la.Kind == DTokens.CloseCurlyBrace &&
                              la.line == parserEndLocation.Line))
                    {
                        /*
                         * On "case:" or "default:" blocks (so mostly in switch blocks),
                         * skip back to the 'switch' scope.
                         *
                         * switch(..)
                         * {
                         *		default:
                         *		case ..:
                         *			// There is indentation now!
                         *			// (On following lines, case blocks are still active)
                         * } // Decreased Indentation; case blocks discarded
                         */
                        if (la.Kind == DTokens.CloseCurlyBrace)
                        {
                            while (block != null && block.IsNonClampBlock)
                            {
                                block = block.Parent;
                            }
                        }

                        if (block != null)
                        {
                            block = block.Parent;
                        }
                    }
                }
            }

            return(block);
        }
Exemple #2
0
        public CodeBlock CalculateIndentation(TextReader code, int line)
        {
            block = null;

            Lexer   = new Lexer(code);
            maxLine = line;

            Lexer.NextToken();
            DToken lastToken = null;

            while (!Lexer.IsEOF)
            {
                if (t != null && la.Line > t.Line && t.Line < maxLine)
                {
                    RemoveNextLineUnindentBlocks();
                }

                lastToken = t;
                Lexer.NextToken();

                if (IsEOF)
                {
                    if (la.Line > maxLine || Lexer.IsEOF)
                    {
                        lastLineIndent = null;
                    }

                    if (t.Line > maxLine)
                    {
                        break;
                    }
                }

                /*
                 * if(..)
                 *		for(...)
                 *			while(...)
                 *				foo();
                 *	// No indentation anymore!
                 */
                if (t.Kind == DTokens.Comma || t.Kind == DTokens.Semicolon && maxLine > t.Line && la.Line > t.Line)
                {
                    if (block == null)
                    {
                        continue;
                    }

                    if (block.Reason == CodeBlock.IndentReason.UnfinishedStatement)
                    {
                        PopBlock();
                    }

                    while (
                        block != null &&
                        block.Reason == CodeBlock.IndentReason.SingleLineStatement &&
                        !IsSemicolonContainingStatement)
                    {
                        PopBlock();
                    }
                }

                // (,[,{
                else if (t.Kind == DTokens.OpenParenthesis ||
                         t.Kind == DTokens.OpenSquareBracket ||
                         t.Kind == DTokens.OpenCurlyBrace)
                {
                    var tBlock = block;

                    if (block != null && (
                            block.Reason == CodeBlock.IndentReason.SingleLineStatement ||
                            block.Reason == CodeBlock.IndentReason.UnfinishedStatement))
                    {
                        PopBlock();
                    }

                    PushBlock(tBlock).BlockStartToken = t.Kind;
                }

                // ),],}
                else if (t.Kind == DTokens.CloseParenthesis ||
                         t.Kind == DTokens.CloseSquareBracket ||
                         t.Kind == DTokens.CloseCurlyBrace)
                {
                    if (t.Kind == DTokens.CloseCurlyBrace)
                    {
                        while (block != null && !block.IsClampBlock)
                        {
                            PopBlock();
                        }

                        /*
                         * If the last token was on this line OR if it's eof but on the following line,
                         * decrement indent on next line only.
                         */
                        if (lastToken != null && lastToken.Line == t.Line && block != null)
                        {
                            block.PopOnNextLine = true;
                        }
                        else
                        {
                            PopBlock();
                        }
                    }
                    else
                    {
                        while (block != null && !block.IsClampBlock)
                        {
                            PopBlock();
                        }

                        if (lastLineIndent == null && (block == null || block.StartLocation.Line < t.Line))
                        {
                            lastLineIndent = block;
                        }

                        if (t.Kind == DTokens.CloseParenthesis &&
                            block != null &&
                            block.BlockStartToken == DTokens.OpenParenthesis &&
                            la.Kind != DTokens.OpenCurlyBrace)
                        {
                            block = block.previousBlock;

                            continue;
                        }
                        else
                        {
                            PopBlock();
                        }

                        if (t.Kind == DTokens.CloseParenthesis &&
                            block != null &&
                            block.BlockStartToken == DTokens.OpenParenthesis)
                        {
                            if (la.Kind == DTokens.OpenCurlyBrace && la.Line > t.Line)
                            {
                                PopBlock();
                            }
                            else if (block != null && block.LastPreBlockIdentifier != null && IsPreStatementToken(block.LastPreBlockIdentifier.Kind))
                            {
                                block = block.previousBlock;
                            }
                        }
                    }
                }

                else if ((DParser.IsAttributeSpecifier(t.Kind, la.Kind) && la.Kind == DTokens.Colon) || t.Kind == DTokens.Case || t.Kind == DTokens.Default)
                {
                    while (block != null && block.BlockStartToken != DTokens.OpenCurlyBrace)
                    {
                        PopBlock();
                    }

                    PushBlock().Reason = CodeBlock.IndentReason.StatementLabel;

                    HadCaseStatementBegin = true;
                }
                else if (t.Kind == DTokens.Colon)
                {
                    if (HadCaseStatementBegin)
                    {
                        while (block != null && block.Reason != CodeBlock.IndentReason.StatementLabel)
                        {
                            PopBlock();
                        }
                        HadCaseStatementBegin = false;
                    }
                }

                // Don't indent these in front of function bodies
                else if (t.Kind == DTokens.In || t.Kind == DTokens.Out || t.Kind == DTokens.Body)
                {
                    if (block != null && block.Reason == CodeBlock.IndentReason.UnfinishedStatement)
                    {
                        PopBlock();
                    }
                }


                else if (block == null ||
                         block.Reason != CodeBlock.IndentReason.UnfinishedStatement &&
                         block.Reason != CodeBlock.IndentReason.SingleLineStatement)
                {
                    PushBlock().Reason = CodeBlock.IndentReason.UnfinishedStatement;
                }
            }

            if (t != null && la.Line > t.Line)
            {
                RemoveNextLineUnindentBlocks();
            }

            return(lastLineIndent ?? block);
        }