@Override protected int getPreservedLineInitialIndentation(JoinedTokenSequence<JspTokenId> ts) throws BadLocationException { int[] index = ts.index(); boolean found = false; do { if (ts.token().id() == JspTokenId.COMMENT) { String comment = ts.token().text().toString().trim(); if (comment.startsWith("<%--")) { found = true; break; } } else { break; } } while (ts.movePrevious()); int indent = 0; if (found) { int lineStart = Utilities.getRowStart(getDocument(), ts.offset()); // TODO: can comment token start with spaces?? if yes then adjust // column to point to first non-whitespace int column = ts.offset(); indent = column - lineStart; } ts.moveIndex(index); ts.moveNext(); return indent; }
private void addFolds( BaseDocument doc, List<? extends ASTElement> elements, Map<String, List<OffsetRange>> folds, List<OffsetRange> codeblocks) throws BadLocationException { for (ASTElement element : elements) { ElementKind kind = element.getKind(); switch (kind) { case FIELD: case METHOD: case CONSTRUCTOR: case CLASS: case MODULE: ASTNode node = element.getNode(); OffsetRange range = ASTUtils.getRangeFull(node, doc); // beware of synthetic elements if ((kind == ElementKind.METHOD && !((MethodNode) node).isSynthetic()) || (kind == ElementKind.CONSTRUCTOR && !((ConstructorNode) node).isSynthetic()) || (kind == ElementKind.FIELD && ((FieldNode) node).getInitialExpression() instanceof ClosureExpression) // Only make nested classes/modules foldable, similar to what the java editor is doing || (range.getStart() > Utilities.getRowStart(doc, range.getStart())) && kind != ElementKind.FIELD) { int start = range.getStart(); // Start the fold at the END of the line behind last non-whitespace, remove curly brace, // if any start = Utilities.getRowLastNonWhite(doc, start); if (start >= 0 && doc.getChars(start, 1)[0] != '{') { start++; } int end = range.getEnd(); if (start != (-1) && end != (-1) && start < end && end <= doc.getLength()) { range = new OffsetRange(start, end); codeblocks.add(range); } } break; } List<? extends ASTElement> children = element.getChildren(); if (children != null && children.size() > 0) { addFolds(doc, children, folds, codeblocks); } } }
@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; }