private static TextRange buildRangeForBraces(
     TextRange range, @NotNull ASTNode astNode, IElementType lbraceType, IElementType rbraceType) {
   ASTNode lBrace = astNode.findChildByType(lbraceType);
   ASTNode rBrace = astNode.findChildByType(rbraceType);
   if (lBrace != null && rBrace != null) {
     range = buildRange(range, lBrace.getStartOffset() + 1, rBrace.getStartOffset());
   }
   return range;
 }
Example #2
0
 @NotNull
 public TextRange getTextRange() {
   if (myElements.length == 0) {
     final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild((ASTNode) myTag);
     if (child != null)
       return new TextRange(child.getStartOffset() + 1, child.getStartOffset() + 1);
     return new TextRange(
         myTag.getTextRange().getEndOffset(), myTag.getTextRange().getEndOffset());
   }
   return new TextRange(
       myElements[0].getTextRange().getStartOffset(),
       myElements[myElements.length - 1].getTextRange().getEndOffset());
 }
  private static boolean isEmbraced(@Nullable PsiElement element, int offset) {
    if (element == null) {
      return false;
    }
    ASTNode node = element.getNode();
    if (node == null) {
      return false;
    }
    final ASTNode lbrace = node.findChildByType(CfscriptTokenTypes.L_BRACKET);
    final ASTNode rbrace = node.findChildByType(CfscriptTokenTypes.R_BRACKET);

    if (lbrace == null || rbrace == null) {
      return false;
    }
    return lbrace.getStartOffset() < offset && rbrace.getStartOffset() >= offset;
  }
 @Override
 protected TextRange calculateDefaultRangeInElement() {
   TextRange _xblockexpression = null;
   {
     final ASTNode referencenNode = this.getReferenceNode();
     int _startOffset = referencenNode.getStartOffset();
     ASTNode _node = this.myElement.getNode();
     int _startOffset_1 = _node.getStartOffset();
     final int startOffset = (_startOffset - _startOffset_1);
     ASTNode _referenceNode = this.getReferenceNode();
     int _textLength = _referenceNode.getTextLength();
     final int endOffset = (startOffset + _textLength);
     _xblockexpression = new TextRange(startOffset, endOffset);
   }
   return _xblockexpression;
 }
 private SchemaPrefixReference createPrefixReference(
     ASTNode startTagName, String prefix, TagNameReference tagRef) {
   return new SchemaPrefixReference(
       this,
       TextRange.from(startTagName.getStartOffset() - getStartOffset(), prefix.length()),
       prefix,
       tagRef);
 }
  private static void addFoldingDescriptors(
      final List<FoldingDescriptor> descriptors, final PsiElement tag, @NotNull Document document) {

    TextRange elementRange = tag.getTextRange();
    final int start = elementRange.getStartOffset();
    final int end = elementRange.getEndOffset();

    if (start + 1 < end) {
      TextRange range = null;
      ASTNode astNode = tag.getNode();
      IElementType astType = astNode.getElementType();

      if (tag instanceof CfmlTag) {
        // if (tag instanceof CfmlTagFunctionImpl || tag instanceof CfmlTagComponentImpl || tag
        // instanceof CfmlTagScriptImpl) {
        range =
            buildRangeForBraces(
                range, astNode, CfmlTokenTypes.R_ANGLEBRACKET, CfmlTokenTypes.LSLASH_ANGLEBRACKET);
        // }
      } else if (astType == CfmlElementTypes.FUNCTIONBODY
          || astType == CfmlElementTypes.BLOCK_OF_STATEMENTS) {
        range = buildRange(range, start, end);
      } else if (astType == CfmlElementTypes.SWITCHEXPRESSION) {
        ASTNode lparen = astNode.findChildByType(CfscriptTokenTypes.L_CURLYBRACKET);
        ASTNode rparen = astNode.findChildByType(CfscriptTokenTypes.R_CURLYBRACKET);
        if (lparen != null && rparen != null) {
          range = buildRange(range, lparen.getStartOffset(), rparen.getTextRange().getEndOffset());
        }
      } else if (tag instanceof PsiComment) {
        boolean isColdFusionComment = astNode.getElementType() == CfmlTokenTypes.COMMENT;
        int endIndex = astNode.getText().lastIndexOf(isColdFusionComment ? "--->" : "*/");
        if (endIndex != -1) {
          String commentText = astNode.getText().substring(0, endIndex);
          if (commentText.contains("\n")) {
            int startOffset = tag.getTextRange().getStartOffset();
            range =
                buildRange(
                    range,
                    startOffset + (isColdFusionComment ? "<!---" : "/*").length(),
                    startOffset + commentText.length());
          }
        }
      }

      if (range != null) {
        descriptors.add(new FoldingDescriptor(astNode, range));
      }

      // TODO: insert condition
      addFoldingDescriptorsFromChildren(descriptors, tag, document);
    }
  }
 @Override
 public void updateParameterInfo(
     @NotNull JetValueArgumentList argumentList, @NotNull UpdateParameterInfoContext context) {
   if (context.getParameterOwner() != argumentList) context.removeHint();
   int offset = context.getOffset();
   ASTNode child = argumentList.getNode().getFirstChildNode();
   int i = 0;
   while (child != null && child.getStartOffset() < offset) {
     if (child.getElementType() == JetTokens.COMMA) ++i;
     child = child.getTreeNext();
   }
   context.setCurrentParameter(i);
 }
 protected Set<AbstractElement> computeFollowElements(final CompletionParameters parameters) {
   Editor _editor = parameters.getEditor();
   Document _document = _editor.getDocument();
   PsiElement _position = parameters.getPosition();
   ASTNode _node = _position.getNode();
   int _startOffset = _node.getStartOffset();
   TextRange _textRange = new TextRange(0, _startOffset);
   final String text = _document.getText(_textRange);
   final Collection<FollowElement> followElements =
       this.contentAssistParser.getFollowElements(text, false);
   final HashSet<AbstractElement> allElements = CollectionLiterals.<AbstractElement>newHashSet();
   this.followElementComputer.computeFollowElements(followElements, allElements);
   return allElements;
 }
  static void registerProblem(
      BnfExpression choice,
      BnfExpression branch,
      String message,
      ProblemsHolder problemsHolder,
      LocalQuickFix... fixes) {
    TextRange textRange = branch.getTextRange();
    if (textRange.isEmpty()) {
      ASTNode nextOr = TreeUtil.findSibling(branch.getNode(), BnfTypes.BNF_OP_OR);
      ASTNode prevOr = TreeUtil.findSiblingBackward(branch.getNode(), BnfTypes.BNF_OP_OR);

      int shift = choice.getTextRange().getStartOffset();
      int startOffset = prevOr != null ? prevOr.getStartOffset() - shift : 0;
      TextRange range =
          new TextRange(
              startOffset,
              nextOr != null
                  ? nextOr.getStartOffset() + 1 - shift
                  : Math.min(startOffset + 2, choice.getTextLength()));
      problemsHolder.registerProblem(choice, range, message, fixes);
    } else {
      problemsHolder.registerProblem(branch, message, fixes);
    }
  }
  protected int getCloseQuoteOffset() {
    PsiElement lastChild = getLastChild();

    if (lastChild instanceof PerlParsableStringWrapperlImpl) {
      PsiElement realString = lastChild.getFirstChild();
      assert realString instanceof PerlStringImplMixin;
      return ((PerlStringImplMixin) realString).getCloseQuoteOffset();
    }

    ASTNode currentNode = lastChild.getNode();

    if (PerlParserUtil.CLOSE_QUOTES.contains(currentNode.getElementType()))
      return currentNode.getStartOffset();

    // unclosed string
    return lastChild.getTextOffset() + lastChild.getTextLength();
  }
  @Nullable
  private static TextRange getEndTagRange(ASTNode tagNode) {
    final ASTNode endTagStart = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(tagNode);
    if (endTagStart == null) {
      return null;
    }

    ASTNode endTagEnd = endTagStart;
    while (endTagEnd != null && endTagEnd.getElementType() != XmlTokenType.XML_TAG_END) {
      endTagEnd = endTagEnd.getTreeNext();
    }

    if (endTagEnd == null) {
      return null;
    }

    return new TextRange(endTagStart.getStartOffset(), endTagEnd.getTextRange().getEndOffset());
  }
  @Override
  protected String replaceWithPsiInLeaf(
      final TextRange textRange, String whiteSpace, ASTNode leafElement) {
    if (!myCanModifyAllWhiteSpaces) {
      if (leafElement.getElementType() == TokenType.WHITE_SPACE) return null;
      LOG.assertTrue(leafElement.getPsi().isValid());
      ASTNode prevNode = TreeUtil.prevLeaf(leafElement);

      if (prevNode != null) {
        IElementType type = prevNode.getElementType();
        if (type == TokenType.WHITE_SPACE) {
          final String text = prevNode.getText();

          final @NonNls String cdataStartMarker = "<![CDATA[";
          final int cdataPos = text.indexOf(cdataStartMarker);
          if (cdataPos != -1 && whiteSpace.indexOf(cdataStartMarker) == -1) {
            whiteSpace = mergeWsWithCdataMarker(whiteSpace, text, cdataPos);
            if (whiteSpace == null) return null;
          }

          prevNode = TreeUtil.prevLeaf(prevNode);
          type = prevNode != null ? prevNode.getElementType() : null;
        }

        final @NonNls String cdataEndMarker = "]]>";
        if (type == XmlTokenType.XML_CDATA_END && whiteSpace.indexOf(cdataEndMarker) == -1) {
          final ASTNode at = findElementAt(prevNode.getStartOffset());

          if (at != null && at.getPsi() instanceof PsiWhiteSpace) {
            final String s = at.getText();
            final int cdataEndPos = s.indexOf(cdataEndMarker);
            whiteSpace = mergeWsWithCdataMarker(whiteSpace, s, cdataEndPos);
            leafElement = at;
          } else {
            whiteSpace = null;
          }
          if (whiteSpace == null) return null;
        }
      }
    }
    FormatterUtil.replaceWhiteSpace(whiteSpace, leafElement, TokenType.WHITE_SPACE, textRange);
    return whiteSpace;
  }
 /**
  * Current handler inserts closing curly brace (right brace) if necessary. There is a possible
  * case that it should be located more than one line forward.
  *
  * <p><b>Example</b>
  *
  * <pre>
  *     if (test1()) {
  *     } else {<caret> if (test2()) {
  *         foo();
  *     }
  * </pre>
  *
  * <p>We want to get this after the processing:
  *
  * <pre>
  *     if (test1()) {
  *     } else {
  *         if (test2()) {
  *             foo();
  *         }
  *     }
  * </pre>
  *
  * I.e. closing brace should be inserted two lines below current caret line. Hence, we need to
  * calculate correct offset to use for brace inserting. This method is responsible for that.
  *
  * <p>In essence it inspects PSI structure and finds PSE elements with the max length that starts
  * at caret offset. End offset of that element is used as an insertion point.
  *
  * @param file target PSI file
  * @param text text from the given file
  * @param offset target offset where line feed will be inserted
  * @return offset to use for inserting closing brace
  */
 protected int calculateOffsetToInsertClosingBrace(
     PsiFile file, CharSequence text, final int offset) {
   PsiElement element = PsiUtilCore.getElementAtOffset(file, offset);
   ASTNode node = element.getNode();
   if (node != null && node.getElementType() == TokenType.WHITE_SPACE) {
     return CharArrayUtil.shiftForwardUntil(text, offset, "\n");
   }
   for (PsiElement parent = element.getParent(); parent != null; parent = parent.getParent()) {
     ASTNode parentNode = parent.getNode();
     if (parentNode == null || parentNode.getStartOffset() != offset) {
       break;
     }
     element = parent;
   }
   if (element.getTextOffset() != offset) {
     return CharArrayUtil.shiftForwardUntil(text, offset, "\n");
   }
   return element.getTextRange().getEndOffset();
 }
  @Nullable
  private static TextRange getStartTagRange(ASTNode tagNode) {
    final ASTNode startTagStart = XmlChildRole.START_TAG_START_FINDER.findChild(tagNode);
    if (startTagStart == null) {
      return null;
    }

    ASTNode tagName = startTagStart.getTreeNext();
    if (tagName == null || tagName.getElementType() != XmlTokenType.XML_NAME) {
      return null;
    }

    ASTNode next = tagName.getTreeNext();
    if (next != null && next.getElementType() == XmlTokenType.XML_TAG_END) {
      tagName = next;
    }

    return new TextRange(startTagStart.getStartOffset(), tagName.getTextRange().getEndOffset());
  }
 public void getLanguagesToInject(
     @NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement host) {
   Pair<ASTNode, ASTNode> pair = parseConditionalCommentBoundaries(host);
   if (pair == null) {
     return;
   }
   final TextRange textRange = host.getTextRange();
   final int startOffset = textRange.getStartOffset();
   Language language = host.getParent().getLanguage();
   ASTNode conditionalStart = pair.first;
   ASTNode conditionalEnd = pair.second;
   TextRange range =
       new TextRange(
           conditionalStart.getTextRange().getEndOffset() - startOffset,
           conditionalEnd.getStartOffset() - startOffset);
   registrar
       .startInjecting(language)
       .addPlace(null, null, (PsiLanguageInjectionHost) host, range)
       .doneInjecting();
 }
  protected int getOpenQuoteOffset() {
    PsiElement firstChild = getFirstChild();

    if (firstChild instanceof PerlParsableStringWrapperlImpl) {
      PsiElement realString = firstChild.getFirstChild();
      assert realString instanceof PerlStringImplMixin;
      return ((PerlStringImplMixin) realString).getOpenQuoteOffset();
    }

    ASTNode currentNode = firstChild.getNode();

    while (currentNode != null) {
      if (PerlParserUtil.OPEN_QUOTES.contains(currentNode.getElementType()))
        return currentNode.getStartOffset();
      currentNode = currentNode.getTreeNext();
    }
    throw new RuntimeException(
        "Unable to find opening quote inside: "
            + getText()
            + " "
            + getContainingFile().getVirtualFile());
  }
 public int getTextOffset() {
   final ASTNode name = getNameNode();
   return name != null ? name.getStartOffset() : super.getTextOffset();
 }
  public static void replaceWhiteSpace(
      final String whiteSpace,
      final ASTNode leafElement,
      final IElementType whiteSpaceToken,
      @Nullable final TextRange textRange) {
    final CharTable charTable = SharedImplUtil.findCharTableByTree(leafElement);

    ASTNode treePrev = findPreviousWhiteSpace(leafElement, whiteSpaceToken);
    if (treePrev == null) {
      treePrev = getWsCandidate(leafElement);
    }

    if (treePrev != null
        && treePrev.getText().trim().isEmpty()
        && treePrev.getElementType() != whiteSpaceToken
        && treePrev.getTextLength() > 0
        && !whiteSpace.isEmpty()) {
      LeafElement whiteSpaceElement =
          Factory.createSingleLeafElement(
              treePrev.getElementType(),
              whiteSpace,
              charTable,
              SharedImplUtil.getManagerByTree(leafElement));

      ASTNode treeParent = treePrev.getTreeParent();
      treeParent.replaceChild(treePrev, whiteSpaceElement);
    } else {
      LeafElement whiteSpaceElement =
          Factory.createSingleLeafElement(
              whiteSpaceToken, whiteSpace, charTable, SharedImplUtil.getManagerByTree(leafElement));

      if (treePrev == null) {
        if (!whiteSpace.isEmpty()) {
          addWhiteSpace(leafElement, whiteSpaceElement);
        }
      } else {
        if (!(treePrev.getElementType() == whiteSpaceToken)) {
          if (!whiteSpace.isEmpty()) {
            addWhiteSpace(treePrev, whiteSpaceElement);
          }
        } else {
          if (treePrev.getElementType() == whiteSpaceToken) {
            final CompositeElement treeParent = (CompositeElement) treePrev.getTreeParent();
            if (!whiteSpace.isEmpty()) {
              //          LOG.assertTrue(textRange == null ||
              // treeParent.getTextRange().equals(textRange));
              treeParent.replaceChild(treePrev, whiteSpaceElement);
            } else {
              treeParent.removeChild(treePrev);
            }

            // There is a possible case that more than one PSI element is matched by the target text
            // range.
            // That is the case, for example, for Python's multi-line expression. It may looks like
            // below:
            //     import contextlib,\
            //       math, decimal
            // Here single range contains two blocks: '\' & '\n  '. So, we may want to replace that
            // range to another text, hence,
            // we replace last element located there with it ('\n  ') and want to remove any
            // remaining elements ('\').
            ASTNode removeCandidate = findPreviousWhiteSpace(whiteSpaceElement, whiteSpaceToken);
            while (textRange != null
                && removeCandidate != null
                && removeCandidate.getStartOffset() >= textRange.getStartOffset()) {
              treePrev = findPreviousWhiteSpace(removeCandidate, whiteSpaceToken);
              removeCandidate.getTreeParent().removeChild(removeCandidate);
              removeCandidate = treePrev;
            }
            // treeParent.subtreeChanged();
          }
        }
      }
    }
  }