mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-87318 Backspace should delete whitespace to chosen indent level, or be configurable
This commit is contained in:
@@ -76,10 +76,11 @@ public class CodeInsightSettings implements PersistentStateComponent<Element>, C
|
||||
|
||||
public boolean SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO = false;
|
||||
|
||||
@MagicConstant(intValues = {OFF, AUTOINDENT})
|
||||
@MagicConstant(intValues = {OFF, AUTOINDENT, INDENT})
|
||||
public int SMART_BACKSPACE = AUTOINDENT;
|
||||
public static final int OFF = 0;
|
||||
public static final int AUTOINDENT = 1;
|
||||
public static final int INDENT = 2;
|
||||
|
||||
public boolean SMART_INDENT_ON_ENTER = true;
|
||||
public boolean INSERT_BRACE_ON_ENTER = true;
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
|
||||
|
||||
abstract class AbstractIndentingBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
private final int myMode;
|
||||
private boolean myEnabled;
|
||||
|
||||
AbstractIndentingBackspaceHandler(int mode) {
|
||||
myMode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
myEnabled = false;
|
||||
if (!StringUtil.isWhiteSpace(c)) {
|
||||
return;
|
||||
}
|
||||
int mode = getBackspaceMode(file.getLanguage());
|
||||
if (mode != myMode) {
|
||||
return;
|
||||
}
|
||||
doBeforeCharDeleted(c, file, editor);
|
||||
myEnabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charDeleted(char c, PsiFile file, Editor editor) {
|
||||
if (!myEnabled) {
|
||||
return false;
|
||||
}
|
||||
return doCharDeleted(c, file, editor);
|
||||
}
|
||||
|
||||
protected abstract void doBeforeCharDeleted(char c, PsiFile file, Editor editor);
|
||||
|
||||
protected abstract boolean doCharDeleted(char c, PsiFile file, Editor editor);
|
||||
|
||||
private static int getBackspaceMode(Language language) {
|
||||
LanguageCodeStyleSettingsProvider codeStyleSettingsProvider = LanguageCodeStyleSettingsProvider.forLanguage(language);
|
||||
if (codeStyleSettingsProvider != null && codeStyleSettingsProvider.isIndentBasedLanguageSemantics()) {
|
||||
return CodeInsightSettings.INDENT;
|
||||
}
|
||||
else {
|
||||
return CodeInsightSettings.getInstance().SMART_BACKSPACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-2
@@ -23,6 +23,7 @@ import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
|
||||
@@ -36,6 +37,7 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
@@ -167,7 +169,7 @@ public class BackspaceHandler extends EditorWriteActionHandler {
|
||||
if (editor.getSelectionModel().hasSelection() || editor.getSelectionModel().hasBlockSelection()) return null;
|
||||
|
||||
final LogicalPosition caretPos = editor.getCaretModel().getLogicalPosition();
|
||||
if (caretPos.line == 0 || caretPos.column == 0) {
|
||||
if (caretPos.column == 0) {
|
||||
return null;
|
||||
}
|
||||
if (!isWhitespaceBeforeCaret(editor)) {
|
||||
@@ -175,13 +177,21 @@ public class BackspaceHandler extends EditorWriteActionHandler {
|
||||
}
|
||||
|
||||
// Decrease column down to indentation * n
|
||||
final int indent = CodeStyleSettingsManager.getSettings(file.getProject()).getIndentSize(file.getFileType());
|
||||
final int indent = CodeStyleSettingsManager.getSettings(file.getProject()).getIndentOptionsByFile(file).INDENT_SIZE;
|
||||
int column = (caretPos.column - 1) / indent * indent;
|
||||
if (column < 0) {
|
||||
column = 0;
|
||||
}
|
||||
return new LogicalPosition(caretPos.line, column);
|
||||
}
|
||||
|
||||
public static void deleteToTargetPosition(@NotNull Editor editor, @NotNull LogicalPosition pos) {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final int targetOffset = editor.logicalPositionToOffset(pos);
|
||||
editor.getSelectionModel().setSelection(targetOffset, offset);
|
||||
EditorModificationUtil.deleteSelectedText(editor);
|
||||
editor.getCaretModel().moveToLogicalPosition(pos);
|
||||
}
|
||||
|
||||
public static boolean isWhitespaceBeforeCaret(Editor editor) {
|
||||
final LogicalPosition caretPos = editor.getCaretModel().getLogicalPosition();
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.psi.PsiFile;
|
||||
|
||||
public class SimpleIndentingBackspaceHandler extends AbstractIndentingBackspaceHandler {
|
||||
private LogicalPosition myTargetPosition;
|
||||
|
||||
public SimpleIndentingBackspaceHandler() {
|
||||
super(CodeInsightSettings.INDENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBeforeCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
myTargetPosition = BackspaceHandler.getBackspaceUnindentPosition(file, editor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
if (myTargetPosition != null) {
|
||||
BackspaceHandler.deleteToTargetPosition(editor, myTargetPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+24
-36
@@ -17,7 +17,9 @@ package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeStyle.CodeStyleFacade;
|
||||
import com.intellij.formatting.*;
|
||||
import com.intellij.formatting.FormatterEx;
|
||||
import com.intellij.formatting.FormattingModel;
|
||||
import com.intellij.formatting.FormattingModelBuilder;
|
||||
import com.intellij.lang.LanguageFormatting;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
@@ -33,40 +35,30 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Makes Backspace action delete all whitespace till next valid indent position
|
||||
*/
|
||||
public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
private static final Logger LOG = Logger.getInstance(IndentingBackspaceHandler.class);
|
||||
public class SmartIndentingBackspaceHandler extends AbstractIndentingBackspaceHandler {
|
||||
private static final Logger LOG = Logger.getInstance(SmartIndentingBackspaceHandler.class);
|
||||
|
||||
private boolean isApplicable;
|
||||
private boolean caretWasAtLineStart;
|
||||
private String precalculatedSpacing;
|
||||
|
||||
public SmartIndentingBackspaceHandler() {
|
||||
super(CodeInsightSettings.AUTOINDENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
if (CodeInsightSettings.getInstance().SMART_BACKSPACE != CodeInsightSettings.AUTOINDENT || !StringUtil.isWhiteSpace(c)) {
|
||||
isApplicable = false;
|
||||
return;
|
||||
}
|
||||
LanguageCodeStyleSettingsProvider codeStyleSettingsProvider = LanguageCodeStyleSettingsProvider.forLanguage(file.getLanguage());
|
||||
if (codeStyleSettingsProvider != null && codeStyleSettingsProvider.isIndentBasedLanguageSemantics()) {
|
||||
isApplicable = false;
|
||||
return;
|
||||
}
|
||||
protected void doBeforeCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
Document document = editor.getDocument();
|
||||
CharSequence charSequence = document.getCharsSequence();
|
||||
CaretModel caretModel = editor.getCaretModel();
|
||||
int caretOffset = caretModel.getOffset();
|
||||
LogicalPosition pos = caretModel.getLogicalPosition();
|
||||
isApplicable = true;
|
||||
caretWasAtLineStart = pos.column == 0;
|
||||
precalculatedSpacing = null;
|
||||
if (caretWasAtLineStart && pos.line > 0 && caretOffset < charSequence.length() && !StringUtil.isWhiteSpace(charSequence.charAt(caretOffset))) {
|
||||
if (caretWasAtLineStart && pos.line > 0 && caretOffset < charSequence.length()
|
||||
&& !StringUtil.isWhiteSpace(charSequence.charAt(caretOffset))) {
|
||||
int prevLineEnd = document.getLineEndOffset(pos.line - 1);
|
||||
if (prevLineEnd > 0 && !StringUtil.isWhiteSpace(charSequence.charAt(prevLineEnd - 1))) {
|
||||
PsiDocumentManager.getInstance(file.getProject()).commitDocument(document);
|
||||
@@ -76,11 +68,7 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charDeleted(char c, PsiFile file, Editor editor) {
|
||||
if (!isApplicable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean doCharDeleted(char c, PsiFile file, Editor editor) {
|
||||
Project project = file.getProject();
|
||||
Document document = editor.getDocument();
|
||||
CaretModel caretModel = editor.getCaretModel();
|
||||
@@ -153,6 +141,17 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getSpacing(PsiFile file, int offset) {
|
||||
FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file);
|
||||
if (builder == null) {
|
||||
return "";
|
||||
}
|
||||
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(file.getProject());
|
||||
FormattingModel model = builder.createModel(file, settings);
|
||||
int spacing = FormatterEx.getInstance().getSpacingForBlockAtOffset(model, offset);
|
||||
return StringUtil.repeatSymbol(' ', spacing);
|
||||
}
|
||||
|
||||
private static int getTabSize(@NotNull CodeStyleFacade codeStyleFacade, @NotNull Document document) {
|
||||
VirtualFile file = FileDocumentManager.getInstance().getFile(document);
|
||||
FileType fileType = file == null ? null : file.getFileType();
|
||||
@@ -175,15 +174,4 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
private static String getSpacing(PsiFile file, int offset) {
|
||||
FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file);
|
||||
if (builder == null) {
|
||||
return "";
|
||||
}
|
||||
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(file.getProject());
|
||||
FormattingModel model = builder.createModel(file, settings);
|
||||
int spacing = FormatterEx.getInstance().getSpacingForBlockAtOffset(model, offset);
|
||||
return StringUtil.repeatSymbol(' ', spacing);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
|
||||
|
||||
public class SimpleIndentingBackspaceHandlerTest extends LightPlatformCodeInsightTestCase {
|
||||
public void testBasicUnindent() {
|
||||
doTest(" <caret>text",
|
||||
" <caret>text");
|
||||
}
|
||||
|
||||
public void testAtLineStart() {
|
||||
doTest("line1\n<caret>line2",
|
||||
"line1<caret>line2");
|
||||
}
|
||||
|
||||
private void doTest(String before, String after) {
|
||||
int savedMode = CodeInsightSettings.getInstance().SMART_BACKSPACE;
|
||||
try {
|
||||
CodeInsightSettings.getInstance().SMART_BACKSPACE = CodeInsightSettings.INDENT;
|
||||
configureFromFileText(getTestName(false) + ".txt", before);
|
||||
executeAction(IdeActions.ACTION_EDITOR_BACKSPACE);
|
||||
checkResultByText(after);
|
||||
}
|
||||
finally {
|
||||
CodeInsightSettings.getInstance().SMART_BACKSPACE = savedMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,7 +578,8 @@
|
||||
id="EnterBetweenBracesHandler"/>
|
||||
<enterHandlerDelegate implementation="com.intellij.codeInsight.editorActions.enter.EnterAfterJavadocTagHandler"/>
|
||||
|
||||
<backspaceHandlerDelegate implementation="com.intellij.codeInsight.editorActions.IndentingBackspaceHandler" />
|
||||
<backspaceHandlerDelegate implementation="com.intellij.codeInsight.editorActions.SimpleIndentingBackspaceHandler" />
|
||||
<backspaceHandlerDelegate implementation="com.intellij.codeInsight.editorActions.SmartIndentingBackspaceHandler" />
|
||||
|
||||
<codeInsight.linkHandler prefix="#inspection/" handlerClass="com.intellij.codeInsight.hint.InspectionDescriptionLinkHandler"/>
|
||||
<codeInsight.linkHandler prefix="#navigation/" handlerClass="com.intellij.codeInsight.hint.NavigationLinkHandler"/>
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
<lang.emacs language="Python" implementationClass="com.jetbrains.python.editor.PyEmacsHandler"/>
|
||||
<annotator language="Python" implementationClass="com.jetbrains.python.validation.PyAnnotatingVisitor"/>
|
||||
<annotator language="Python" implementationClass="com.jetbrains.python.validation.PyDumbAwareAnnotator"/>
|
||||
<backspaceHandlerDelegate implementation="com.jetbrains.python.editor.PythonBackspaceHandler"/>
|
||||
<quoteHandler fileType="Python" className="com.jetbrains.python.editor.PythonQuoteHandler"/>
|
||||
<enterHandlerDelegate implementation="com.jetbrains.python.editor.PythonEnterHandler"/>
|
||||
<enterHandlerDelegate implementation="com.jetbrains.python.editor.PyEnterAtIndentHandler" order="first"/>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.jetbrains.python.editor;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.BackspaceHandler;
|
||||
import com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PythonBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
private LogicalPosition myTargetPosition;
|
||||
|
||||
public void beforeCharDeleted(final char c, final PsiFile file, final Editor editor) {
|
||||
if (PythonFileType.INSTANCE != file.getFileType()) return;
|
||||
myTargetPosition = BackspaceHandler.getBackspaceUnindentPosition(file, editor);
|
||||
}
|
||||
|
||||
public boolean charDeleted(final char c, final PsiFile file, final Editor editor) {
|
||||
if (myTargetPosition != null) {
|
||||
// Remove all the following spaces before moving to targetPosition
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final int targetOffset = editor.logicalPositionToOffset(myTargetPosition);
|
||||
editor.getSelectionModel().setSelection(targetOffset, offset);
|
||||
EditorModificationUtil.deleteSelectedText(editor);
|
||||
editor.getCaretModel().moveToLogicalPosition(myTargetPosition);
|
||||
myTargetPosition = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user