/** * @param offset * @param document * @return */ private int getBeginWithoutWhiteSpaces(int offset, FormatterDocument document) { int length = document.getLength(); while (offset < length) { if (!Character.isWhitespace(document.charAt(offset))) { break; } offset++; } return offset; }
private int getBlockStartOffset(int offset, FormatterDocument document) { int length = document.getLength(); while (offset < length) { if (document.charAt(offset) == '{') { break; } offset++; } return offset; }
/** * Scan for given character located at the same line. Return the given offset if non is found. * * @param offset * @param document * @return The offset of the character; The given offset if character not found. */ private int locateCharacterInSameLine(char character, int offset, FormatterDocument document) { for (int i = offset; i < document.getLength(); i++) { char c = document.charAt(i); if (c == character) { return i; } if (c == '\n' || c == '\r') { break; } } return offset; }
/** * Searchings backwards starting at 'offset' and continues until it finds a non-whitespace char * (ignores punctuation) * * @param offset * @param document * @return */ private int getEndWithoutWhiteSpaces(int offset, FormatterDocument document) { while (offset > 0) { if (!Character.isWhitespace(document.charAt(offset)) && document.charAt(offset) != '{' && !PUNCTUATION.contains(Character.toString(document.charAt(offset)))) { break; } offset--; } return offset; }
private void pushFormatterSelectorNodes(CSSSelectorNode[] selectors) { for (int i = 0; i < selectors.length; i++) { CSSSelectorNode selectorNode = selectors[i]; FormatterBlockWithBeginNode formatterSelectorNode = new FormatterCSSSelectorNode(document, i == 0, false); int selectorEndOffset = getEndWithoutWhiteSpaces(selectorNode.getEndingOffset() + 1, document) + 1; formatterSelectorNode.setBegin( createTextNode( document, getBeginWithoutWhiteSpaces(selectorNode.getStartingOffset(), document), selectorEndOffset)); push(formatterSelectorNode); checkedPop(formatterSelectorNode, -1); int nextNonWhiteSpaceOffset = getBeginWithoutWhiteSpaces(selectorEndOffset, document); TypePunctuation punctuation = getTypePunctuationForChar(document.charAt(nextNonWhiteSpaceOffset)); if (punctuation != null) { findAndPushPunctuationNode(punctuation, nextNonWhiteSpaceOffset, false); } } }
// This is a temporary fix for custom at-rules. When the parser adds support to return the ruleID, // this will need to // be changed private void pushAtRuleNode(CSSNode atRuleNode) { int length = document.getLength(); int selectorStartingOffset = atRuleNode.getStartingOffset(); int selectEndingOffset = atRuleNode.getEndingOffset(); // Locate first white space after the @rule while (selectorStartingOffset < length) { if (Character.isWhitespace(document.charAt(selectorStartingOffset))) { break; } selectorStartingOffset++; } // Find the starting offset for the selector selectorStartingOffset = getBeginWithoutWhiteSpaces(selectorStartingOffset, document); // Find the end offset for the selector while (selectEndingOffset >= selectorStartingOffset) { if (!Character.isWhitespace(document.charAt(selectEndingOffset - 1))) { break; } selectEndingOffset--; } // Push an At-Node to control the lines separators. FormatterCSSAtRuleNode atNode = new FormatterCSSAtRuleNode(document); atNode.setBegin( createTextNode(document, atRuleNode.getStartingOffset(), selectorStartingOffset)); push(atNode); checkedPop(atNode, -1); // We use a selector node for now, we may want to create a new formatter node type for rule id FormatterBlockWithBeginNode formatterSelectorNode = new FormatterCSSSelectorNode(document, false, false); formatterSelectorNode.setBegin( createTextNode( document, getBeginWithoutWhiteSpaces(selectorStartingOffset, document), getEndWithoutWhiteSpaces(selectEndingOffset, document) + 1)); push(formatterSelectorNode); findAndPushPunctuationNode(TypePunctuation.SEMICOLON, selectEndingOffset, false); checkedPop(formatterSelectorNode, -1); }
/** * Locate and push a punctuation node. * * @param offsetToSearch - The offset that will be used as the start for the search of the * punctuation characters. */ private void findAndPushPunctuationNode( TypePunctuation type, int offsetToSearch, boolean isEndofDeclarationNode) { char punctuationType = type.toString().charAt(0); int punctuationOffset = locateCharForward(document, punctuationType, offsetToSearch); if (punctuationOffset != offsetToSearch || document.charAt(punctuationOffset) == punctuationType) { FormatterCSSPunctuationNode punctuationNode = new FormatterCSSPunctuationNode(document, type, isEndofDeclarationNode); punctuationNode.setBegin(createTextNode(document, punctuationOffset, punctuationOffset + 1)); push(punctuationNode); checkedPop(punctuationNode, -1); } }
private void pushDeclarationValueNode( CSSExpressionNode expressionNode, boolean isLastDeclaration) { int expressionEndOffset = expressionNode.getEndingOffset(); int semicolonLocation = locateCharacterSkippingWhitespaces(document, expressionEndOffset + 1, ';', false); int commaLocation = locateCharacterSkippingWhitespaces(document, expressionEndOffset + 1, ',', false); int forwardSlashLocation = locateCharacterSkippingWhitespaces(document, expressionEndOffset + 1, '/', false); int LFLocation = locateCharacterSkippingWhitespaces(document, expressionEndOffset + 1, '\n', false); int CRLocation = locateCharacterSkippingWhitespaces(document, expressionEndOffset + 1, '\r', false); boolean endsWithSemicolon = false; boolean endsWithComma = false; boolean endsWithSlash = false; boolean isLastNodeInDeclaration = false; if (document.charAt(semicolonLocation) == ';') { endsWithSemicolon = true; } if (document.charAt(commaLocation) == ',') { endsWithComma = true; } if (document.charAt(forwardSlashLocation) == '/') { endsWithSlash = true; } if (document.charAt(forwardSlashLocation) == '/') { endsWithSlash = true; } if ((document.charAt(LFLocation) == '\n' || document.charAt(CRLocation) == '\r') && isLastDeclaration) { isLastNodeInDeclaration = true; } FormatterBlockWithBeginNode formatterDeclarationValueNode = new FormatterCSSDeclarationValueNode( document, isLastNodeInDeclaration, endsWithComma || endsWithSemicolon || endsWithSlash); formatterDeclarationValueNode.setBegin( createTextNode( document, expressionNode.getStartingOffset(), expressionNode.getEndingOffset() + 1)); push(formatterDeclarationValueNode); checkedPop(formatterDeclarationValueNode, -1); if (endsWithComma) { findAndPushPunctuationNode(TypePunctuation.COMMA, commaLocation, false); } }
/** * build * * @param parseResult * @param document * @return */ public IFormatterContainerNode build(IParseNode parseResult, FormatterDocument document) { this._document = document; // create the formatter root node IFormatterContainerNode rootNode = new JSONRootFormatNode(document); // begin the transformation start(rootNode); JSONFormattingWalker walker = new JSONFormattingWalker(); JSONParseRootNode jsonRootNode = (JSONParseRootNode) parseResult; jsonRootNode.accept(walker); // end the transformation checkedPop(rootNode, document.getLength()); return rootNode; }
/** * @param parseResult * @param document * @return */ public IFormatterContainerNode build(IParseNode parseResult, FormatterDocument document) { this.document = document; final IFormatterContainerNode rootNode = new FormatterCSSRootNode(document); start(rootNode); IParseNode[] children = parseResult.getChildren(); addNodes(children); checkedPop(rootNode, document.getLength()); // Collect Off/On tags if (parseResult instanceof IParseRootNode) { setOffOnRegions( resolveOffOnRegions( (IParseRootNode) parseResult, document, CSSFormatterConstants.FORMATTER_OFF_ON_ENABLED, CSSFormatterConstants.FORMATTER_OFF, CSSFormatterConstants.FORMATTER_ON)); } return rootNode; }
private void pushFormatterDeclarationNodes( int parentEndOffset, CSSDeclarationNode[] declarations, FormatterBlockWithBeginEndNode formatterBlockNode) { for (int i = 0; i < declarations.length; ++i) { CSSDeclarationNode declarationNode = declarations[i]; CSSExpressionNode expressionNode = declarationNode.getAssignedValue(); // If we run into a CSSErrorDeclarationNode, we just create a text node and move on to the // next declaration // node if (declarationNode instanceof CSSErrorDeclarationNode) { formatterBlockNode.addChild( createTextNode( document, declarationNode.getStartingOffset(), declarationNode.getEndingOffset() + 1)); // Create text nodes for comments between declaration findAndPushCommentsBetweenDeclarations( parentEndOffset, declarations, formatterBlockNode, i); continue; } // push the property FormatterBlockWithBeginNode formatterDeclarationPropertyNode = new FormatterCSSDeclarationPropertyNode(document); int propertyEndOffset = getEndWithoutWhiteSpaces( locateCharacterInSameLine(':', declarationNode.getStartingOffset(), document), document); formatterDeclarationPropertyNode.setBegin( createTextNode(document, declarationNode.getStartingOffset(), propertyEndOffset + 1)); push(formatterDeclarationPropertyNode); checkedPop(formatterDeclarationPropertyNode, -1); // push the ':' findAndPushPunctuationNode(TypePunctuation.PROPERTY_COLON, propertyEndOffset, false); // push the value for the declaration if (expressionNode != null) { if (expressionNode instanceof CSSTermListNode) { pushTermListNode((CSSTermListNode) expressionNode, i == declarations.length - 1); } else { pushDeclarationValueNode(expressionNode, i == declarations.length - 1); } // Push a text node for status nodes: currently it's only !important IRange statusRange = declarationNode.getStatusRange(); if (declarationNode.getStatus() != null) { formatterBlockNode.addChild( createTextNode( document, statusRange.getStartingOffset(), statusRange.getEndingOffset() + 1)); } } // Push a semicolon if the declaration ends with one if (document.charAt(declarationNode.getEndingOffset()) == ';') { findAndPushPunctuationNode( TypePunctuation.SEMICOLON, declarationNode.getEndingOffset(), true); } // Create text nodes for comments between declaration findAndPushCommentsBetweenDeclarations(parentEndOffset, declarations, formatterBlockNode, i); } }