Example #1
0
 /**
  * Tries to calculate given line's indent column assuming that there might be a comment at the
  * given indent offset (see {@link #getCommentPrefix(IElementType)}).
  *
  * @param line target line
  * @param indentOffset start indent offset to use for the given line
  * @param lineEndOffset given line's end offset
  * @param fallbackColumn column to return if it's not possible to apply comment-specific indent
  *     calculation rules
  * @return given line's indent column to use
  */
 private int calcIndent(int line, int indentOffset, int lineEndOffset, int fallbackColumn) {
   final HighlighterIterator it = myEditor.getHighlighter().createIterator(indentOffset);
   IElementType tokenType = it.getTokenType();
   Language language = tokenType.getLanguage();
   TokenSet comments = myComments.get(language);
   if (comments == null) {
     ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
     if (definition != null) {
       comments = definition.getCommentTokens();
     }
     if (comments == null) {
       return fallbackColumn;
     } else {
       myComments.put(language, comments);
     }
   }
   if (comments.contains(tokenType) && indentOffset == it.getStart()) {
     String prefix = COMMENT_PREFIXES.get(tokenType);
     if (prefix == null) {
       prefix = getCommentPrefix(tokenType);
     }
     if (!NO_COMMENT_INFO_MARKER.equals(prefix)) {
       final int indentInsideCommentOffset =
           CharArrayUtil.shiftForward(
               myChars, indentOffset + prefix.length(), lineEndOffset, " \t");
       if (indentInsideCommentOffset < lineEndOffset) {
         int indent = myEditor.calcColumnNumber(indentInsideCommentOffset, line);
         indentAfterUncomment.put(line, indent - prefix.length());
         return indent;
       }
     }
   }
   return fallbackColumn;
 }
 @Override
 public void advance() {
   myCurrentStart = getCurrentStart();
   myCurrentEnd = getCurrentEnd();
   myCurrentAttributes = myIterator.getTextAttributes();
   myIterator.advance();
   skipBadCharacters();
 }
 public static List<IElementType> getAllTokens(EditorHighlighter highlighter) {
   List<IElementType> tokens = new ArrayList<IElementType>();
   HighlighterIterator iterator = highlighter.createIterator(0);
   while (!iterator.atEnd()) {
     tokens.add(iterator.getTokenType());
     iterator.advance();
   }
   return tokens;
 }
 private static List<BidiRun> createRuns(EditorImpl editor, char[] text, int startOffsetInEditor) {
   int textLength = text.length;
   if (editor.myDisableRtl) return Collections.singletonList(new BidiRun((byte) 0, 0, textLength));
   List<BidiRun> runs = new ArrayList<BidiRun>();
   if (startOffsetInEditor >= 0) {
     // running bidi algorithm separately for text fragments corresponding to different lexer
     // tokens
     int lastOffset = startOffsetInEditor;
     IElementType lastToken = null;
     HighlighterIterator iterator = editor.getHighlighter().createIterator(startOffsetInEditor);
     int endOffsetInEditor = startOffsetInEditor + textLength;
     while (!iterator.atEnd() && iterator.getStart() < endOffsetInEditor) {
       IElementType currentToken = iterator.getTokenType();
       if (distinctTokens(lastToken, currentToken)) {
         int tokenStart = Math.max(iterator.getStart(), startOffsetInEditor);
         addRuns(runs, text, lastOffset - startOffsetInEditor, tokenStart - startOffsetInEditor);
         lastToken = currentToken;
         lastOffset = tokenStart;
       }
       iterator.advance();
     }
     addRuns(
         runs, text, lastOffset - startOffsetInEditor, endOffsetInEditor - startOffsetInEditor);
   } else {
     addRuns(runs, text, 0, textLength);
   }
   return runs;
 }
 private static boolean isAtTokenNeeded(InsertionContext myContext) {
   HighlighterIterator iterator =
       ((EditorEx) myContext.getEditor())
           .getHighlighter()
           .createIterator(myContext.getStartOffset());
   LOG.assertTrue(iterator.getTokenType() == JavaTokenType.IDENTIFIER);
   iterator.retreat();
   if (iterator.getTokenType() == TokenType.WHITE_SPACE) iterator.retreat();
   return iterator.getTokenType() != JavaTokenType.AT
       && iterator.getTokenType() != JavaTokenType.DOT;
 }
 private void paintBorderEffect(
     Graphics2D g,
     ClipDetector clipDetector,
     EditorHighlighter highlighter,
     int clipStartOffset,
     int clipEndOffset) {
   HighlighterIterator it = highlighter.createIterator(clipStartOffset);
   while (!it.atEnd() && it.getStart() < clipEndOffset) {
     TextAttributes attributes = it.getTextAttributes();
     if (isBorder(attributes)) {
       paintBorderEffect(g, clipDetector, it.getStart(), it.getEnd(), attributes);
     }
     it.advance();
   }
 }
  /**
   * Calculates number of unmatched left braces before the given offset.
   *
   * @param editor target editor
   * @param offset target offset
   * @param fileType target file type
   * @return number of unmatched braces before the given offset; negative value if it's not possible
   *     to perform the calculation or if there are no unmatched left braces before the given offset
   */
  protected static int getUnmatchedLBracesNumberBefore(
      Editor editor, int offset, FileType fileType) {
    if (offset == 0) {
      return -1;
    }
    CharSequence chars = editor.getDocument().getCharsSequence();
    if (chars.charAt(offset - 1) != '{') {
      return -1;
    }

    EditorHighlighter highlighter = ((EditorEx) editor).getHighlighter();
    HighlighterIterator iterator = highlighter.createIterator(offset - 1);
    BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator);

    if (!braceMatcher.isLBraceToken(iterator, chars, fileType)
        || !braceMatcher.isStructuralBrace(iterator, chars, fileType)) {
      return -1;
    }

    Language language = iterator.getTokenType().getLanguage();

    iterator = highlighter.createIterator(0);
    int lBracesBeforeOffset = 0;
    int lBracesAfterOffset = 0;
    int rBracesBeforeOffset = 0;
    int rBracesAfterOffset = 0;
    for (; !iterator.atEnd(); iterator.advance()) {
      IElementType tokenType = iterator.getTokenType();
      if (!tokenType.getLanguage().equals(language)
          || !braceMatcher.isStructuralBrace(iterator, chars, fileType)) {
        continue;
      }

      boolean beforeOffset = iterator.getStart() < offset;

      if (braceMatcher.isLBraceToken(iterator, chars, fileType)) {
        if (beforeOffset) {
          lBracesBeforeOffset++;
        } else {
          lBracesAfterOffset++;
        }
      } else if (braceMatcher.isRBraceToken(iterator, chars, fileType)) {
        if (beforeOffset) {
          rBracesBeforeOffset++;
        } else {
          rBracesAfterOffset++;
        }
      }
    }

    return lBracesBeforeOffset - rBracesBeforeOffset - (rBracesAfterOffset - lBracesAfterOffset);
  }
    @Override
    @NotNull
    public Map<TodoIndexEntry, Integer> map(@NotNull final FileContent inputData) {
      if (IndexPatternUtil.getIndexPatternCount() > 0) {
        final CharSequence chars = inputData.getContentAsText();
        final OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true);
        EditorHighlighter highlighter;

        final EditorHighlighter editorHighlighter = inputData.getUserData(EDITOR_HIGHLIGHTER);
        if (editorHighlighter != null
            && checkCanUseCachedEditorHighlighter(chars, editorHighlighter)) {
          highlighter = editorHighlighter;
        } else {
          highlighter = HighlighterFactory.createHighlighter(inputData.getProject(), myFile);
          highlighter.setText(chars);
        }

        final int documentLength = chars.length();
        BaseFilterLexer.TodoScanningState todoScanningState = null;
        final HighlighterIterator iterator = highlighter.createIterator(0);

        while (!iterator.atEnd()) {
          final IElementType token = iterator.getTokenType();

          if (myCommentTokens.contains(token) || CacheUtil.isInComments(token)) {
            int start = iterator.getStart();
            if (start >= documentLength) break;
            int end = iterator.getEnd();

            todoScanningState =
                BaseFilterLexer.advanceTodoItemsCount(
                    chars.subSequence(start, Math.min(end, documentLength)),
                    occurrenceConsumer,
                    todoScanningState);
            if (end > documentLength) break;
          }
          iterator.advance();
        }
        final Map<TodoIndexEntry, Integer> map = new HashMap<>();
        for (IndexPattern pattern : IndexPatternUtil.getIndexPatterns()) {
          final int count = occurrenceConsumer.getOccurrenceCount(pattern);
          if (count > 0) {
            map.put(
                new TodoIndexEntry(pattern.getPatternString(), pattern.isCaseSensitive()), count);
          }
        }
        return map;
      }
      return Collections.emptyMap();
    }
  protected boolean handleBackspace(
      Editor editor, Caret caret, DataContext dataContext, boolean toWordStart) {
    Project project = CommonDataKeys.PROJECT.getData(dataContext);
    if (project == null) return false;

    PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);

    if (file == null) return false;

    if (editor.getSelectionModel().hasSelection()) return false;

    int offset = editor.getCaretModel().getOffset() - 1;
    if (offset < 0) return false;
    CharSequence chars = editor.getDocument().getCharsSequence();
    char c = chars.charAt(offset);

    final Editor injectedEditor =
        TypedHandler.injectedEditorIfCharTypedIsSignificant(c, editor, file);
    final Editor originalEditor = editor;
    if (injectedEditor != editor) {
      int injectedOffset = injectedEditor.getCaretModel().getOffset();
      if (isOffsetInsideInjected(injectedEditor, injectedOffset)) {
        file = PsiDocumentManager.getInstance(project).getPsiFile(injectedEditor.getDocument());
        editor = injectedEditor;
        offset = injectedOffset - 1;
      }
    }

    final BackspaceHandlerDelegate[] delegates =
        Extensions.getExtensions(BackspaceHandlerDelegate.EP_NAME);
    if (!toWordStart) {
      for (BackspaceHandlerDelegate delegate : delegates) {
        delegate.beforeCharDeleted(c, file, editor);
      }
    }

    FileType fileType = file.getFileType();
    final QuoteHandler quoteHandler = TypedHandler.getQuoteHandler(file, editor);

    HighlighterIterator hiterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
    boolean wasClosingQuote =
        quoteHandler != null && quoteHandler.isClosingQuote(hiterator, offset);

    myOriginalHandler.execute(originalEditor, caret, dataContext);

    if (!toWordStart) {
      for (BackspaceHandlerDelegate delegate : delegates) {
        if (delegate.charDeleted(c, file, editor)) {
          return true;
        }
      }
    }

    if (offset >= editor.getDocument().getTextLength()) return true;

    chars = editor.getDocument().getCharsSequence();
    if ((c == '(' || c == '[' || c == '{')
        && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) {
      char c1 = chars.charAt(offset);
      if (c1 != getRightChar(c)) return true;

      HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
      BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator);
      if (!braceMatcher.isLBraceToken(iterator, chars, fileType)
          && !braceMatcher.isRBraceToken(iterator, chars, fileType)) {
        return true;
      }

      int rparenOffset =
          BraceMatchingUtil.findRightmostRParen(iterator, iterator.getTokenType(), chars, fileType);
      if (rparenOffset >= 0) {
        iterator = ((EditorEx) editor).getHighlighter().createIterator(rparenOffset);
        boolean matched = BraceMatchingUtil.matchBrace(chars, fileType, iterator, false);
        if (matched) return true;
      }

      editor.getDocument().deleteString(offset, offset + 1);
    } else if ((c == '"' || c == '\'' || c == '`')
        && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE) {
      char c1 = chars.charAt(offset);
      if (c1 != c) return true;
      if (wasClosingQuote) return true;

      HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
      if (quoteHandler == null || !quoteHandler.isOpeningQuote(iterator, offset)) return true;

      editor.getDocument().deleteString(offset, offset + 1);
    }

    return true;
  }
  public static boolean semicolonNeeded(final Editor editor, PsiFile file, final int startOffset) {
    final PsiJavaCodeReferenceElement ref =
        PsiTreeUtil.findElementOfClassAtOffset(
            file, startOffset, PsiJavaCodeReferenceElement.class, false);
    if (ref != null && !(ref instanceof PsiReferenceExpression)) {
      if (ref.getParent() instanceof PsiTypeElement) {
        return true;
      }
    }

    HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(startOffset);
    if (iterator.atEnd()) return false;

    if (iterator.getTokenType() == JavaTokenType.IDENTIFIER) {
      iterator.advance();
    }

    while (!iterator.atEnd()
        && ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(iterator.getTokenType())) {
      iterator.advance();
    }

    if (!iterator.atEnd()
        && (iterator.getTokenType() == JavaTokenType.LPARENTH
            || iterator.getTokenType() == JavaTokenType.COLON)) {
      return true;
    }

    while (!iterator.atEnd()
        && ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(iterator.getTokenType())) {
      iterator.advance();
    }

    if (iterator.atEnd() || iterator.getTokenType() != JavaTokenType.IDENTIFIER) return false;
    iterator.advance();

    while (!iterator.atEnd()
        && ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(iterator.getTokenType())) {
      iterator.advance();
    }
    if (iterator.atEnd()) return false;

    return iterator.getTokenType() == JavaTokenType.EQ
        || iterator.getTokenType() == JavaTokenType.LPARENTH;
  }
 private void skipBadCharacters() {
   while (!myIterator.atEnd() && myIterator.getTokenType() == TokenType.BAD_CHARACTER) {
     myIterator.advance();
   }
 }
 private int getCurrentEnd() {
   return Math.min(myIterator.getEnd(), myEndOffset);
 }
 private int getCurrentStart() {
   return Math.max(myIterator.getStart(), myStartOffset);
 }
 @Override
 public boolean atEnd() {
   return myIterator.atEnd() || getCurrentStart() >= myEndOffset;
 }
  protected String addTextRangeToHistory(
      TextRange textRange, final EditorEx consoleEditor, boolean preserveMarkup) {
    final Document history = myHistoryViewer.getDocument();
    final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
    if (myPrompt != null) {
      appendToHistoryDocument(history, myPrompt);
    }
    markupModel.addRangeHighlighter(
        history.getTextLength() - StringUtil.length(myPrompt),
        history.getTextLength(),
        HighlighterLayer.SYNTAX,
        ConsoleViewContentType.USER_INPUT.getAttributes(),
        HighlighterTargetArea.EXACT_RANGE);
    final int localStartOffset = textRange.getStartOffset();
    String text;
    EditorHighlighter highlighter;
    if (consoleEditor instanceof EditorWindow) {
      EditorWindow editorWindow = (EditorWindow) consoleEditor;
      EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
      PsiFile file = editorWindow.getInjectedFile();
      final VirtualFile virtualFile = file.getVirtualFile();
      assert virtualFile != null;
      highlighter = HighlighterFactory.createHighlighter(virtualFile, scheme, getProject());
      String fullText = InjectedLanguageUtil.getUnescapedText(file, null, null);
      highlighter.setText(fullText);
      text = textRange.substring(fullText);
    } else {
      text = consoleEditor.getDocument().getText(textRange);
      highlighter = consoleEditor.getHighlighter();
    }
    // offset can be changed after text trimming after insert due to buffer constraints
    appendToHistoryDocument(history, text);
    int offset = history.getTextLength() - text.length();

    final HighlighterIterator iterator = highlighter.createIterator(localStartOffset);
    final int localEndOffset = textRange.getEndOffset();
    while (!iterator.atEnd()) {
      final int itStart = iterator.getStart();
      if (itStart > localEndOffset) break;
      final int itEnd = iterator.getEnd();
      if (itEnd >= localStartOffset) {
        final int start = Math.max(itStart, localStartOffset) - localStartOffset + offset;
        final int end = Math.min(itEnd, localEndOffset) - localStartOffset + offset;
        markupModel.addRangeHighlighter(
            start,
            end,
            HighlighterLayer.SYNTAX,
            iterator.getTextAttributes(),
            HighlighterTargetArea.EXACT_RANGE);
      }
      iterator.advance();
    }
    if (preserveMarkup) {
      duplicateHighlighters(
          markupModel,
          DocumentMarkupModel.forDocument(consoleEditor.getDocument(), myProject, true),
          offset,
          textRange);
      duplicateHighlighters(markupModel, consoleEditor.getMarkupModel(), offset, textRange);
    }
    if (!text.endsWith("\n")) {
      appendToHistoryDocument(history, "\n");
    }
    return text;
  }
 public boolean isOpeningQuote(HighlighterIterator iterator, int offset) {
   return iterator.getTokenType() == XmlTokenType.XML_ATTRIBUTE_VALUE_START_DELIMITER;
 }