예제 #1
0
  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);
      }
    }
  }
예제 #2
0
  /**
   * Accepts a CSSPageNode and breaks down the node into different formatter nodes which should
   * represent it while rewriting the doc.<br>
   * The CSSPageNode will be broken down into several nodes of type FormatterCSSSelectorNode,
   * FormatterCSSBlockNode, and FormatterCSSDeclarationNode (if declarations are present).
   *
   * @param pageNode
   */
  private void pushFormatterPageNode(CSSPageNode pageNode) {
    // Push an At-Node to control the lines separators.
    FormatterCSSAtRuleNode atNode = new FormatterCSSAtRuleNode(document);
    // +5 for @page length
    int pageNodeStart = pageNode.getStartingOffset();
    atNode.setBegin(createTextNode(document, pageNodeStart, pageNodeStart + PAGE_AT_RULE_LENGTH));
    push(atNode);
    checkedPop(atNode, -1);

    CSSPageSelectorNode selector = pageNode.getSelector();
    CSSDeclarationNode[] declarations = pageNode.getDeclarations();
    int blockStartOffset = getBlockStartOffset(pageNodeStart + 1, document);

    if (selector != null) {
      blockStartOffset = getBlockStartOffset(selector.getEndingOffset() + 1, document);

      FormatterBlockWithBeginNode formatterSelectorNode =
          new FormatterCSSSelectorNode(document, true, false);
      formatterSelectorNode.setBegin(
          createTextNode(
              document,
              getBeginWithoutWhiteSpaces(pageNodeStart, document),
              getEndWithoutWhiteSpaces(pageNodeStart + PAGE_AT_RULE_LENGTH, document) + 1));
      push(formatterSelectorNode);
      checkedPop(formatterSelectorNode, -1);

      formatterSelectorNode = new FormatterCSSSelectorNode(document, false, false);
      // we do startingOffset - 1 to account for the ':'
      formatterSelectorNode.setBegin(
          createTextNode(
              document,
              getBeginWithoutWhiteSpaces(selector.getStartingOffset() - 1, document),
              getEndWithoutWhiteSpaces(selector.getEndingOffset() + 1, document) + 1));

      push(formatterSelectorNode);
      checkedPop(formatterSelectorNode, -1);
    }

    FormatterBlockWithBeginEndNode formatterBlockNode = new FormatterCSSBlockNode(document, false);
    formatterBlockNode.setBegin(createTextNode(document, blockStartOffset, blockStartOffset + 1));
    push(formatterBlockNode);

    // Don't create text nodes when there are no declarations, or only white space
    if (declarations != null
        && declarations.length != 0
        && getBeginWithoutWhiteSpaces(blockStartOffset + 1, document)
            < declarations[0].getStartingOffset()) {
      formatterBlockNode.addChild(
          createTextNode(document, blockStartOffset + 1, declarations[0].getStartingOffset()));
    }

    pushFormatterDeclarationNodes(pageNode.getEndingOffset(), declarations, formatterBlockNode);

    checkedPop(formatterBlockNode, -1);
    formatterBlockNode.setEnd(
        createTextNode(document, pageNode.getEndingOffset(), pageNode.getEndingOffset() + 1));
  }
예제 #3
0
  /**
   * Pushes the selector nodes in a media node. (Also recursively handles nodes inside parenthesis)
   *
   * @param medias
   * @param startIndex
   * @return The index of the last medias that it was pushed
   */
  private int pushFormatterMediaSelectorNodes(CSSTextNode[] medias, int startIndex) {
    boolean previousNodeIsPunctuation = startIndex > 0;
    int lastMediaIndex = startIndex;
    for (; lastMediaIndex < medias.length; lastMediaIndex++) {
      CSSTextNode mediaSelectorNode = medias[lastMediaIndex];
      String selectorText = mediaSelectorNode.getText();

      // For media nodes that are just punctuation, we skip it
      if (selectorText.length() == 1 && NON_LETTER_PATTERN.matcher(selectorText).matches()) {
        TypePunctuation punctuation = getTypePunctuationForChar(selectorText.charAt(0));
        // push a punctuation node if it's part of the list
        if (punctuation != null) {
          findAndPushPunctuationNode(punctuation, mediaSelectorNode.getStartingOffset(), false);
        } else if (selectorText.charAt(0) == '(') {
          // This is the start of a parenthesis block
          int openParen = mediaSelectorNode.getStartingOffset();
          FormatterBlockWithBeginEndNode parenthesisNode =
              new FormatterCSSParenthesesNode(document);
          parenthesisNode.setBegin(createTextNode(document, openParen, openParen + 1));

          push(parenthesisNode);
          // push contents inside the parenthesis
          lastMediaIndex = pushFormatterMediaSelectorNodes(medias, lastMediaIndex + 1);

          checkedPop(parenthesisNode, -1);
          if (lastMediaIndex >= medias.length) {
            break;
          }
          mediaSelectorNode = medias[lastMediaIndex];
          parenthesisNode.setEnd(
              createTextNode(
                  document,
                  mediaSelectorNode.getStartingOffset(),
                  mediaSelectorNode.getStartingOffset() + 1));
        } else if (selectorText.charAt(0) == ')') {
          // This is the end of a parenthesis block
          return lastMediaIndex;
        }
        previousNodeIsPunctuation = true;
        // otherwise, we still skip all other punctuation
        continue;
      }

      FormatterBlockWithBeginNode formatterSelectorNode =
          new FormatterCSSSelectorNode(document, false, previousNodeIsPunctuation);
      formatterSelectorNode.setBegin(
          createTextNode(
              document,
              getBeginWithoutWhiteSpaces(mediaSelectorNode.getStartingOffset(), document),
              getEndWithoutWhiteSpaces(mediaSelectorNode.getEndingOffset() + 1, document) + 1));
      push(formatterSelectorNode);
      checkedPop(formatterSelectorNode, -1);
      previousNodeIsPunctuation = false;
    }
    return lastMediaIndex;
  }
예제 #4
0
  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);
    }
  }
예제 #5
0
  // 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);
  }
예제 #6
0
  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);
    }
  }