update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / editorActions / JavaTypedHandler.java
blob052b5f897625b211e4299d6168958eba0298d7af
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() != null && 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 return Result.STOP;
108 return Result.CONTINUE;
111 public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) {
112 if (myJavaLTTyped) {
113 myJavaLTTyped = false;
114 handleAfterJavaLT(editor);
115 return Result.STOP;
117 return Result.CONTINUE;
120 @Nullable
121 private static FileType getOriginalFileType(final PsiFile file) {
122 final VirtualFile virtualFile = file.getVirtualFile();
123 return virtualFile != null ? virtualFile.getFileType() : null;
126 private static boolean handleSemicolon(Editor editor, FileType fileType) {
127 if (fileType != StdFileTypes.JAVA) return false;
128 int offset = editor.getCaretModel().getOffset();
129 if (offset == editor.getDocument().getTextLength()) return false;
131 char charAt = editor.getDocument().getCharsSequence().charAt(offset);
132 if (charAt != ';') return false;
134 editor.getCaretModel().moveToOffset(offset + 1);
135 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
136 return true;
139 //need custom handler, since brace matcher cannot be used
140 private static boolean handleJavaGT(final Editor editor) {
141 if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return false;
143 int offset = editor.getCaretModel().getOffset();
145 if (offset == editor.getDocument().getTextLength()) return false;
147 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
148 if (iterator.getTokenType() != JavaTokenType.GT) return false;
149 while (!iterator.atEnd() && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
150 iterator.advance();
153 if (iterator.atEnd()) return false;
154 if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.retreat();
156 int balance = 0;
157 while (!iterator.atEnd() && balance >= 0) {
158 final IElementType tokenType = iterator.getTokenType();
159 if (tokenType == JavaTokenType.LT) {
160 balance--;
162 else if (tokenType == JavaTokenType.GT) {
163 balance++;
165 else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
166 break;
169 iterator.retreat();
172 if (balance == 0) {
173 editor.getCaretModel().moveToOffset(offset + 1);
174 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
175 return true;
178 return false;
181 //need custom handler, since brace matcher cannot be used
182 private static void handleAfterJavaLT(final Editor editor) {
183 if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return;
185 int offset = editor.getCaretModel().getOffset();
186 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
187 while (iterator.getStart() > 0 && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
188 iterator.retreat();
191 if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.advance();
193 int balance = 0;
194 while (!iterator.atEnd() && balance >= 0) {
195 final IElementType tokenType = iterator.getTokenType();
196 if (tokenType == JavaTokenType.LT) {
197 balance++;
199 else if (tokenType == JavaTokenType.GT) {
200 balance--;
202 else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
203 break;
206 iterator.advance();
209 if (balance == 1) {
210 editor.getDocument().insertString(offset, ">");
214 private static void autoPopupJavadocLookup(final Project project, final Editor editor) {
215 if (ApplicationManager.getApplication().isUnitTestMode()) return;
217 final CodeInsightSettings settings = CodeInsightSettings.getInstance();
218 if (settings.AUTO_POPUP_JAVADOC_LOOKUP) {
219 final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);
220 if (file == null) return;
221 final Runnable request = new Runnable(){
222 public void run(){
223 PsiDocumentManager.getInstance(project).commitAllDocuments();
224 CommandProcessor.getInstance().executeCommand(project, new Runnable() {
225 public void run(){
226 new JavadocAutoLookupHandler().invoke(project, editor, file);
230 null, UndoConfirmationPolicy.DEFAULT, editor.getDocument()
234 AutoPopupController.getInstance(project).invokeAutoPopupRunnable(request, settings.JAVADOC_LOOKUP_DELAY);
238 public static boolean isAfterClassLikeIdentifierOrDot(final int offset, final Editor editor) {
239 HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
240 if (iterator.atEnd()) return false;
241 if (iterator.getStart() > 0) iterator.retreat();
242 final IElementType tokenType = iterator.getTokenType();
243 if (tokenType == JavaTokenType.DOT) return true;
244 if (tokenType == JavaTokenType.IDENTIFIER && iterator.getEnd() == offset) {
245 final CharSequence chars = editor.getDocument().getCharsSequence();
246 final char startChar = chars.charAt(iterator.getStart());
247 if (!Character.isUpperCase(startChar)) return false;
248 final CharSequence word = chars.subSequence(iterator.getStart(), iterator.getEnd());
249 if (word.length() == 1) return true;
250 for (int i = 1; i < word.length(); i++) {
251 if (Character.isLowerCase(word.charAt(i))) return true;
255 return false;
258 private static class MemberAutoLookupCondition implements Condition<Editor> {
259 public boolean value(final Editor editor) {
260 final Project project = editor.getProject();
261 if (project == null) return false;
262 PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
263 if (file == null) return false;
264 int offset = editor.getCaretModel().getOffset();
266 PsiElement lastElement = file.findElementAt(offset - 1);
267 if (lastElement == null) {
268 return false;
271 //do not show lookup when typing varargs ellipsis
272 final PsiElement prevSibling = lastElement.getPrevSibling();
273 if (prevSibling == null || ".".equals(prevSibling.getText())) return false;
274 PsiElement parent = prevSibling;
275 do {
276 parent = parent.getParent();
277 } while(parent instanceof PsiJavaCodeReferenceElement || parent instanceof PsiTypeElement);
278 if (parent instanceof PsiParameterList) return false;
280 if (!".".equals(lastElement.getText()) && !"#".equals(lastElement.getText())) {
281 return false;
283 else{
284 final PsiElement element = file.findElementAt(offset);
285 return element == null ||
286 !"#".equals(lastElement.getText()) ||
287 new SuperParentFilter(new ClassFilter(PsiDocComment.class)).isAcceptable(element, element.getParent());