/**
* Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* @author: fabioz
* Created: January 2004
*/
package org.python.pydev.editor.actions;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.preference.IPreferenceStore;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.editor.actions.PyFormatStd.FormatStd;
import org.python.pydev.editor.commentblocks.CommentBlocksPreferences;
import org.python.pydev.plugin.preferences.PydevPrefs;
import org.python.pydev.shared_core.SharedCorePlugin;
import org.python.pydev.shared_core.string.FastStringBuffer;
import org.python.pydev.shared_core.string.StringUtils;
import org.python.pydev.shared_core.structure.Tuple;
/**
* Creates a comment block. Comment blocks are slightly different than regular comments
* created in that they provide a distinguishing element at the beginning and end as a
* separator. In this case, it is a string of <code>=======</code> symbols to strongly
* differentiate this comment block.
*
* @author Fabio Zadrozny
* @author Parhaum Toofanian
*/
public class PyAddBlockComment extends AbstractBlockCommentAction {
private boolean defaultClassNameBehaviour;
private boolean defaultFunctionNameBehaviour;
private FormatStd std;
public PyAddBlockComment(FormatStd std) {
//default
this.std = std;
}
public PyAddBlockComment() {
this(null);
}
/**
* For tests: assigns the default values
*/
PyAddBlockComment(FormatStd std, int defaultCols, boolean alignLeft, boolean classNameBehaviour,
boolean functionNameBehaviour) {
super(defaultCols, alignLeft);
this.std = std;
this.defaultClassNameBehaviour = classNameBehaviour;
this.defaultFunctionNameBehaviour = functionNameBehaviour;
}
@Override
protected void revealSelEndLine(PySelection ps) {
getTextEditor().selectAndReveal(ps.getEndLine().getOffset(), 0);
}
protected boolean getUseClassNameBehaviour() {
if (SharedCorePlugin.inTestMode()) {
return defaultClassNameBehaviour;
}
IPreferenceStore prefs = PydevPrefs.getPreferenceStore();
return prefs.getBoolean(CommentBlocksPreferences.MULTI_BLOCK_COMMENT_SHOW_ONLY_CLASS_NAME);
}
protected boolean getUseFunctionNameBehaviour() {
if (SharedCorePlugin.inTestMode()) {
return defaultFunctionNameBehaviour;
}
IPreferenceStore prefs = PydevPrefs.getPreferenceStore();
return prefs.getBoolean(CommentBlocksPreferences.MULTI_BLOCK_COMMENT_SHOW_ONLY_FUNCTION_NAME);
}
/**
* Performs the action with a given PySelection
*
* @param ps Given PySelection
* @return boolean The success or failure of the action
*/
@Override
public Tuple<Integer, Integer> perform(PySelection ps) {
// What we'll be replacing the selected text with
FastStringBuffer strbuf = new FastStringBuffer();
FastStringBuffer tempBuffer = new FastStringBuffer();
// If they selected a partial line, count it as a full one
ps.selectCompleteLine();
try {
String fullCommentLine;
String endLineDelim = ps.getEndLineDelim();
int startLineIndex = ps.getStartLineIndex();
int endLineIndex = ps.getEndLineIndex();
boolean classBehaviour = false;
if (startLineIndex == endLineIndex && getUseClassNameBehaviour()) {
if (ps.isInClassLine()) {
//just get the class name
classBehaviour = true;
}
}
boolean functionBehaviour = false;
if (startLineIndex == endLineIndex && getUseFunctionNameBehaviour()) {
if (ps.isInFunctionLine(false)) {
//just get the class name
functionBehaviour = true;
}
}
// Start of block
if (classBehaviour || functionBehaviour) {
String line = ps.getLine(startLineIndex);
int classIndex;
int tokLen;
if (classBehaviour) {
classIndex = line.indexOf("class ");
tokLen = 6;
} else {
classIndex = line.indexOf("def ");
tokLen = 4;
}
fullCommentLine = getFullCommentLine(classIndex, tempBuffer);
String spacesBefore;
if (classIndex > 0) {
spacesBefore = line.substring(0, classIndex);
} else {
spacesBefore = "";
}
strbuf.append(spacesBefore + "#").append(fullCommentLine).append(endLineDelim);
String initialLine = line;
line = line.substring(classIndex + tokLen);
FastStringBuffer className = new FastStringBuffer();
for (int i = 0; i < line.length(); i++) {
char cN = line.charAt(i);
if (Character.isJavaIdentifierPart(cN)) {
className.append(cN);
} else {
break;
}
}
strbuf.append(spacesBefore);
strbuf.append("# ");
strbuf.append(className);
strbuf.append(endLineDelim);
strbuf.append(spacesBefore);
strbuf.append("#").append(fullCommentLine);
strbuf.append(endLineDelim);
strbuf.append(initialLine);
} else {
List<String> lines = new ArrayList<String>();
int minCharsBefore = Integer.MAX_VALUE;
for (int i = startLineIndex; i <= endLineIndex; i++) {
String line = ps.getLine(i);
minCharsBefore = Math.min(minCharsBefore, PySelection.getFirstCharPosition(line));
lines.add(line);
}
String firstLine = lines.get(0);
String lastLine = lines.get(lines.size() - 1);
String strBefore = firstLine.substring(0, minCharsBefore);
fullCommentLine = getFullCommentLine(getLenOfStrConsideringTabEditorLen(strBefore), tempBuffer.clear());
strbuf.append(strBefore).append("#").append(fullCommentLine).append(endLineDelim);
String spacesInStartComment = null;
FormatStd std = this.std != null ? this.std : PyFormatStd.getFormat(getPyEdit());
if (std.spacesInStartComment != 0) {
if (std.spacesInStartComment < 0) {
//Negative means that we manage it manually!
spacesInStartComment = StringUtils.createSpaceString(1);
} else {
spacesInStartComment = StringUtils.createSpaceString(std.spacesInStartComment);
}
}
// For each line, comment them out
for (int i = startLineIndex; i <= endLineIndex; i++) {
String line = ps.getLine(i);
strbuf.append(line.substring(0, minCharsBefore));
strbuf.append("#");
line = line.substring(minCharsBefore);
strbuf.append(spacesInStartComment);
strbuf.append(line);
strbuf.append(endLineDelim);
}
// End of block
String strAfter = firstLine.substring(0, minCharsBefore);
fullCommentLine = getFullCommentLine(getLenOfStrConsideringTabEditorLen(strAfter), tempBuffer.clear());
strbuf.append(lastLine.substring(0, minCharsBefore)).append("#").append(fullCommentLine);
}
int startOffset = ps.getStartLine().getOffset();
String str = strbuf.toString();
// Replace the text with the modified information
ps.getDoc().replace(startOffset, ps.getSelLength(), str);
return new Tuple<Integer, Integer>(startOffset + str.length(), 0);
} catch (Exception e) {
e.printStackTrace();
beep(e);
}
// In event of problems, return null
return null;
}
@Override
protected String getPreferencesNameForChar() {
return CommentBlocksPreferences.MULTI_BLOCK_COMMENT_CHAR;
}
/**
* Currently returns a string with the comment block.
*
* @return Comment line string, or a default one if Preferences are null
*/
protected String getFullCommentLine(int subtract, FastStringBuffer buffer) {
Tuple<Integer, Character> colsAndChar = getColsAndChar();
int cols = colsAndChar.o1 - subtract;
char c = colsAndChar.o2;
buffer.clear();
for (int i = 0; i < cols - 1; i++) {
buffer.append(c);
}
return buffer.toString();
}
}