/** * 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); }
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; }