don't add a newline when completing with smart enter shortcut (IDEA-126726)

This commit is contained in:
peter
2014-07-08 18:40:07 +02:00
parent 4029019812
commit e3fd6eb900
9 changed files with 106 additions and 42 deletions
@@ -47,7 +47,21 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.smartEnter.JavaSmartEnterProcessor");
private static final Fixer[] ourFixers;
private static final EnterProcessor[] ourEnterProcessors;
private static final EnterProcessor[] ourEnterProcessors = {
new CommentBreakerEnterProcessor(),
new AfterSemicolonEnterProcessor(),
new LeaveCodeBlockEnterProcessor(),
new PlainEnterProcessor()
};
private static final EnterProcessor[] ourAfterCompletionEnterProcessors = {
new AfterSemicolonEnterProcessor(),
new EnterProcessor() {
@Override
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
return PlainEnterProcessor.expandCodeBlock(editor, psiElement);
}
}
};
static {
final List<Fixer> fixers = new ArrayList<Fixer>();
@@ -78,15 +92,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
fixers.add(new MissingArrayInitializerBraceFixer());
fixers.add(new MissingArrayConstructorBracketFixer());
fixers.add(new EnumFieldFixer());
//ourFixers.add(new CompletionFixer());
ourFixers = fixers.toArray(new Fixer[fixers.size()]);
List<EnterProcessor> processors = new ArrayList<EnterProcessor>();
processors.add(new CommentBreakerEnterProcessor());
processors.add(new AfterSemicolonEnterProcessor());
processors.add(new LeaveCodeBlockEnterProcessor());
processors.add(new PlainEnterProcessor());
ourEnterProcessors = processors.toArray(new EnterProcessor[processors.size()]);
}
private int myFirstErrorOffset = Integer.MAX_VALUE;
@@ -102,13 +108,22 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
public boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.complete.statement");
return invokeProcessor(editor, psiFile, false);
}
@Override
public boolean processAfterCompletion(@NotNull Editor editor, @NotNull PsiFile psiFile) {
return invokeProcessor(editor, psiFile, true);
}
private boolean invokeProcessor(Editor editor, PsiFile psiFile, boolean afterCompletion) {
final Document document = editor.getDocument();
final String textForRollback = document.getText();
final CharSequence textForRollback = document.getImmutableCharSequence();
try {
editor.putUserData(SMART_ENTER_TIMESTAMP, editor.getDocument().getModificationStamp());
myFirstErrorOffset = Integer.MAX_VALUE;
mySkipEnter = false;
process(project, editor, psiFile, 0);
process(editor, psiFile, 0, afterCompletion);
}
catch (TooManyAttemptsException e) {
document.replaceString(0, document.getTextLength(), textForRollback);
@@ -118,8 +133,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
return true;
}
private void process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file, final int attempt) throws TooManyAttemptsException {
private void process(@NotNull final Editor editor, @NotNull final PsiFile file, final int attempt, boolean afterCompletion) throws TooManyAttemptsException {
if (attempt > MAX_ATTEMPTS) throw new TooManyAttemptsException();
try {
@@ -148,18 +162,18 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
for (PsiElement psiElement : queue) {
for (Fixer fixer : ourFixers) {
fixer.apply(editor, this, psiElement);
if (LookupManager.getInstance(project).getActiveLookup() != null) {
if (LookupManager.getInstance(file.getProject()).getActiveLookup() != null) {
return;
}
if (isUncommited(project) || !psiElement.isValid()) {
if (isUncommited(file.getProject()) || !psiElement.isValid()) {
moveCaretInsideBracesIfAny(editor, file);
process(project, editor, file, attempt + 1);
process(editor, file, attempt + 1, afterCompletion);
return;
}
}
}
doEnter(atCaret, editor);
doEnter(atCaret, editor, afterCompletion);
}
catch (IncorrectOperationException e) {
LOG.error(e);
@@ -187,7 +201,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
}
private void doEnter(PsiElement atCaret, Editor editor) throws IncorrectOperationException {
private void doEnter(PsiElement atCaret, Editor editor, boolean afterCompletion) throws IncorrectOperationException {
final PsiFile psiFile = atCaret.getContainingFile();
final RangeMarker rangeMarker = createRangeMarker(atCaret);
@@ -205,7 +219,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
}
atCaret = CodeInsightUtil.findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(), atCaret.getClass());
for (EnterProcessor processor : ourEnterProcessors) {
for (EnterProcessor processor : afterCompletion ? ourAfterCompletionEnterProcessors : ourEnterProcessors) {
if(atCaret == null){
// Can't restore element at caret after enter processor execution!
break;
@@ -214,7 +228,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
if (processor.doEnter(editor, atCaret, isModified(editor))) return;
}
if (!isModified(editor)) {
if (!isModified(editor) && !afterCompletion) {
plainEnter(editor);
} else {
if (myFirstErrorOffset == Integer.MAX_VALUE) {
@@ -42,29 +42,37 @@ import org.jetbrains.annotations.Nullable;
public class PlainEnterProcessor implements EnterProcessor {
@Override
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
if (expandCodeBlock(editor, psiElement)) return true;
getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE).execute(editor, ((EditorEx)editor).getDataContext());
return true;
}
static boolean expandCodeBlock(Editor editor, PsiElement psiElement) {
PsiCodeBlock block = getControlStatementBlock(editor.getCaretModel().getOffset(), psiElement);
if (processExistingBlankLine(editor, block, psiElement)) {
return true;
}
EditorActionHandler enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE);
if (block != null) {
PsiElement firstElement = block.getFirstBodyElement();
if (firstElement == null) {
firstElement = block.getRBrace();
// Plain enter processor inserts enter after the end of line, hence, we don't want to use it here because the line ends with
// the empty braces block. So, we get the following in case of default handler usage:
// Before:
// if (condition[caret]) {}
// After:
// if (condition) {}
// [caret]
enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_ENTER);
}
editor.getCaretModel().moveToOffset(firstElement != null ?
firstElement.getTextRange().getStartOffset() :
block.getTextRange().getEndOffset());
if (block == null) {
return false;
}
EditorActionHandler enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE);
PsiElement firstElement = block.getFirstBodyElement();
if (firstElement == null) {
firstElement = block.getRBrace();
// Plain enter processor inserts enter after the end of line, hence, we don't want to use it here because the line ends with
// the empty braces block. So, we get the following in case of default handler usage:
// Before:
// if (condition[caret]) {}
// After:
// if (condition) {}
// [caret]
enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_ENTER);
}
editor.getCaretModel().moveToOffset(firstElement != null ?
firstElement.getTextRange().getStartOffset() :
block.getTextRange().getEndOffset());
enterHandler.execute(editor, ((EditorEx)editor).getDataContext());
return true;
}
@@ -0,0 +1,9 @@
class Tester {
private void build(EntityBuilder builder) {
}
public void test1(int abc, int abd) {
System.out.println(a<caret>);
}
}
@@ -0,0 +1,9 @@
class Tester {
private void build(EntityBuilder builder) {
}
public void test1(int abc, int abd) {
System.out.println(abc);<caret>
}
}
@@ -0,0 +1,9 @@
class Tester {
private void build(EntityBuilder builder) {
}
public void test1(int abc, int abd) {
if(a<caret>)
}
}
@@ -0,0 +1,11 @@
class Tester {
private void build(EntityBuilder builder) {
}
public void test1(int abc, int abd) {
if (abc) {
<caret>
}
}
}
@@ -920,6 +920,9 @@ public class ListUtils {
}
public void testSmartEnterWrapsConstructorCall() throws Throwable { doTest(Lookup.COMPLETE_STATEMENT_SELECT_CHAR as String) }
public void testSmartEnterNoNewLine() { doTest(Lookup.COMPLETE_STATEMENT_SELECT_CHAR as String) }
public void testSmartEnterWithNewLine() { doTest(Lookup.COMPLETE_STATEMENT_SELECT_CHAR as String) }
public void testTabReplacesMethodNameWithLocalVariableName() throws Throwable { doTest('\t'); }
public void testMethodParameterAnnotationClass() throws Throwable { doTest(); }
public void testPrimitiveCastOverwrite() throws Throwable { doTest '\t' }
@@ -36,6 +36,10 @@ import org.jetbrains.annotations.Nullable;
public abstract class SmartEnterProcessor {
public abstract boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile);
public boolean processAfterCompletion(@NotNull final Editor editor, @NotNull final PsiFile psiFile) {
return process(psiFile.getProject(), editor, psiFile);
}
protected void reformat(PsiElement atCaret) throws IncorrectOperationException {
final TextRange range = atCaret.getTextRange();
final PsiFile file = atCaret.getContainingFile();
@@ -772,11 +772,8 @@ public class CodeCompletionHandlerBase {
if (context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) {
final Language language = PsiUtilBase.getLanguageInEditor(editor, project);
if (language != null) {
final List<SmartEnterProcessor> processors = SmartEnterProcessors.INSTANCE.forKey(language);
if (processors.size() > 0) {
for (SmartEnterProcessor processor : processors) {
processor.process(project, editor, indicator.getParameters().getOriginalFile());
}
for (SmartEnterProcessor processor : SmartEnterProcessors.INSTANCE.forKey(language)) {
if (processor.processAfterCompletion(editor, indicator.getParameters().getOriginalFile())) break;
}
}
}