private void getIndentFromState( List<IndentCommand> iis, boolean updateState, int lineStartOffset) { Stack<TplStackItem> blockStack = getStack(); int lastUnprocessedItem = blockStack.size(); for (int i = blockStack.size() - 1; i >= 0; i--) { if (!blockStack.get(i).processed) { lastUnprocessedItem = i; } else { break; } } for (int i = lastUnprocessedItem; i < blockStack.size(); i++) { TplStackItem item = blockStack.get(i); assert !item.processed : item; if (item.state == StackItemState.IN_BODY) { IndentCommand ii = new IndentCommand(IndentCommand.Type.INDENT, lineStartOffset); if (item.indent != -1) { ii.setFixedIndentSize(item.indent); } iis.add(ii); if (updateState) { item.processed = Boolean.TRUE; } } else if (item.state == StackItemState.BODY_FINISHED) { IndentCommand ii = new IndentCommand(IndentCommand.Type.RETURN, lineStartOffset); iis.add(ii); if (updateState) { item.processed = Boolean.TRUE; blockStack.remove(i); i--; } } } }
@Override protected List<IndentCommand> getLineIndent( IndenterContextData<TplTopTokenId> context, List<IndentCommand> preliminaryNextLineIndent) throws BadLocationException { Stack<TplStackItem> blockStack = getStack(); List<IndentCommand> iis = new ArrayList<IndentCommand>(); getIndentFromState(iis, true, context.getLineStartOffset()); JoinedTokenSequence<TplTopTokenId> ts = context.getJoinedTokenSequences(); ts.move(context.getLineStartOffset()); boolean isSmartyBodyCommand = false; boolean isSmartyElseCommand = false; boolean afterDelimiter = false; int embeddingLevel = 0; String lastTplCommand = ""; // iterate over tokens on the line and push to stack any changes while (!context.isBlankLine() && ts.moveNext() && ((ts.isCurrentTokenSequenceVirtual() && ts.offset() < context.getLineEndOffset()) || ts.offset() <= context.getLineEndOffset())) { Token<TplTopTokenId> token = ts.token(); if (token == null) { continue; } else if (ts.embedded() != null) { // indent for smarty command of the zero embedding level if (embeddingLevel == 1 && afterDelimiter) { if (token.id() == TplTopTokenId.T_SMARTY && context.isIndentThisLine()) { String tplToken = getFunctionalTplTokenId(token); isSmartyBodyCommand = isBodyCommand(tplToken, context); if (isSmartyBodyCommand) { lastTplCommand = tplToken; isSmartyElseCommand = isElseCommand(tplToken); } } else { isSmartyBodyCommand = false; isSmartyElseCommand = false; } } continue; } if (token.id() == TplTopTokenId.T_SMARTY_OPEN_DELIMITER) { afterDelimiter = true; embeddingLevel++; TplStackItem state = new TplStackItem(StackItemState.IN_RULE); blockStack.push(state); } else if (token.id() == TplTopTokenId.T_SMARTY_CLOSE_DELIMITER) { afterDelimiter = false; if (isInState(blockStack, StackItemState.IN_RULE)) { // check that IN_RULE is the last state TplStackItem item = blockStack.pop(); embeddingLevel--; if (embeddingLevel == 0) { assert item.state == StackItemState.IN_RULE; if (isSmartyBodyCommand) { if (!blockStack.isEmpty() && isInRelatedCommand(lastTplCommand, blockStack.peek().getCommand())) { if (isSmartyElseCommand) { String command = blockStack.pop().command; blockStack.push(new TplStackItem(StackItemState.IN_BODY, command)); } else { blockStack.pop(); } iis.add(new IndentCommand(IndentCommand.Type.RETURN, preservedLineIndentation)); } else { blockStack.push(new TplStackItem(StackItemState.IN_BODY, lastTplCommand)); } } } } } else if (isCommentToken(token)) { int start = context.getLineStartOffset(); if (start < ts.offset()) { start = ts.offset(); } int commentEndOffset = ts.offset() + ts.token().text().toString().trim().length() - 1; int end = context.getLineEndOffset(); if (end > commentEndOffset) { end = commentEndOffset; } if (start > end) { // do nothing } else if (start == ts.offset()) { if (end < commentEndOffset) { // if comment ends on next line put formatter to IN_COMMENT state int lineStart = Utilities.getRowStart(getDocument(), ts.offset()); preservedLineIndentation = start - lineStart; } } else if (end == commentEndOffset) { String text = getDocument().getText(start, end - start + 1).trim(); if (!text.startsWith("*/")) { // if line does not start with '*/' then treat it as unformattable IndentCommand ic = new IndentCommand( IndentCommand.Type.PRESERVE_INDENTATION, context.getLineStartOffset()); ic.setFixedIndentSize(preservedLineIndentation); iis.add(ic); } preservedLineIndentation = -1; } else { IndentCommand ic = new IndentCommand( IndentCommand.Type.PRESERVE_INDENTATION, context.getLineStartOffset()); ic.setFixedIndentSize(preservedLineIndentation); iis.add(ic); } } } if (context.isBlankLine() && iis.isEmpty()) { IndentCommand ic = new IndentCommand(IndentCommand.Type.PRESERVE_INDENTATION, context.getLineStartOffset()); ic.setFixedIndentSize(preservedLineIndentation); iis.add(ic); } if (iis.isEmpty()) { iis.add(new IndentCommand(IndentCommand.Type.NO_CHANGE, context.getLineStartOffset())); } if (context.getNextLineStartOffset() != -1) { getIndentFromState(preliminaryNextLineIndent, false, context.getNextLineStartOffset()); if (preliminaryNextLineIndent.isEmpty()) { preliminaryNextLineIndent.add( new IndentCommand(IndentCommand.Type.NO_CHANGE, context.getNextLineStartOffset())); } } return iis; }