mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
java-like pair <> handling in groovy
This commit is contained in:
+11
-7
@@ -22,6 +22,7 @@ import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
|
||||
public class JavaBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
@@ -43,30 +44,33 @@ public class JavaBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
char c1 = chars.charAt(offset);
|
||||
if (c == '<' && myToDeleteGt) {
|
||||
if (c1 != '>') return true;
|
||||
handleLTDeletion(editor, offset);
|
||||
handleLTDeletion(editor, offset, JavaTokenType.LT, JavaTokenType.GT, JavaTypedHandler.INVALID_INSIDE_REFERENCE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void handleLTDeletion(final Editor editor, final int offset) {
|
||||
public static void handleLTDeletion(final Editor editor,
|
||||
final int offset,
|
||||
final IElementType lt,
|
||||
final IElementType gt, final TokenSet invalidInsideReference) {
|
||||
HighlighterIterator iterator = ((EditorEx)editor).getHighlighter().createIterator(offset);
|
||||
while (iterator.getStart() > 0 && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
|
||||
while (iterator.getStart() > 0 && !invalidInsideReference.contains(iterator.getTokenType())) {
|
||||
iterator.retreat();
|
||||
}
|
||||
|
||||
if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.advance();
|
||||
if (invalidInsideReference.contains(iterator.getTokenType())) iterator.advance();
|
||||
|
||||
int balance = 0;
|
||||
while (!iterator.atEnd() && balance >= 0) {
|
||||
final IElementType tokenType = iterator.getTokenType();
|
||||
if (tokenType == JavaTokenType.LT) {
|
||||
if (tokenType == lt) {
|
||||
balance++;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.GT) {
|
||||
else if (tokenType == gt) {
|
||||
balance--;
|
||||
}
|
||||
else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
|
||||
else if (invalidInsideReference.contains(tokenType)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.intellij.psi.filters.position.SuperParentFilter;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.jsp.JspFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -42,6 +43,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @author yole
|
||||
*/
|
||||
public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
static final TokenSet INVALID_INSIDE_REFERENCE = TokenSet.create(JavaTokenType.SEMICOLON, JavaTokenType.LBRACE, JavaTokenType.RBRACE);
|
||||
private boolean myJavaLTTyped;
|
||||
|
||||
public Result checkAutoPopup(final char charTyped, final Project project, final Editor editor, final PsiFile file) {
|
||||
@@ -106,7 +108,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
if (file instanceof PsiJavaFile && !(file instanceof JspFile) &&
|
||||
CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
|
||||
PsiUtil.isLanguageLevel5OrHigher(file)) {
|
||||
if (handleJavaGT(editor)) return Result.STOP;
|
||||
if (handleJavaGT(editor, JavaTokenType.LT, JavaTokenType.GT, INVALID_INSIDE_REFERENCE)) return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +146,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) {
|
||||
if (myJavaLTTyped) {
|
||||
myJavaLTTyped = false;
|
||||
handleAfterJavaLT(editor);
|
||||
handleAfterJavaLT(editor, JavaTokenType.LT, JavaTokenType.GT, INVALID_INSIDE_REFERENCE);
|
||||
return Result.STOP;
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
@@ -170,7 +172,10 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
}
|
||||
|
||||
//need custom handler, since brace matcher cannot be used
|
||||
private static boolean handleJavaGT(final Editor editor) {
|
||||
public static boolean handleJavaGT(final Editor editor,
|
||||
final IElementType lt,
|
||||
final IElementType gt,
|
||||
final TokenSet invalidInsideReference) {
|
||||
if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return false;
|
||||
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
@@ -178,24 +183,23 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
if (offset == editor.getDocument().getTextLength()) return false;
|
||||
|
||||
HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
|
||||
if (iterator.getTokenType() != JavaTokenType.GT) return false;
|
||||
while (!iterator.atEnd() && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
|
||||
if (iterator.getTokenType() != gt) return false;
|
||||
while (!iterator.atEnd() && !invalidInsideReference.contains(iterator.getTokenType())) {
|
||||
iterator.advance();
|
||||
}
|
||||
|
||||
if (iterator.atEnd()) return false;
|
||||
if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.retreat();
|
||||
if (!iterator.atEnd() && invalidInsideReference.contains(iterator.getTokenType())) iterator.retreat();
|
||||
|
||||
int balance = 0;
|
||||
while (!iterator.atEnd() && balance >= 0) {
|
||||
final IElementType tokenType = iterator.getTokenType();
|
||||
if (tokenType == JavaTokenType.LT) {
|
||||
if (tokenType == lt) {
|
||||
balance--;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.GT) {
|
||||
else if (tokenType == gt) {
|
||||
balance++;
|
||||
}
|
||||
else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
|
||||
else if (invalidInsideReference.contains(tokenType)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -212,27 +216,30 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
}
|
||||
|
||||
//need custom handler, since brace matcher cannot be used
|
||||
private static void handleAfterJavaLT(final Editor editor) {
|
||||
public static void handleAfterJavaLT(final Editor editor,
|
||||
final IElementType lt,
|
||||
final IElementType gt,
|
||||
final TokenSet invalidInsideReference) {
|
||||
if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return;
|
||||
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
|
||||
while (iterator.getStart() > 0 && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) {
|
||||
while (iterator.getStart() > 0 && !invalidInsideReference.contains(iterator.getTokenType())) {
|
||||
iterator.retreat();
|
||||
}
|
||||
|
||||
if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.advance();
|
||||
if (invalidInsideReference.contains(iterator.getTokenType())) iterator.advance();
|
||||
|
||||
int balance = 0;
|
||||
while (!iterator.atEnd() && balance >= 0) {
|
||||
final IElementType tokenType = iterator.getTokenType();
|
||||
if (tokenType == JavaTokenType.LT) {
|
||||
if (tokenType == lt) {
|
||||
balance++;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.GT) {
|
||||
else if (tokenType == gt) {
|
||||
balance--;
|
||||
}
|
||||
else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) {
|
||||
else if (invalidInsideReference.contains(tokenType)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -262,7 +269,11 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
if (iterator.getStart() > 0) iterator.retreat();
|
||||
final IElementType tokenType = iterator.getTokenType();
|
||||
if (tokenType == JavaTokenType.DOT) return true;
|
||||
if (tokenType == JavaTokenType.IDENTIFIER && iterator.getEnd() == offset) {
|
||||
return isClassLikeIdentifier(offset, editor, iterator, JavaTokenType.IDENTIFIER);
|
||||
}
|
||||
|
||||
public static boolean isClassLikeIdentifier(int offset, Editor editor, HighlighterIterator iterator, final IElementType idType) {
|
||||
if (iterator.getTokenType() == idType && iterator.getEnd() == offset) {
|
||||
final CharSequence chars = editor.getDocument().getCharsSequence();
|
||||
final char startChar = chars.charAt(iterator.getStart());
|
||||
if (!Character.isUpperCase(startChar)) return false;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
|
||||
public class JavaTypedHandlerUtil {
|
||||
private JavaTypedHandlerUtil() {
|
||||
}
|
||||
|
||||
public static boolean isTokenInvalidInsideReference(final IElementType tokenType) {
|
||||
return tokenType == JavaTokenType.SEMICOLON ||
|
||||
tokenType == JavaTokenType.LBRACE ||
|
||||
tokenType == JavaTokenType.RBRACE;
|
||||
}
|
||||
}
|
||||
@@ -162,6 +162,9 @@
|
||||
<typedHandler implementation="org.jetbrains.plugins.groovy.lang.editor.actions.GStringTypedActionHandler"/>
|
||||
<backspaceHandlerDelegate implementation="org.jetbrains.plugins.groovy.lang.editor.actions.GStringBackspaceHandlerDelegate"/>
|
||||
|
||||
<typedHandler implementation="org.jetbrains.plugins.groovy.lang.editor.actions.GroovyTypedHandler"/>
|
||||
<backspaceHandlerDelegate implementation="org.jetbrains.plugins.groovy.lang.editor.actions.GroovyBackspaceHandler"/>
|
||||
|
||||
<liveTemplateContext implementation="org.jetbrains.plugins.groovy.template.GroovyTemplateContextType"/>
|
||||
<liveTemplateOptionalProcessor implementation="org.jetbrains.plugins.groovy.template.GroovyShortenFQNamesProcessor"/>
|
||||
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.editor.actions;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate;
|
||||
import com.intellij.codeInsight.editorActions.JavaBackspaceHandler;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class GroovyBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
private boolean myToDeleteGt;
|
||||
|
||||
public void beforeCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
int offset = editor.getCaretModel().getOffset() - 1;
|
||||
myToDeleteGt = c =='<' && file instanceof GroovyFile && GroovyTypedHandler.isAfterClassLikeIdentifier(offset, editor);
|
||||
}
|
||||
|
||||
public boolean charDeleted(final char c, final PsiFile file, final Editor editor) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
final CharSequence chars = editor.getDocument().getCharsSequence();
|
||||
if (editor.getDocument().getTextLength() <= offset) return false; //virtual space after end of file
|
||||
|
||||
char c1 = chars.charAt(offset);
|
||||
if (c == '<' && myToDeleteGt) {
|
||||
if (c1 != '>') return true;
|
||||
JavaBackspaceHandler.handleLTDeletion(editor, offset, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, GroovyTypedHandler.INVALID_INSIDE_REFERENCE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.editor.actions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.editorActions.JavaTypedHandler;
|
||||
import com.intellij.codeInsight.editorActions.TypedHandlerDelegate;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class GroovyTypedHandler extends TypedHandlerDelegate {
|
||||
static final TokenSet INVALID_INSIDE_REFERENCE = TokenSet.create(GroovyTokenTypes.mSEMI, GroovyTokenTypes.mLCURLY, GroovyTokenTypes.mRCURLY);
|
||||
private boolean myJavaLTTyped;
|
||||
|
||||
public Result beforeCharTyped(final char c, final Project project, final Editor editor, final PsiFile file, final FileType fileType) {
|
||||
int offsetBefore = editor.getCaretModel().getOffset();
|
||||
|
||||
//important to calculate before inserting charTyped
|
||||
myJavaLTTyped = '<' == c &&
|
||||
file instanceof GroovyFile &&
|
||||
CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
|
||||
isAfterClassLikeIdentifier(offsetBefore, editor);
|
||||
|
||||
if ('>' == c) {
|
||||
if (file instanceof GroovyFile && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) {
|
||||
if (JavaTypedHandler.handleJavaGT(editor, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, INVALID_INSIDE_REFERENCE)) return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) {
|
||||
if (myJavaLTTyped) {
|
||||
myJavaLTTyped = false;
|
||||
JavaTypedHandler.handleAfterJavaLT(editor, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, INVALID_INSIDE_REFERENCE);
|
||||
return Result.STOP;
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
public static boolean isAfterClassLikeIdentifier(final int offset, final Editor editor) {
|
||||
HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset);
|
||||
if (iterator.atEnd()) return false;
|
||||
if (iterator.getStart() > 0) iterator.retreat();
|
||||
return JavaTypedHandler.isClassLikeIdentifier(offset, editor, iterator, GroovyTokenTypes.mIDENT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -39,4 +39,8 @@ public class GroovyEditingTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testEnterInMultilineString() throws Throwable { doTest('\n'); }
|
||||
public void testEnterInStringInRefExpr() throws Throwable {doTest('\n');}
|
||||
public void testEnterInGStringInRefExpr() throws Throwable {doTest('\n');}
|
||||
public void testPairAngleBracketAfterClassName() throws Throwable {doTest('<');}
|
||||
public void testPairAngleBracketAfterClassNameOvertype() throws Throwable {doTest('>');}
|
||||
public void testPairAngleBracketAfterClassNameBackspace() throws Throwable {doTest('\b');}
|
||||
public void testNoPairLess() throws Throwable {doTest('<');}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
def foo = x<caret>
|
||||
@@ -0,0 +1 @@
|
||||
def foo = x<<caret>
|
||||
@@ -0,0 +1 @@
|
||||
Foo<caret>
|
||||
+1
@@ -0,0 +1 @@
|
||||
Foo<<caret>>
|
||||
+1
@@ -0,0 +1 @@
|
||||
Foo<caret>
|
||||
@@ -0,0 +1 @@
|
||||
Foo<x<caret>>
|
||||
+1
@@ -0,0 +1 @@
|
||||
Foo<x><caret>
|
||||
@@ -0,0 +1 @@
|
||||
Foo<<caret>>
|
||||
Reference in New Issue
Block a user