When typing assignment operator insert spaces automatically

This commit is contained in:
Yaroslav Lepenkin
2016-01-25 17:46:16 +03:00
parent 69c823ae78
commit 11872cd158
4 changed files with 223 additions and 0 deletions
@@ -0,0 +1,95 @@
/*
* Copyright 2000-2016 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.codeInsight.editorActions.AutoFormatTypedHandler;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
public class JavaReformatOnTypingTest extends LightPlatformCodeInsightFixtureTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
AutoFormatTypedHandler.setEnabledInTests(true);
}
@Override
public void tearDown() throws Exception {
AutoFormatTypedHandler.setEnabledInTests(false);
//noinspection SuperTearDownInFinally
super.tearDown();
}
private static void useSpacesAroundAssignmentOperator(boolean value, Project project, Language language) {
CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
CommonCodeStyleSettings common = settings.getCommonSettings(language);
common.SPACE_AROUND_ASSIGNMENT_OPERATORS = value;
}
public void test_AddSpacesAroundAssignmentOperator() throws Exception {
doTest("class T { int<caret> }", "=", "class T { int = <caret> }");
}
public void test_IgnoreSpacePressedAfterAssignmentOperator() {
useSpacesAroundAssignmentOperator(true, myFixture.getProject(), JavaLanguage.INSTANCE);
myFixture.configureByText(JavaFileType.INSTANCE, "class T { int<caret> }");
myFixture.type('=');
myFixture.type(' ');
myFixture.checkResult("class T { int = <caret> }");
}
public void test_DoNotInsertDoubleSpaceBeforeAssignment() {
doTest("class T { int <caret> }",
"=",
"class T { int = <caret> }");
}
public void test_DoNotInsertDoubleSpaceAnywhere() {
useSpacesAroundAssignmentOperator(true, myFixture.getProject(), JavaLanguage.INSTANCE);
myFixture.configureByText(JavaFileType.INSTANCE, "class T { int <caret> }");
myFixture.type('=');
myFixture.type(' ');
myFixture.checkResult("class T { int = <caret> }");
}
public void test_DoNotInsertSpaceIfNotAssignment() {
doTest("1 <caret>", "!=", "1 != <caret>");
doTest("c <caret>", ">=", "c >= <caret>");
doTest("c <caret>", "<=", "c <= <caret>");
doTest("c <caret>", "+=", "c += <caret>");
doTest("c <caret>", "-=", "c -= <caret>");
doTest("c <caret>", "*=", "c *= <caret>");
doTest("c <caret>", "/=", "c /= <caret>");
doTest("c <caret>", "&=", "c &= <caret>");
doTest("c <caret>", "%=", "c %= <caret>");
doTest("c <caret>", "^=", "c ^= <caret>");
doTest("c <caret>", "|=", "c |= <caret>");
}
private void doTest(String before, String typing, String after) {
useSpacesAroundAssignmentOperator(true, myFixture.getProject(), JavaLanguage.INSTANCE);
myFixture.configureByText(JavaFileType.INSTANCE, before);
myFixture.type(typing);
myFixture.checkResult(after);
}
}
@@ -0,0 +1,125 @@
/*
* Copyright 2000-2016 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.codeInsight.template.impl.editorActions.TypedActionHandlerBase;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.util.PsiUtilBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
public class AutoFormatTypedHandler extends TypedActionHandlerBase {
private static boolean myIsEnabledInTests = false;
private static char[] NO_SPACE_AFTER = { '+', '-', '*', '/', '%', '&', '^', '|', '<', '>', '!', '=', ' ' };
private boolean myIgnoreNextSpace = false;
private Document myLastModifiedDocument = null;
private int myLastOffset = -1;
public AutoFormatTypedHandler(@Nullable TypedActionHandler originalHandler) {
super(originalHandler);
}
private static boolean isEnabled() {
return Registry.is("editor.reformat.on.typing")
|| myIsEnabledInTests && ApplicationManager.getApplication().isUnitTestMode();
}
@TestOnly
public static void setEnabledInTests(boolean value) {
myIsEnabledInTests = value;
}
@Override
public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) {
if (isEnabled() && charTyped == ' ' && shouldIgnoreSpace(editor)) {
myIgnoreNextSpace = false;
return;
}
Document document = editor.getDocument();
boolean addSpaces = isEnabled() && charTyped == '=' && shouldInsertSpaces(editor, dataContext);
int caretOffset = editor.getCaretModel().getOffset();
CharSequence text = document.getImmutableCharSequence();
if (addSpaces && shouldInsertBefore(caretOffset, text)) {
EditorModificationUtil.insertStringAtCaret(editor, " ");
}
if (myOriginalHandler != null) myOriginalHandler.execute(editor, charTyped, dataContext);
if (addSpaces) {
EditorModificationUtil.insertStringAtCaret(editor, " ");
myIgnoreNextSpace = true;
myLastModifiedDocument = document;
myLastOffset = editor.getCaretModel().getOffset();
}
else {
myIgnoreNextSpace = false;
}
}
private static boolean shouldInsertBefore(int caretOffset, CharSequence text) {
if (caretOffset == 0) return false;
char charBefore = text.charAt(caretOffset - 1);
for (char c : NO_SPACE_AFTER) {
if (c == charBefore) {
return false;
}
}
return true;
}
private static boolean shouldInsertSpaces(Editor editor, DataContext dataContext) {
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
PsiFile file = project == null ? null : PsiUtilBase.getPsiFileInEditor(editor, project);
if (file != null) {
Language language = file.getLanguage();
CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
CommonCodeStyleSettings common = settings.getCommonSettings(language);
return common.SPACE_AROUND_ASSIGNMENT_OPERATORS;
}
return false;
}
private boolean shouldIgnoreSpace(@NotNull Editor editor) {
if (!myIgnoreNextSpace) {
return false;
}
Document document = editor.getDocument();
CaretModel caretModel = editor.getCaretModel();
return myLastModifiedDocument == document && myLastOffset == caretModel.getOffset();
}
}
@@ -727,6 +727,7 @@
order="before hide-hints"/>
<editorTypedHandler implementationClass="com.intellij.codeInsight.lookup.impl.LookupTypedHandler" id="lookup"/>
<editorTypedHandler implementationClass="com.intellij.codeInsight.editorActions.AutoFormatTypedHandler"/>
<typedHandler implementation="com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler" id="completionAutoPopup"
order="first"/>
<typedHandler implementation="com.intellij.codeInsight.editorActions.SelectionQuotingTypedHandler" id="selectionQuoting"/>
@@ -149,6 +149,8 @@ editor.navigation.history.stack.size.description=Stack size limit for back/forwa
editor.mac.smooth.scrolling=false
editor.mac.smooth.scrolling.description=Enable precise (with sub-line resolution) scrolling on Mac with mouse or trackpad
editor.reformat.on.typing=false
ide.showIndexRebuildMessage=false
ide.tabbedPane.bufferedPaint=true