IDEA-24645
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / editorActions / JavaTypedHandler.java
blobb0480784f5e396ea060290f9ae8a8f158cad2820
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInsight.editorActions;
18 import com.intellij.codeInsight.AutoPopupController;
19 import com.intellij.codeInsight.CodeInsightSettings;
20 import com.intellij.codeInsight.completion.JavadocAutoLookupHandler;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.command.CommandProcessor;
23 import com.intellij.openapi.command.UndoConfirmationPolicy;
24 import com.intellij.openapi.editor.Editor;
25 import com.intellij.openapi.editor.ScrollType;
26 import com.intellij.openapi.editor.EditorModificationUtil;
27 import com.intellij.openapi.editor.ex.EditorEx;
28 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
29 import com.intellij.openapi.fileTypes.FileType;
30 import com.intellij.openapi.fileTypes.StdFileTypes;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.util.Condition;
33 import com.intellij.openapi.vfs.VirtualFile;
34 import com.intellij.psi.*;
35 import com.intellij.psi.filters.ClassFilter;
36 import com.intellij.psi.filters.position.SuperParentFilter;
37 import com.intellij.psi.javadoc.PsiDocComment;
38 import com.intellij.psi.jsp.JspFile;
39 import com.intellij.psi.tree.IElementType;
40 import com.intellij.psi.util.PsiTreeUtil;
41 import com.intellij.psi.util.PsiUtil;
42 import com.intellij.psi.util.PsiUtilBase;
43 import org.jetbrains.annotations.Nullable;
45 /**
46 * @author yole
48 public class JavaTypedHandler extends TypedHandlerDelegate {
49 private boolean myJavaLTTyped;
51 public Result checkAutoPopup(final char charTyped, final Project project, final Editor editor, final PsiFile file) {
52 if (charTyped == '@' && file instanceof PsiJavaFile) {
53 autoPopupJavadocLookup(project, editor);
54 return Result.STOP;
56 if (charTyped == '#' || charTyped == '.') {
57 AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, new MemberAutoLookupCondition());
58 return Result.STOP;
61 return Result.CONTINUE;
64 public Result beforeCharTyped(final char c, final Project project, final Editor editor, final PsiFile file, final FileType fileType) {
65 final FileType originalFileType = getOriginalFileType(file);
67 int offsetBefore = editor.getCaretModel().getOffset();
69 //important to calculate before inserting charTyped
70 myJavaLTTyped = '<' == c &&
71 file instanceof PsiJavaFile &&
72 !(file instanceof JspFile) &&
73 CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
74 PsiUtil.isLanguageLevel5OrHigher(file) &&
75 isAfterClassLikeIdentifierOrDot(offsetBefore, editor);
77 if ('>' == c) {
78 if (file instanceof PsiJavaFile && !(file instanceof JspFile) &&
79 CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
80 PsiUtil.isLanguageLevel5OrHigher(file)) {
81 if (handleJavaGT(editor)) return Result.STOP;
85 if (c == ';') {
86 if (handleSemicolon(editor, fileType)) return Result.STOP;
88 if (originalFileType == StdFileTypes.JAVA && c == '{') {
89 int offset = editor.getCaretModel().getOffset();
90 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset - 1);
91 while (iterator.getTokenType() == TokenType.WHITE_SPACE) {
92 iterator.retreat();
94 if (iterator.getTokenType() == JavaTokenType.RBRACKET || iterator.getTokenType() == JavaTokenType.EQ) {
95 return Result.CONTINUE;
97 PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
98 final PsiElement leaf = file.findElementAt(offset);
99 if (PsiTreeUtil.getParentOfType(leaf, PsiArrayInitializerExpression.class, false, PsiCodeBlock.class, PsiMember.class) != null) {
100 return Result.CONTINUE;
102 if (PsiTreeUtil.getParentOfType(leaf, PsiCodeBlock.class, false, PsiMember.class) != null) {
103 EditorModificationUtil.insertStringAtCaret(editor, "{", false, true);
104 TypedHandler.indentOpenedBrace(project, editor);
105 return Result.STOP;
109 return Result.CONTINUE;
112 public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) {
113 if (myJavaLTTyped) {
114 myJavaLTTyped = false;
115 handleAfterJavaLT(editor);
116 return Result.STOP;
118 return Result.CONTINUE;
121 @Nullable
122 private static FileType getOriginalFileType(final PsiFile file) {
123 final VirtualFile virtualFile = file.getVirtualFile();
124 return virtualFile != null ? virtualFile.getFileType() : null;
127 private static boolean handleSemicolon(Editor editor, FileType fileType) {
128 if (fileType != StdFileTypes.JAVA) return false;
129 int offset = editor.getCaretModel().getOffset();
130 if (offset == editor.getDocument().getTextLength()) return false;
132 char charAt = editor.getDocument().getCharsSequence().charAt(offset);
133 if (charAt != ';') return false;
135 editor.getCaretModel().moveToOffset(offset + 1);
136 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
137 return true;
140 //need custom handler, since brace matcher cannot be used
141 private static boolean handleJavaGT(final Editor editor) {
142 if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return false;
144 int offset = editor.getCaretModel().getOffset();
146 if (offset == editor.getDocument().getTextLength()) return false;
148 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
149 if (iterator.getTokenType() != JavaTokenType.GT) return false;
150 while (!iterator.atEnd() && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
151 iterator.advance();
154 if (iterator.atEnd()) return false;
155 if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.retreat();
157 int balance = 0;
158 while (!iterator.atEnd() && balance >= 0) {
159 final IElementType tokenType = iterator.getTokenType();
160 if (tokenType == JavaTokenType.LT) {
161 balance--;
163 else if (tokenType == JavaTokenType.GT) {
164 balance++;
166 else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
167 break;
170 iterator.retreat();
173 if (balance == 0) {
174 editor.getCaretModel().moveToOffset(offset + 1);
175 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
176 return true;
179 return false;
182 //need custom handler, since brace matcher cannot be used
183 private static void handleAfterJavaLT(final Editor editor) {
184 if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return;
186 int offset = editor.getCaretModel().getOffset();
187 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
188 while (iterator.getStart() > 0 && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
189 iterator.retreat();
192 if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.advance();
194 int balance = 0;
195 while (!iterator.atEnd() && balance >= 0) {
196 final IElementType tokenType = iterator.getTokenType();
197 if (tokenType == JavaTokenType.LT) {
198 balance++;
200 else if (tokenType == JavaTokenType.GT) {
201 balance--;
203 else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
204 break;
207 iterator.advance();
210 if (balance == 1) {
211 editor.getDocument().insertString(offset, ">");
215 private static void autoPopupJavadocLookup(final Project project, final Editor editor) {
216 if (ApplicationManager.getApplication().isUnitTestMode()) return;
218 final CodeInsightSettings settings = CodeInsightSettings.getInstance();
219 if (settings.AUTO_POPUP_JAVADOC_LOOKUP) {
220 final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);
221 if (file == null) return;
222 final Runnable request = new Runnable(){
223 public void run(){
224 PsiDocumentManager.getInstance(project).commitAllDocuments();
225 CommandProcessor.getInstance().executeCommand(project, new Runnable() {
226 public void run(){
227 new JavadocAutoLookupHandler().invoke(project, editor, file);
231 null, UndoConfirmationPolicy.DEFAULT, editor.getDocument()
235 AutoPopupController.getInstance(project).invokeAutoPopupRunnable(request, settings.JAVADOC_LOOKUP_DELAY);
239 public static boolean isAfterClassLikeIdentifierOrDot(final int offset, final Editor editor) {
240 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
241 if (iterator.atEnd()) return false;
242 if (iterator.getStart() > 0) iterator.retreat();
243 final IElementType tokenType = iterator.getTokenType();
244 if (tokenType == JavaTokenType.DOT) return true;
245 if (tokenType == JavaTokenType.IDENTIFIER && iterator.getEnd() == offset) {
246 final CharSequence chars = editor.getDocument().getCharsSequence();
247 final char startChar = chars.charAt(iterator.getStart());
248 if (!Character.isUpperCase(startChar)) return false;
249 final CharSequence word = chars.subSequence(iterator.getStart(), iterator.getEnd());
250 if (word.length() == 1) return true;
251 for (int i = 1; i < word.length(); i++) {
252 if (Character.isLowerCase(word.charAt(i))) return true;
256 return false;
259 private static class MemberAutoLookupCondition implements Condition<Editor> {
260 public boolean value(final Editor editor) {
261 final Project project = editor.getProject();
262 if (project == null) return false;
263 PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
264 if (file == null) return false;
265 int offset = editor.getCaretModel().getOffset();
267 PsiElement lastElement = file.findElementAt(offset - 1);
268 if (lastElement == null) {
269 return false;
272 //do not show lookup when typing varargs ellipsis
273 final PsiElement prevSibling = lastElement.getPrevSibling();
274 if (prevSibling == null || ".".equals(prevSibling.getText())) return false;
275 PsiElement parent = prevSibling;
276 do {
277 parent = parent.getParent();
278 } while(parent instanceof PsiJavaCodeReferenceElement || parent instanceof PsiTypeElement);
279 if (parent instanceof PsiParameterList) return false;
281 if (!".".equals(lastElement.getText()) && !"#".equals(lastElement.getText())) {
282 return false;
284 else{
285 final PsiElement element = file.findElementAt(offset);
286 return element == null ||
287 !"#".equals(lastElement.getText()) ||
288 new SuperParentFilter(new ClassFilter(PsiDocComment.class)).isAcceptable(element, element.getParent());