alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor.ext.java;

import org.netbeans.editor.TokenID;
import org.netbeans.editor.TokenItem;
import org.netbeans.editor.TokenContextPath;
import org.netbeans.editor.TokenItem;
import org.netbeans.editor.ext.FormatTokenPosition;
import org.netbeans.editor.ext.ExtFormatSupport;
import org.netbeans.editor.ext.FormatWriter;
import org.netbeans.editor.ext.java.JavaTokenContext;
import org.netbeans.editor.ext.java.JavaSyntax;

/**
* Java indentation services are located here
*
* @author Miloslav Metelka
* @version 1.00
*/

public class JavaFormatSupport extends ExtFormatSupport {

    private TokenContextPath tokenContextPath;

    public JavaFormatSupport(FormatWriter formatWriter) {
        this(formatWriter, JavaTokenContext.contextPath);
    }

    public JavaFormatSupport(FormatWriter formatWriter, TokenContextPath tokenContextPath) {
        super(formatWriter);
        this.tokenContextPath = tokenContextPath;
    }

    public TokenContextPath getTokenContextPath() {
        return tokenContextPath;
    }

    public boolean isComment(TokenItem token, int offset) {
        TokenID tokenID = token.getTokenID();
        return (token.getTokenContextPath() == tokenContextPath
                && (tokenID == JavaTokenContext.LINE_COMMENT
                    || tokenID == JavaTokenContext.BLOCK_COMMENT));
    }

    public boolean isMultiLineComment(TokenItem token) {
        return (token.getTokenID() == JavaTokenContext.BLOCK_COMMENT);
    }

    public boolean isMultiLineComment(FormatTokenPosition pos) {
        TokenItem token = pos.getToken();
        return (token == null) ? false : isMultiLineComment(token);
    }

    /** Check whether the given token is multi-line comment
     * that starts with slash and two stars.
     */
    public boolean isJavaDocComment(TokenItem token) {
        return isMultiLineComment(token)
            && token.getImage().startsWith("/**");
    }

    public TokenID getWhitespaceTokenID() {
        return JavaTokenContext.WHITESPACE;
    }

    public TokenContextPath getWhitespaceTokenContextPath() {
        return tokenContextPath;
    }

    public boolean canModifyWhitespace(TokenItem inToken) {
        if (inToken.getTokenContextPath() == JavaTokenContext.contextPath) {
            switch (inToken.getTokenID().getNumericID()) {
                case JavaTokenContext.BLOCK_COMMENT_ID:
                case JavaTokenContext.WHITESPACE_ID:
                    return true;
            }
        }

        return false;
    }


    /** Find the starting token of the statement before
     * the given position and also return all the command
     * delimiters. It searches in the backward direction
     * for all the delimiters and statement starts and
     * return all the tokens that are either command starts
     * or delimiters. As the first step it uses
     * getPreviousToken() so it ignores the initial token.
     * @param token token before which the statement-start
     *  and delimiter is being searched.
     * @return token that is start of the given statement
     *  or command delimiter.
     *  If the start of the statement is not found, null is retrurned.
     */
    public TokenItem findStatement(TokenItem token) {
        TokenItem lit = null; // last important token
        TokenItem t = getPreviousToken(token);

        while (t != null) {
            if (t.getTokenContextPath() == tokenContextPath) {

                switch (t.getTokenID().getNumericID()) {
                    case JavaTokenContext.SEMICOLON_ID:
                        if (!isForLoopSemicolon(t)) {
                            return (lit != null) ? lit : t;
                        }
                        break;

                    case JavaTokenContext.LBRACE_ID:
                    case JavaTokenContext.RBRACE_ID:
                    case JavaTokenContext.ELSE_ID:
                        return (lit != null) ? lit : t;

                    case JavaTokenContext.COLON_ID:
                        TokenItem tt = findAnyToken(t, null, new TokenID[] {JavaTokenContext.CASE, JavaTokenContext.DEFAULT, JavaTokenContext.FOR, JavaTokenContext.QUESTION, JavaTokenContext.ASSERT}, t.getTokenContextPath(), true);
                        if (tt != null) {
                            switch (tt.getTokenID().getNumericID()) {
                                case JavaTokenContext.CASE_ID:
                                case JavaTokenContext.DEFAULT_ID:
                                case JavaTokenContext.FOR_ID:
                                    return (lit != null) ? lit : t;
                            }
                        }
                        break;

                    case JavaTokenContext.DO_ID:
                    case JavaTokenContext.SWITCH_ID:
                    case JavaTokenContext.CASE_ID:
                    case JavaTokenContext.DEFAULT_ID:
                        return t;

                    case JavaTokenContext.FOR_ID:
                    case JavaTokenContext.IF_ID:
                    case JavaTokenContext.WHILE_ID:
                        /* Try to find the statement after ( ... )
                         * If it exists, then the first important
                         * token after it is the stmt start. Otherwise
                         * it's this token.
                         */
                        if (lit != null && lit.getTokenID() == JavaTokenContext.LPAREN) {
                            // Find matching right paren in fwd dir
                            TokenItem mt = findMatchingToken(lit, token,
                                    JavaTokenContext.RPAREN, false);
                            if (mt != null && mt.getNext() != null) {
                                mt = findImportantToken(mt.getNext(), token, false);
                                if (mt != null) {
                                    return mt;
                                }
                            }
                        }

                        // No further stmt found, return this one
                        return t;

                }

                // Remember last important token
                if (isImportant(t, 0)) {
                    lit = t;
                }

            }

            t = t.getPrevious();
        }

        return lit;
    }


    /** Find the 'if' when the 'else' is provided.
     * @param elseToken the token with the 'else' command
     *  for which the 'if' is being searched.
     * @return corresponding 'if' token or null if there's
     *  no corresponding 'if' statement.
     */
    public TokenItem findIf(TokenItem elseToken) {
        if (elseToken == null || !tokenEquals(elseToken,
                    JavaTokenContext.ELSE, tokenContextPath)
        ) {
            throw new IllegalArgumentException("Only accept 'else'."); // NOI18N
        }

        int braceDepth = 0; // depth of the braces
        int elseDepth = 0; // depth of multiple else stmts
        while (true) {
            elseToken = findStatement(elseToken);
            if (elseToken == null) {
                return null;
            }
            
            switch (elseToken.getTokenID().getNumericID()) {
                case JavaTokenContext.LBRACE_ID:
                    if (--braceDepth < 0) {
                        return null; // no corresponding right brace
                    }
                    break;

                case JavaTokenContext.RBRACE_ID:
                    braceDepth++;
                    break;

                case JavaTokenContext.ELSE_ID:
                    if (braceDepth == 0) {
                        elseDepth++;
                    }
                    break;

                case JavaTokenContext.SEMICOLON_ID:
                case JavaTokenContext.COLON_ID:
                case JavaTokenContext.DO_ID:
                case JavaTokenContext.CASE_ID:
                case JavaTokenContext.DEFAULT_ID:
                case JavaTokenContext.FOR_ID:
                case JavaTokenContext.WHILE_ID:
                    break;

                case JavaTokenContext.IF_ID:
                    if (braceDepth == 0) {
                        if (elseDepth-- == 0) {
                            return elseToken; // successful search
                        }
                    }
                    break;
            }
        }
    }


    /** Find the 'switch' when the 'case' is provided.
     * @param caseToken the token with the 'case' command
     *  for which the 'switch' is being searched.
     * @return corresponding 'switch' token or null if there's
     *  no corresponding 'switch' statement.
     */
    public TokenItem findSwitch(TokenItem caseToken) {
        if (caseToken == null || 
             (!tokenEquals(caseToken, JavaTokenContext.CASE,
               tokenContextPath)
               && !tokenEquals(caseToken, JavaTokenContext.DEFAULT,
                    tokenContextPath))
        ) {
            throw new IllegalArgumentException("Only accept 'case' or 'default'."); // NOI18N
        }

        int braceDepth = 1; // depth of the braces - need one more left
        while (true) {
            caseToken = findStatement(caseToken);
            if (caseToken == null) {
                return null;
            }
            
            switch (caseToken.getTokenID().getNumericID()) {
                case JavaTokenContext.LBRACE_ID:
                    if (--braceDepth < 0) {
                        return null; // no corresponding right brace
                    }
                    break;

                case JavaTokenContext.RBRACE_ID:
                    braceDepth++;
                    break;

                case JavaTokenContext.SWITCH_ID:
                case JavaTokenContext.DEFAULT_ID:
                    if (braceDepth == 0) {
                        return caseToken;
                    }
                    break;
            }
        }
    }

    /** Find the 'try' when the 'catch' is provided.
     * @param catchToken the token with the 'catch' command
     *  for which the 'try' is being searched.
     * @return corresponding 'try' token or null if there's
     *  no corresponding 'try' statement.
     */
    public TokenItem findTry(TokenItem catchToken) {
        if (catchToken == null || 
             (!tokenEquals(catchToken, JavaTokenContext.CATCH,
               tokenContextPath))
        ) {
            throw new IllegalArgumentException("Only accept 'catch'."); // NOI18N
        }

        int braceDepth = 0; // depth of the braces
        while (true) {
            catchToken = findStatement(catchToken);
            if (catchToken == null) {
                return null;
            }
            
            switch (catchToken.getTokenID().getNumericID()) {
                case JavaTokenContext.LBRACE_ID:
                    if (--braceDepth < 0) {
                        return null; // no corresponding right brace
                    }
                    break;

                case JavaTokenContext.RBRACE_ID:
                    braceDepth++;
                    break;

                case JavaTokenContext.TRY_ID:
                    if (braceDepth == 0) {
                        return catchToken;
                    }
                    break;
            }
        }
    }
    
    /** Find the start of the statement.
     * @param token token from which to start. It searches
     *  backward using findStatement() so it ignores
     *  the given token.
     * @return the statement start token (outer statement start for nested
     *  statements).
     *  It returns the same token if there is '{' before
     *  the given token.
     */
    public TokenItem findStatementStart(TokenItem token) {
        TokenItem t = findStatement(token);
        if (t != null) {
            switch (t.getTokenID().getNumericID()) {
                case JavaTokenContext.SEMICOLON_ID: // ';' found
                    TokenItem scss = findStatement(t);
                    
                    // fix for issue 14274
                    if (scss == null)
                        return token;
                    
                    switch (scss.getTokenID().getNumericID()) {
                        case JavaTokenContext.LBRACE_ID: // '{' then ';'
                        case JavaTokenContext.RBRACE_ID: // '}' then ';'
                        case JavaTokenContext.COLON_ID: // ':' then ';'
                        case JavaTokenContext.CASE_ID: // 'case' then ';'
                        case JavaTokenContext.DEFAULT_ID:
                        case JavaTokenContext.SEMICOLON_ID: // ';' then ';'
                            return t; // return ';'

                        case JavaTokenContext.DO_ID:
                        case JavaTokenContext.FOR_ID:
                        case JavaTokenContext.IF_ID:
                        case JavaTokenContext.WHILE_ID:
                        case JavaTokenContext.SYNCHRONIZED_ID:
                            return findStatementStart(t);

                        case JavaTokenContext.ELSE_ID: // 'else' then ';'
                            // Find the corresponding 'if'
                            TokenItem ifss = findIf(scss);
                            if (ifss != null) { // 'if' ... 'else' then ';'
                                return findStatementStart(ifss);

                            } else { // no valid starting 'if'
                                return scss; // return 'else'
                            }

                        default: // something usual then ';'
                            TokenItem bscss = findStatement(scss);
                            if (bscss != null) {
                                switch (bscss.getTokenID().getNumericID()) {
                                    case JavaTokenContext.SEMICOLON_ID: // ';' then stmt ending with ';'
                                    case JavaTokenContext.LBRACE_ID:
                                    case JavaTokenContext.RBRACE_ID:
                                    case JavaTokenContext.COLON_ID:
                                        return scss; // 

                                    case JavaTokenContext.DO_ID:
                                    case JavaTokenContext.FOR_ID:
                                    case JavaTokenContext.IF_ID:
                                    case JavaTokenContext.WHILE_ID:
                                    case JavaTokenContext.SYNCHRONIZED_ID:
                                        return findStatementStart(bscss);

                                    case JavaTokenContext.ELSE_ID:
                                        // Find the corresponding 'if'
                                        ifss = findIf(bscss);
                                        if (ifss != null) { // 'if' ... 'else' ... ';'
                                            return findStatementStart(ifss);

                                        } else { // no valid starting 'if'
                                            return bscss; // return 'else'
                                        }
                                }
                            }

                            return scss;
                    } // semicolon servicing end

                case JavaTokenContext.LBRACE_ID: // '{' found
                    return token; // return original token

                case JavaTokenContext.RBRACE_ID: // '}' found
                    TokenItem lb = findMatchingToken(t, null,
                            JavaTokenContext.LBRACE, true);
                    if (lb != null) { // valid matching left-brace
                        // Find a stmt-start of the '{'
                        TokenItem lbss = findStatement(lb);
                        if (lbss != null) {
                            switch (lbss.getTokenID().getNumericID()) {
                                case JavaTokenContext.ELSE_ID: // 'else {'
                                    // Find the corresponding 'if'
                                    TokenItem ifss = findIf(lbss);
                                    if (ifss != null) { // valid 'if'
                                        return findStatementStart(ifss);
                                    } else {
                                        return lbss; // return 'else'
                                    }

                                case JavaTokenContext.CATCH_ID: // 'catch (...) {'
                                    // Find the corresponding 'try'
                                    TokenItem tryss = findTry(lbss);
                                    if (tryss != null) { // valid 'try'
                                        return findStatementStart(tryss);
                                    } else {
                                        return lbss; // return 'catch'
                                    }
                                    
                                case JavaTokenContext.DO_ID:
                                case JavaTokenContext.FOR_ID:
                                case JavaTokenContext.IF_ID:
                                case JavaTokenContext.WHILE_ID:
                                case JavaTokenContext.SYNCHRONIZED_ID:
                                    return findStatementStart(lbss);

                            }
                            
                            // another hack to prevent problem described in issue 17033
                            if (lbss.getTokenID().getNumericID() == JavaTokenContext.LBRACE_ID) {
                                return t; // return right brace
                            }
                            
                            return lbss;
                        }

                    }
                    return t; // return right brace

                case JavaTokenContext.COLON_ID:
                case JavaTokenContext.CASE_ID:
                case JavaTokenContext.DEFAULT_ID:
                    return token;

                case JavaTokenContext.ELSE_ID:
                    // Find the corresponding 'if'
                    TokenItem ifss = findIf(t);
                    return (ifss != null) ? findStatementStart(ifss) : t;

                case JavaTokenContext.DO_ID:
                case JavaTokenContext.FOR_ID:
                case JavaTokenContext.IF_ID:
                case JavaTokenContext.WHILE_ID:
                case JavaTokenContext.SYNCHRONIZED_ID:
                    return findStatementStart(t);
            }
        }

        return token; // return original token
    }

    /** Get the indentation for the given token.
     * It first searches whether there's an non-whitespace and a non-leftbrace
     * character on the line with the token and if so,
     * it takes indent of the non-ws char instead.
     * @param token token for which the indent is being searched.
     *  The token itself is ignored and the previous token
     *  is used as a base for the search.
     * @param forceFirstNonWhitespace set true to ignore leftbrace and search 
     * directly for first non-whitespace
     */
    public int getTokenIndent(TokenItem token, boolean forceFirstNonWhitespace) {
        FormatTokenPosition tp = getPosition(token, 0);
        // this is fix for bugs: 7980 and 9111
        // see the findLineFirstNonWhitespaceAndNonLeftBrace definition
        // for more info about the fix
        FormatTokenPosition fnw;
        if (forceFirstNonWhitespace)
            fnw = findLineFirstNonWhitespace(tp);
        else
            fnw = findLineFirstNonWhitespaceAndNonLeftBrace(tp);
        
        if (fnw != null) { // valid first non-whitespace
            tp = fnw;
        }
        return getVisualColumnOffset(tp);
    }

    public int getTokenIndent(TokenItem token) {
        return getTokenIndent(token, false);
    }   
    
    /** Find the indentation for the first token on the line.
     * The given token is also examined in some cases.
     */
    public int findIndent(TokenItem token) {
        int indent = -1; // assign invalid indent

        // First check the given token
        if (token != null) {
            switch (token.getTokenID().getNumericID()) {
                case JavaTokenContext.ELSE_ID:
                    TokenItem ifss = findIf(token);
                    if (ifss != null) {
                        indent = getTokenIndent(ifss);
                    }
                    break;

                case JavaTokenContext.LBRACE_ID:
                    TokenItem stmt = findStatement(token);
                    if (stmt == null) {
                        indent = 0;

                    } else {
                        switch (stmt.getTokenID().getNumericID()) {
                            case JavaTokenContext.DO_ID:
                            case JavaTokenContext.FOR_ID:
                            case JavaTokenContext.IF_ID:
                            case JavaTokenContext.WHILE_ID:
                            case JavaTokenContext.ELSE_ID:
                                indent = getTokenIndent(stmt);
                                break;
                                
                            case JavaTokenContext.LBRACE_ID:
                                indent = getTokenIndent(stmt) + getShiftWidth();
                                break;
                                
                            default:
                                stmt = findStatementStart(token);
                                if (stmt == null) {
                                    indent = 0;

                                } else if (stmt == token) { 
                                    stmt = findStatement(token); // search for delimiter
                                    indent = (stmt != null) ? indent = getTokenIndent(stmt) : 0;

                                } else { // valid statement
                                    indent = getTokenIndent(stmt);
                                    switch (stmt.getTokenID().getNumericID()) {
                                        case JavaTokenContext.LBRACE_ID:
                                            indent += getShiftWidth();
                                            break;
                                    }
                                }
                        }
                    }
                    break;

                case JavaTokenContext.RBRACE_ID:
                    TokenItem rbmt = findMatchingToken(token, null,
                                JavaTokenContext.LBRACE, true);
                    if (rbmt != null) { // valid matching left-brace
                        TokenItem t = findStatement(rbmt);
                        boolean forceFirstNonWhitespace = false;
                        if (t == null) {
                            t = rbmt; // will get indent of the matching brace

                        } else {
                            switch (t.getTokenID().getNumericID()) {
                                case JavaTokenContext.SEMICOLON_ID:
                                case JavaTokenContext.LBRACE_ID:
                                case JavaTokenContext.RBRACE_ID:
                                {
                                    t = rbmt;
                                    forceFirstNonWhitespace = true;
                                }
                            }
                        }
                        // the right brace must be indented to the first 
                        // non-whitespace char - forceFirstNonWhitespace=true
                        indent = getTokenIndent(t, forceFirstNonWhitespace);

                    } else { // no matching left brace
                        indent = getTokenIndent(token); // leave as is
                    }
                    break;

                case JavaTokenContext.CASE_ID:
                case JavaTokenContext.DEFAULT_ID:
                    TokenItem swss = findSwitch(token);
                    if (swss != null) {
                        indent = getTokenIndent(swss) + getShiftWidth();
                    }
                    break;

            }
        }

        // If indent not found, search back for the first important token
        if (indent < 0) { // if not yet resolved
            TokenItem t = findImportantToken(token, null, true);
            if (t != null) { // valid important token
                switch (t.getTokenID().getNumericID()) {
                    case JavaTokenContext.SEMICOLON_ID: // semicolon found
                        TokenItem tt = findStatementStart(token);
                        indent = getTokenIndent(tt);
                            
                        break;

                    case JavaTokenContext.LBRACE_ID:
                        TokenItem lbss = findStatementStart(t);
                        indent = getTokenIndent(t) + getShiftWidth();
                        break;

                    case JavaTokenContext.RBRACE_ID:
                        if (true) {
                            TokenItem t3 = findStatementStart(token);
                            indent = getTokenIndent(t3);
                            break;
                        }

                        /** Check whether the following situation occurs:
                         *  if (t1)
                         *    if (t2) {
                         *      ...
                         *    }
                         * 
                         *  In this case the indentation must be shifted
                         *  one level back.
                         */
                        TokenItem rbmt = findMatchingToken(t, null,
                                JavaTokenContext.LBRACE, true);
                        if (rbmt != null) { // valid matching left-brace
                            // Check whether there's a indent stmt
                            TokenItem t6 = findStatement(rbmt);
                            if (t6 != null) {
                                switch (t6.getTokenID().getNumericID()) {
                                    case JavaTokenContext.ELSE_ID:
                                        /* Check the following situation:
                                         * if (t1)
                                         *   if (t2)
                                         *     c1();
                                         *   else {
                                         *     c2();
                                         *   }
                                         */

                                        // Find the corresponding 'if'
                                        t6 = findIf(t6);
                                        if (t6 != null) { // valid 'if'
                                            TokenItem t7 = findStatement(t6);
                                            if (t7 != null) {
                                                switch (t7.getTokenID().getNumericID()) {
                                                    case JavaTokenContext.DO_ID:
                                                    case JavaTokenContext.FOR_ID:
                                                    case JavaTokenContext.IF_ID:
                                                    case JavaTokenContext.WHILE_ID:
                                                        indent = getTokenIndent(t7);
                                                        break;

                                                    case JavaTokenContext.ELSE_ID:
                                                        indent = getTokenIndent(findStatementStart(t6));
                                                }
                                            }
                                        }
                                        break;

                                    case JavaTokenContext.DO_ID:
                                    case JavaTokenContext.FOR_ID:
                                    case JavaTokenContext.IF_ID:
                                    case JavaTokenContext.WHILE_ID:
                                        /* Check the following:
                                         * if (t1)
                                         *   if (t2) {
                                         *     c1();
                                         *   }
                                         */
                                        TokenItem t7 = findStatement(t6);
                                        if (t7 != null) {
                                            switch (t7.getTokenID().getNumericID()) {
                                                case JavaTokenContext.DO_ID:
                                                case JavaTokenContext.FOR_ID:
                                                case JavaTokenContext.IF_ID:
                                                case JavaTokenContext.WHILE_ID:
                                                    indent = getTokenIndent(t7);
                                                    break;

                                                case JavaTokenContext.ELSE_ID:
                                                    indent = getTokenIndent(findStatementStart(t6));

                                            }
                                        }
                                        break;

                                    case JavaTokenContext.LBRACE_ID: // '{' ... '{'
                                        indent = getTokenIndent(rbmt);
                                        break;

                                }

                            }

                            if (indent < 0) {
                                indent = getTokenIndent(t); // indent of original rbrace
                            }

                        } else { // no matching left-brace
                            indent = getTokenIndent(t); // return indent of '}'
                        }
                        break;

                    case JavaTokenContext.RPAREN_ID:
                        // Try to find the matching left paren
                        TokenItem rpmt = findMatchingToken(t, null, JavaTokenContext.LPAREN, true);
                        if (rpmt != null) {
                            rpmt = findImportantToken(rpmt, null, true);
                            // Check whether there are the indent changing kwds
                            if (rpmt != null && rpmt.getTokenContextPath() == tokenContextPath) {
                                switch (rpmt.getTokenID().getNumericID()) {
                                    case JavaTokenContext.FOR_ID:
                                    case JavaTokenContext.IF_ID:
                                    case JavaTokenContext.WHILE_ID:
                                        // Indent one level
                                        indent = getTokenIndent(rpmt) + getShiftWidth();
                                        break;
                                }
                            }
                        }
                        break;

                    case JavaTokenContext.COLON_ID:
                        TokenItem ttt = findAnyToken(t, null, new TokenID[] {JavaTokenContext.CASE, JavaTokenContext.DEFAULT, JavaTokenContext.FOR, JavaTokenContext.QUESTION, JavaTokenContext.ASSERT}, t.getTokenContextPath(), true);
                        if (ttt != null && ttt.getTokenID().getNumericID() == JavaTokenContext.QUESTION_ID) {
                            indent = getTokenIndent(ttt) + getShiftWidth();
                        } else {
                            // Indent of line with ':' plus one indent level
                            indent = getTokenIndent(t) + getShiftWidth();
                        }
                        break;

                    case JavaTokenContext.QUESTION_ID:
                    case JavaTokenContext.DO_ID:
                    case JavaTokenContext.ELSE_ID:
                        indent = getTokenIndent(t) + getShiftWidth();
                        break;

                }

                if (indent < 0) { // no indent found yet
                    indent = getTokenIndent(t);
                }
            }
        }
        
        if (indent < 0) { // no important token found
            indent = 0;
        }

        return indent;
    }

    public FormatTokenPosition indentLine(FormatTokenPosition pos) {
        int indent = 0; // Desired indent

        // Get the first non-whitespace position on the line
        FormatTokenPosition firstNWS = findLineFirstNonWhitespace(pos);
        if (firstNWS != null) { // some non-WS on the line
            if (isComment(firstNWS)) { // comment is first on the line
                if (isMultiLineComment(firstNWS) && firstNWS.getOffset() != 0) {

                    // Indent the inner lines of the multi-line comment by one
                    indent = getLineIndent(getPosition(firstNWS.getToken(), 0), true) + 1;

                    // If the line is inside multi-line comment and doesn't contain '*'
                    if (!isIndentOnly() && getChar(firstNWS) != '*') {
                        if (isJavaDocComment(firstNWS.getToken())) {
                            if (getFormatLeadingStarInComment()) {
                                // For java-doc it should be OK to add the star
                                insertString(firstNWS, "* "); // NOI18N
                            }

                        } else {
                            // For non-java-doc not because it can be commented code
                            indent = getLineIndent(pos, true);
                        }
                    }

                } else if (!isMultiLineComment(firstNWS)) { // line-comment
                    indent = findIndent(firstNWS.getToken());
                } else { // multi-line comment
                    if (isJavaDocComment(firstNWS.getToken()))
                    {
                        indent = findIndent(firstNWS.getToken());
                    }
                    else
                    {
                        // check whether the multiline comment isn't finished on the same line (see issue 12821)
                        if (firstNWS.getToken().getImage().indexOf('\n') == -1)
                            indent = findIndent(firstNWS.getToken());
                        else
                        indent = getLineIndent(firstNWS, true);
                    }
                }

            } else { // first non-WS char is not comment
                indent = findIndent(firstNWS.getToken());
            }

        } else { // whole line is WS
            // Can be empty line inside multi-line comment
            TokenItem token = pos.getToken();
            if (token == null) {
                token = findLineStart(pos).getToken();
                if (token == null) { // empty line
                    token = getLastToken();
                }
            }

            if (token != null && isMultiLineComment(token)) {
                if (getFormatLeadingStarInComment()
                    && (isIndentOnly() || isJavaDocComment(token))
                ) {
                    // Insert initial '*'
                    insertString(pos, "*"); // NOI18N
                    setIndentShift(1);
                }

                // Indent the multi-comment by one more space
                indent = getVisualColumnOffset(getPosition(token, 0)) + 1;

            } else { // non-multi-line comment
                indent = findIndent(pos.getToken());
            }
        }

        // For indent-only always indent
        return changeLineIndent(pos, indent);
    }

    /** Check whether the given semicolon is inside
     * the for() statement.
     * @param token token to check. It must be a semicolon.
     * @return true if the given semicolon is inside
     *  the for() statement, or false otherwise.
     */
    public boolean isForLoopSemicolon(TokenItem token) {
        if (token == null || !tokenEquals(token,
                    JavaTokenContext.SEMICOLON, tokenContextPath)
        ) {
            throw new IllegalArgumentException("Only accept ';'."); // NOI18N
        }

        int parDepth = 0; // parenthesis depth
        int braceDepth = 0; // brace depth
        boolean semicolonFound = false; // next semicolon
        token = token.getPrevious(); // ignore this semicolon
        while (token != null) {
            if (tokenEquals(token, JavaTokenContext.LPAREN, tokenContextPath)) {
                if (parDepth == 0) { // could be a 'for ('
                    FormatTokenPosition tp = getPosition(token, 0);
                    tp = findImportant(tp, null, false, true);
                    if (tp != null && tokenEquals(tp.getToken(),
                            JavaTokenContext.FOR, tokenContextPath)
                    ) {
                        return true;
                    }
                    return false;

                } else { // non-zero depth
                    parDepth--;
                }

            } else if (tokenEquals(token, JavaTokenContext.RPAREN, tokenContextPath)) {
                parDepth++;

            } else if (tokenEquals(token, JavaTokenContext.LBRACE, tokenContextPath)) {
                if (braceDepth == 0) { // unclosed left brace
                    return false;
                }
                braceDepth--;

            } else if (tokenEquals(token, JavaTokenContext.RBRACE, tokenContextPath)) {
                braceDepth++;

            } else if (tokenEquals(token, JavaTokenContext.SEMICOLON, tokenContextPath)) {
                if (semicolonFound) { // one semicolon already found
                    return false;
                }
                semicolonFound = true;
            }

            token = token.getPrevious();
        }

        return false;
    }

    public boolean getFormatSpaceBeforeParenthesis() {
        return getSettingBoolean(JavaSettingsNames.JAVA_FORMAT_SPACE_BEFORE_PARENTHESIS,
                                 JavaSettingsDefaults.defaultJavaFormatSpaceBeforeParenthesis);
    }

    public boolean getFormatSpaceAfterComma() {
        return getSettingBoolean(JavaSettingsNames.JAVA_FORMAT_SPACE_AFTER_COMMA,
                                 JavaSettingsDefaults.defaultJavaFormatSpaceAfterComma);
    }

    public boolean getFormatNewlineBeforeBrace() {
        return getSettingBoolean(JavaSettingsNames.JAVA_FORMAT_NEWLINE_BEFORE_BRACE,
                                 JavaSettingsDefaults.defaultJavaFormatNewlineBeforeBrace);
    }

    public boolean getFormatLeadingSpaceInComment() {
        return getSettingBoolean(JavaSettingsNames.JAVA_FORMAT_LEADING_SPACE_IN_COMMENT,
                                 JavaSettingsDefaults.defaultJavaFormatLeadingSpaceInComment);
    }

    public boolean getFormatLeadingStarInComment() {
        return getSettingBoolean(JavaSettingsNames.JAVA_FORMAT_LEADING_STAR_IN_COMMENT,
                                 JavaSettingsDefaults.defaultJavaFormatLeadingStarInComment);
    }


    
    /*   this is fix for bugs: 7980 and 9111. if user enters
     *        {   foo();
     *   and press enter at the end of the line, she wants
     *   to be indented just under "f" in "foo();" and not under the "{" 
     *   as it happens now. and this is what findLineFirstNonWhitespaceAndNonLeftBrace checks
     */    
    public FormatTokenPosition findLineFirstNonWhitespaceAndNonLeftBrace(FormatTokenPosition pos) {
        // first call the findLineFirstNonWhitespace
        FormatTokenPosition ftp = super.findLineFirstNonWhitespace(pos);
        if (ftp == null) { // no line start, no WS
            return null;
        }

        // now checks if the first non-whitespace char is "{"
        // if it is, find the next non-whitespace char
        if (!ftp.getToken().getImage().startsWith("{")) // NOI18N
            return ftp;

        // if the left brace is closed on the same line - "{ foo(); }"
        // it must be ignored. otherwise next statement is incorrectly indented 
        // under the "f" and not under the "{" as expected
        FormatTokenPosition eolp = findNextEOL(ftp);
        TokenItem rbmt = findMatchingToken(ftp.getToken(), 
            eolp != null ? eolp.getToken() : null, JavaTokenContext.RBRACE, false);
        if (rbmt != null)
            return ftp;
        
        FormatTokenPosition ftp_next = getNextPosition(ftp);
        if (ftp_next == null)
            return ftp;
        
        FormatTokenPosition ftp2 = findImportant(ftp_next, null, true, false);
        if (ftp2 != null)
            return ftp2;
        else
            return ftp;
    }

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.