blob: dd00e2669fa0f1be0d8f7ff017f821a684da656f [file] [log] [blame]
/*
* 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.ide.DataManager;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.text.CharArrayUtil;
import java.util.concurrent.atomic.AtomicBoolean;
public class EndHandler extends EditorActionHandler {
private final EditorActionHandler myOriginalHandler;
public EndHandler(EditorActionHandler originalHandler) {
super(true);
myOriginalHandler = originalHandler;
}
@Override
public void execute(final Editor editor, DataContext dataContext) {
CodeInsightSettings settings = CodeInsightSettings.getInstance();
if (!settings.SMART_END_ACTION) {
if (myOriginalHandler != null) {
myOriginalHandler.execute(editor, dataContext);
}
return;
}
final Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(editor.getComponent()));
if (project == null) {
if (myOriginalHandler != null) {
myOriginalHandler.execute(editor, dataContext);
}
return;
}
final Document document = editor.getDocument();
final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) {
if (myOriginalHandler != null){
myOriginalHandler.execute(editor, dataContext);
}
return;
}
final EditorNavigationDelegate[] extensions = EditorNavigationDelegate.EP_NAME.getExtensions();
if (extensions != null) {
for (EditorNavigationDelegate delegate : extensions) {
if (delegate.navigateToLineEnd(editor, dataContext) == EditorNavigationDelegate.Result.STOP) {
return;
}
}
}
final CaretModel caretModel = editor.getCaretModel();
final int caretOffset = caretModel.getOffset();
CharSequence chars = editor.getDocument().getCharsSequence();
int length = editor.getDocument().getTextLength();
if (caretOffset < length) {
final int offset1 = CharArrayUtil.shiftBackward(chars, caretOffset - 1, " \t");
if (offset1 < 0 || chars.charAt(offset1) == '\n' || chars.charAt(offset1) == '\r') {
int offset2 = CharArrayUtil.shiftForward(chars, offset1 + 1, " \t");
boolean isEmptyLine = offset2 >= length || chars.charAt(offset2) == '\n' || chars.charAt(offset2) == '\r';
if (isEmptyLine) {
// There is a possible case that indent string is not calculated for particular document (that is true at least for plain text
// documents). Hence, we check that and don't finish processing in case we have such a situation. AtomicBoolean is used
// here just as a boolean value holder due to requirement to declare variable used from inner class as final.
final AtomicBoolean stopProcessing = new AtomicBoolean(true);
PsiDocumentManager.getInstance(project).commitAllDocuments();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CodeStyleManager styleManager = CodeStyleManager.getInstance(project);
final String lineIndent = styleManager.getLineIndent(file, caretOffset);
if (lineIndent != null) {
int col = calcColumnNumber(lineIndent, editor.getSettings().getTabSize(project));
int line = caretModel.getVisualPosition().line;
caretModel.moveToVisualPosition(new VisualPosition(line, col));
if (caretModel.getLogicalPosition().column != col){
if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), project)) {
return;
}
editor.getSelectionModel().removeSelection();
EditorModificationUtil.insertStringAtCaret(editor, lineIndent);
}
}
else {
stopProcessing.set(false);
}
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().removeSelection();
}
private int calcColumnNumber(final String lineIndent, final int tabSize) {
int result = 0;
for (char c : lineIndent.toCharArray()) {
if (c == ' ') result++;
if (c == '\t') result += tabSize;
}
return result;
}
});
if (stopProcessing.get()) {
return;
}
}
}
}
if (myOriginalHandler != null){
myOriginalHandler.execute(editor, dataContext);
}
}
}