mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
multi-caret typing fixes for Java files
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 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.
|
||||
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.completion.JavaClassReferenceCompletionContributor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
@@ -132,7 +131,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
if (PsiTreeUtil.getParentOfType(leaf, PsiCodeBlock.class, false, PsiMember.class) != null) {
|
||||
EditorModificationUtil.insertStringAtCaret(editor, "{", false, true);
|
||||
EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, "{");
|
||||
TypedHandler.indentOpenedBrace(project, editor);
|
||||
return Result.STOP;
|
||||
}
|
||||
@@ -170,8 +169,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
char charAt = editor.getDocument().getCharsSequence().charAt(offset);
|
||||
if (charAt != ';') return false;
|
||||
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
EditorModificationUtil.moveAllCaretsRelatively(editor, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -211,8 +209,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
}
|
||||
|
||||
if (balance == 0) {
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
EditorModificationUtil.moveAllCaretsRelatively(editor, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -251,7 +248,12 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
}
|
||||
|
||||
if (balance == 1) {
|
||||
editor.getDocument().insertString(offset, ">");
|
||||
if (editor.getCaretModel().supportsMultipleCarets()) {
|
||||
EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, ">", 0);
|
||||
}
|
||||
else {
|
||||
editor.getDocument().insertString(offset, ">");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
if (true)
|
||||
{<caret>
|
||||
if (true)
|
||||
{<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
if (true)
|
||||
<caret>
|
||||
if (true)
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
if (true) {
|
||||
System.out.println();
|
||||
}<caret>
|
||||
if (true) {
|
||||
System.out.println();
|
||||
}<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
if (true) {
|
||||
System.out.println();
|
||||
<caret>
|
||||
if (true) {
|
||||
System.out.println();
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
if (true) {
|
||||
List<<caret>>
|
||||
}
|
||||
if (true) {
|
||||
List<<caret>>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
if (true) {
|
||||
List<caret>
|
||||
}
|
||||
if (true) {
|
||||
List<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.out.println("<caret>");
|
||||
System.out.println("<caret>");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.out.println(<caret>);
|
||||
System.out.println(<caret>);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.exit(<caret>)
|
||||
System.exit(<caret>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.exit<caret>
|
||||
System.exit<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
java.util.List<String> l1 = new java.util.ArrayList<><caret>();
|
||||
java.util.List<String> l2 = new java.util.ArrayList<><caret>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
java.util.List<String> l1 = new java.util.ArrayList<<caret>>();
|
||||
java.util.List<String> l2 = new java.util.ArrayList<<caret>>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.out.println(""<caret>);
|
||||
System.out.println(""<caret>);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.out.println("<caret>");
|
||||
System.out.println("<caret>");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.exit()<caret>
|
||||
System.exit()<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.exit(<caret>)
|
||||
System.exit(<caret>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.out.println();<caret>
|
||||
System.out.println();<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
void m() {
|
||||
System.out.println()<caret>;
|
||||
System.out.println()<caret>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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;
|
||||
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class JavaTypingTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
public void testMulticaretIndentLBrace() {
|
||||
doTest('{');
|
||||
}
|
||||
|
||||
public void testMulticaretIndentRBrace() {
|
||||
doTest('}');
|
||||
}
|
||||
|
||||
public void testMulticaretSkipSemicolon() {
|
||||
doTest(';');
|
||||
}
|
||||
|
||||
public void testMulticaretSkipGt() {
|
||||
doTest('>');
|
||||
}
|
||||
|
||||
public void testMulticaretInsertGt() {
|
||||
doTest('<');
|
||||
}
|
||||
|
||||
public void testMulticaretSkipRParen() {
|
||||
doTest(')');
|
||||
}
|
||||
|
||||
public void testMulticaretInsertRParen() {
|
||||
doTest('(');
|
||||
}
|
||||
|
||||
public void testMulticaretSkipQuote() {
|
||||
doTest('"');
|
||||
}
|
||||
|
||||
public void testMulticaretInsertQuote() {
|
||||
doTest('"');
|
||||
}
|
||||
|
||||
private void doTest(char c) {
|
||||
myFixture.configureByFile(getTestName(true) + "_before.java");
|
||||
myFixture.type(c);
|
||||
myFixture.checkResultByFile(getTestName(true) + "_after.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/java/java-tests/testData/codeInsight/typing";
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
}
|
||||
}
|
||||
|
||||
if (!editor.getSelectionModel().hasBlockSelection() && editor.getCaretModel().getCaretCount() == 1) {
|
||||
if (!editor.getSelectionModel().hasBlockSelection()) {
|
||||
if (')' == charTyped || ']' == charTyped || '}' == charTyped) {
|
||||
if (FileTypes.PLAIN_TEXT != fileType) {
|
||||
if (handleRParen(editor, fileType, charTyped)) return;
|
||||
@@ -210,7 +210,7 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
|
||||
if (('(' == charTyped || '[' == charTyped || '{' == charTyped) &&
|
||||
CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
|
||||
!editor.getSelectionModel().hasBlockSelection() && editor.getCaretModel().getCaretCount() == 1 && fileType != FileTypes.PLAIN_TEXT) {
|
||||
!editor.getSelectionModel().hasBlockSelection() && fileType != FileTypes.PLAIN_TEXT) {
|
||||
handleAfterLParen(editor, fileType, charTyped);
|
||||
}
|
||||
else if ('}' == charTyped) {
|
||||
@@ -361,7 +361,12 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
else {
|
||||
throw new AssertionError("Unknown char "+lparenChar);
|
||||
}
|
||||
editor.getDocument().insertString(offset, text);
|
||||
if (editor.getCaretModel().supportsMultipleCarets()) {
|
||||
EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, text, 0);
|
||||
}
|
||||
else {
|
||||
editor.getDocument().insertString(offset, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,8 +422,7 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
|
||||
if (!matched) return false;
|
||||
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
EditorModificationUtil.moveAllCaretsRelatively(editor, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -436,8 +440,7 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
|
||||
if (offset < length && chars.charAt(offset) == quote){
|
||||
if (isClosingQuote(editor, quoteHandler, offset)){
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
EditorModificationUtil.moveAllCaretsRelatively(editor, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -456,7 +459,9 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
}
|
||||
}
|
||||
|
||||
myOriginalHandler.execute(editor, quote, dataContext);
|
||||
if (myOriginalHandler != null) {
|
||||
myOriginalHandler.execute(editor, quote, dataContext);
|
||||
}
|
||||
offset = editor.getCaretModel().getOffset();
|
||||
|
||||
if (quoteHandler instanceof MultiCharQuoteHandler) {
|
||||
@@ -464,7 +469,12 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
if (closingQuote != null && hasNonClosedLiterals(editor, quoteHandler, offset - 1)) {
|
||||
if (offset == document.getTextLength() ||
|
||||
!Character.isUnicodeIdentifierPart(document.getCharsSequence().charAt(offset))) { //any better heuristic or an API?
|
||||
document.insertString(offset, closingQuote);
|
||||
if (editor.getCaretModel().supportsMultipleCarets()) {
|
||||
EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, closingQuote.toString(), 0);
|
||||
}
|
||||
else {
|
||||
document.insertString(offset, closingQuote);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -473,7 +483,12 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
if (isOpeningQuote(editor, quoteHandler, offset - 1) && hasNonClosedLiterals(editor, quoteHandler, offset - 1)) {
|
||||
if (offset == document.getTextLength() ||
|
||||
!Character.isUnicodeIdentifierPart(document.getCharsSequence().charAt(offset))) { //any better heuristic or an API?
|
||||
document.insertString(offset, String.valueOf(quote));
|
||||
if (editor.getCaretModel().supportsMultipleCarets()) {
|
||||
EditorModificationUtil.typeInStringAtCaretHonorMultipleCarets(editor, String.valueOf(quote), 0);
|
||||
}
|
||||
else {
|
||||
document.insertString(offset, String.valueOf(quote));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,67 +573,72 @@ public class TypedHandler extends TypedActionHandlerBase {
|
||||
}
|
||||
|
||||
private static void indentBrace(@NotNull final Project project, @NotNull final Editor editor, final char braceChar) {
|
||||
final int offset = editor.getCaretModel().getOffset() - 1;
|
||||
final Document document = editor.getDocument();
|
||||
CharSequence chars = document.getCharsSequence();
|
||||
if (offset < 0 || chars.charAt(offset) != braceChar) return;
|
||||
editor.getCaretModel().runForEachCaret(new CaretAction() {
|
||||
@Override
|
||||
public void perform(Caret caret) {
|
||||
final int offset = editor.getCaretModel().getOffset() - 1;
|
||||
final Document document = editor.getDocument();
|
||||
CharSequence chars = document.getCharsSequence();
|
||||
if (offset < 0 || chars.charAt(offset) != braceChar) return;
|
||||
|
||||
int spaceStart = CharArrayUtil.shiftBackward(chars, offset - 1, " \t");
|
||||
if (spaceStart < 0 || chars.charAt(spaceStart) == '\n' || chars.charAt(spaceStart) == '\r'){
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
documentManager.commitDocument(document);
|
||||
int spaceStart = CharArrayUtil.shiftBackward(chars, offset - 1, " \t");
|
||||
if (spaceStart < 0 || chars.charAt(spaceStart) == '\n' || chars.charAt(spaceStart) == '\r'){
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
documentManager.commitDocument(document);
|
||||
|
||||
final PsiFile file = documentManager.getPsiFile(document);
|
||||
if (file == null || !file.isWritable()) return;
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element == null) return;
|
||||
final PsiFile file = documentManager.getPsiFile(document);
|
||||
if (file == null || !file.isWritable()) return;
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element == null) return;
|
||||
|
||||
EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter();
|
||||
HighlighterIterator iterator = highlighter.createIterator(offset);
|
||||
EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter();
|
||||
HighlighterIterator iterator = highlighter.createIterator(offset);
|
||||
|
||||
final FileType fileType = file.getFileType();
|
||||
BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator);
|
||||
boolean rBraceToken = braceMatcher.isRBraceToken(iterator, chars, fileType);
|
||||
final boolean isBrace = braceMatcher.isLBraceToken(iterator, chars, fileType) || rBraceToken;
|
||||
int lBraceOffset = -1;
|
||||
final FileType fileType = file.getFileType();
|
||||
BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator);
|
||||
boolean rBraceToken = braceMatcher.isRBraceToken(iterator, chars, fileType);
|
||||
final boolean isBrace = braceMatcher.isLBraceToken(iterator, chars, fileType) || rBraceToken;
|
||||
int lBraceOffset = -1;
|
||||
|
||||
if (CodeInsightSettings.getInstance().REFORMAT_BLOCK_ON_RBRACE &&
|
||||
rBraceToken &&
|
||||
braceMatcher.isStructuralBrace(iterator, chars, fileType) && offset > 0) {
|
||||
lBraceOffset = BraceMatchingUtil.findLeftLParen(
|
||||
highlighter.createIterator(offset - 1),
|
||||
braceMatcher.getOppositeBraceTokenType(iterator.getTokenType()),
|
||||
editor.getDocument().getCharsSequence(),
|
||||
fileType
|
||||
);
|
||||
}
|
||||
if (element.getNode() != null && isBrace) {
|
||||
final int finalLBraceOffset = lBraceOffset;
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run(){
|
||||
try{
|
||||
int newOffset;
|
||||
if (finalLBraceOffset != -1) {
|
||||
RangeMarker marker = document.createRangeMarker(offset, offset + 1);
|
||||
CodeStyleManager.getInstance(project).reformatRange(file, finalLBraceOffset, offset, true);
|
||||
newOffset = marker.getStartOffset();
|
||||
marker.dispose();
|
||||
} else {
|
||||
newOffset = CodeStyleManager.getInstance(project).adjustLineIndent(file, offset);
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(newOffset + 1);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
editor.getSelectionModel().removeSelection();
|
||||
}
|
||||
catch(IncorrectOperationException e){
|
||||
LOG.error(e);
|
||||
}
|
||||
if (CodeInsightSettings.getInstance().REFORMAT_BLOCK_ON_RBRACE &&
|
||||
rBraceToken &&
|
||||
braceMatcher.isStructuralBrace(iterator, chars, fileType) && offset > 0) {
|
||||
lBraceOffset = BraceMatchingUtil.findLeftLParen(
|
||||
highlighter.createIterator(offset - 1),
|
||||
braceMatcher.getOppositeBraceTokenType(iterator.getTokenType()),
|
||||
editor.getDocument().getCharsSequence(),
|
||||
fileType
|
||||
);
|
||||
}
|
||||
});
|
||||
if (element.getNode() != null && isBrace) {
|
||||
final int finalLBraceOffset = lBraceOffset;
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run(){
|
||||
try{
|
||||
int newOffset;
|
||||
if (finalLBraceOffset != -1) {
|
||||
RangeMarker marker = document.createRangeMarker(offset, offset + 1);
|
||||
CodeStyleManager.getInstance(project).reformatRange(file, finalLBraceOffset, offset, true);
|
||||
newOffset = marker.getStartOffset();
|
||||
marker.dispose();
|
||||
} else {
|
||||
newOffset = CodeStyleManager.getInstance(project).adjustLineIndent(file, offset);
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(newOffset + 1);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
editor.getSelectionModel().removeSelection();
|
||||
}
|
||||
catch(IncorrectOperationException e){
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -415,6 +415,14 @@ public class EditorModificationUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void typeInStringAtCaretHonorMultipleCarets(final Editor editor, @NotNull final String str) {
|
||||
typeInStringAtCaretHonorMultipleCarets(editor, str, true, str.length());
|
||||
}
|
||||
|
||||
public static void typeInStringAtCaretHonorMultipleCarets(final Editor editor, @NotNull final String str, final int caretShift) {
|
||||
typeInStringAtCaretHonorMultipleCarets(editor, str, true, caretShift);
|
||||
}
|
||||
|
||||
public static void typeInStringAtCaretHonorMultipleCarets(final Editor editor, @NotNull final String str, final boolean toProcessOverwriteMode) {
|
||||
typeInStringAtCaretHonorMultipleCarets(editor, str, toProcessOverwriteMode, str.length());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user