blob: 7d3f1ef2eed8102168c946f51a0ffbc80cdea107 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.uima.ruta.ide.ui.text;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.uima.ruta.ide.ui.RutaPartitions;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.ui.CodeFormatterConstants;
import org.eclipse.dltk.ui.PreferenceConstants;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.rules.FastPartitioner;
public class RutaAutoEditStrategy extends DefaultIndentLineAutoEditStrategy {
// TODO
IPreferenceStore fStore;
String fPartitioning;
final int maxCharsAway = 100;
public RutaAutoEditStrategy(IPreferenceStore store, String part) {
fStore = store;
fPartitioning = part;
}
/*
* possible prefereces:
*
* general indent on/off smart tab key behaviour autoclose "strings", 'strings' autoclose
* {brackets}, [], () smart paste
*/
private boolean isSmartTab() {
return fStore.getBoolean(PreferenceConstants.EDITOR_SMART_TAB);
}
private boolean isSmartMode() {
return fStore.getBoolean(PreferenceConstants.EDITOR_SMART_INDENT);
}
private boolean closeBrackets() {
return fStore.getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACKETS);
}
private boolean isSmartPaste() {
return fStore.getBoolean(PreferenceConstants.EDITOR_SMART_PASTE);
}
private boolean closeStrings() {
return fStore.getBoolean(PreferenceConstants.EDITOR_CLOSE_STRINGS);
}
private int getIndentSize() {
return fStore.getInt(CodeFormatterConstants.FORMATTER_INDENTATION_SIZE);
}
private String getTabStyle() {
return fStore.getString(CodeFormatterConstants.FORMATTER_TAB_CHAR);
}
private String getIndent() {
if (getTabStyle().equals(CodeFormatterConstants.SPACE)) {
int size = getIndentSize();
String res = "";
for (int i = 0; i < size; i++)
res += " ";
return res;
} else
return "\t";
}
private boolean isLineDelimiter(IDocument document, String text) {
String[] delimiters = document.getLegalLineDelimiters();
if (delimiters != null)
return TextUtilities.equals(delimiters, text) > -1;
return false;
}
/**
* Returns the leading whitespaces and tabs.
*
* @param document
* - the document being parsed
* @param line
* - the line being searched
* @return the leading whitespace
* @throws BadLocationException
* in case <code>line</code> is invalid in the document
*/
private String getLineIndent(IDocument document, int line) throws BadLocationException {
if (line > -1) {
int start = document.getLineOffset(line);
int end = start + document.getLineLength(line); // was - 1
int whiteend = findEndOfWhiteSpace(document, start, end);
return document.get(start, whiteend - start);
}
return ""; //$NON-NLS-1$
}
/**
* Returns the leading whitespaces and tabs.
*
* @param line
* - the line being searched
* @return the leading whitespace
*/
public String getLineIndent(String line) {
int end = line.length();
int whiteend = end;
int offset = 0;
while (offset < end) {
char c = line.charAt(offset);
if (c != ' ' && c != '\t') {
whiteend = offset;
break;
}
offset++;
}
return line.substring(0, whiteend);
}
/**
* Find line with number <=line, that is not empty and is not a comment line starting with #
*
* @param d
* the document to search in
* @param line
* number of starting line
* @return number of code line or -1 if no such line found
* @throws BadLocationException
*/
private int getLastNonEmptyLine(IDocument d, int line) throws BadLocationException {
int res = line;
while (res > -1) {
String str = getDocumentLine(d, res).trim();
if ((!str.startsWith("#")) && str.length() > 0)
return res;
res--;
}
return res;
}
/**
* Fetched line from document
*
* @param d
* the document
* @param line
* number of req. line
* @return string with line
* @throws BadLocationException
* if <b>line</b> is not correct line number
*/
public String getDocumentLine(IDocument d, int line) throws BadLocationException {
int start = d.getLineOffset(line);
int length = d.getLineLength(line);
return d.get(start, length);
}
/**
* Get partition type covering offset
*
* @param d
* @param offset
* @return
* @throws BadLocationException
*/
private String getRegionType(IDocument d, int offset) throws BadLocationException {
int p = ((offset == d.getLength()) ? offset - 1 : offset);
ITypedRegion region = TextUtilities.getPartition(d, fPartitioning, p, true);
return region.getType();
}
/**
* Searchs an pair from offset, forward of backwards. Can skip strings and comments (uses ruta
* partitioning).
*
* @param d
* @param offset
* @param forward
* @param opening
* @param closing
* @param skipCommentLines
* @param skipStrings
* @return offset of pair, or -1 if not found
* @throws BadLocationException
*/
private int searchPair(IDocument d, int offset, boolean forward, char opening, char closing,
boolean skipCommentLines, boolean skipStrings) throws BadLocationException {
int deep = 0;
int i = offset;
if (forward) {
while (i < d.getLength()) {
ITypedRegion region = TextUtilities.getPartition(d, fPartitioning, i, true);
if (region.getType() == RutaPartitions.RUTA_COMMENT && skipCommentLines) {
i = region.getOffset() + region.getLength();
continue;
}
if (region.getType() == RutaPartitions.RUTA_STRING && skipStrings) {
i = region.getOffset() + region.getLength();
continue;
}
char c = d.getChar(i);
if (c == opening)
deep++;
if (c == closing) {
if (deep == 0)
return i;
deep--;
}
i++;
if (i - offset > maxCharsAway)
return -1;
}
} else {
while (i >= 0) {
ITypedRegion region = TextUtilities.getPartition(d, fPartitioning, i, true);
if (region.getType() == RutaPartitions.RUTA_COMMENT && skipCommentLines) {
i = region.getOffset() - 1;
continue;
}
if (region.getType() == RutaPartitions.RUTA_STRING && skipStrings) {
i = region.getOffset() - 1;
continue;
}
char c = d.getChar(i);
if (c == closing)
deep++;
if (c == opening) {
if (deep == 0)
return i;
deep--;
}
i--;
if (offset - i > maxCharsAway)
return -1;
}
}
return -1;
}
/**
* Finds line < <b>line</b>, such the indent of it is less than of <b>line</b>
*
* @param d
* the document to search in
* @param line
* appropriate line number
* @return if found, number < <b>line</b>, else <b>line</b>
*/
private int findIndentStart(IDocument d, int line) throws BadLocationException {
String curIndent = getLineIndent(d, line);
int curIndentLength = getPhysicalLength(curIndent);
int cur = line - 1;
while (cur >= 0) {
String curLine = getDocumentLine(d, cur);
String ind = getLineIndent(d, cur);
if ((!curLine.trim().startsWith("#")) && getPhysicalLength(ind) < curIndentLength)
return cur;
cur--;
}
return line;
}
/**
* Calculates real length of string. So any char except \t has length 1, \t has length 8.
*
* @param str
* string to process
* @return length
*/
public int getPhysicalLength(String str) {
int res = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '\t')
res += 8; // TODO
else
res++;
}
return res;
}
/**
* Return pair to brace. Ex. '(' for ')', e.t.c.
*
* @param b
* input brace
* @return peer brace
*/
private char getBracePair(char b) {
switch (b) {
case '(':
return ')';
case ')':
return '(';
case '[':
return ']';
case ']':
return '[';
case '{':
return '}';
case '}':
return '{';
case '\"':
return '\"';
case '\'':
return '\'';
}
return b;
}
/**
* Installs a partitioner with <code>document</code>.
*
* @param document
* the document
*/
private static void installStuff(Document document) {
String[] types = new String[] { RutaPartitions.RUTA_STRING, RutaPartitions.RUTA_COMMENT,
IDocument.DEFAULT_CONTENT_TYPE };
FastPartitioner partitioner = new FastPartitioner(new RutaPartitionScanner(), types);
partitioner.connect(document);
document.setDocumentPartitioner(RutaPartitions.RUTA_PARTITIONING, partitioner);
}
/**
* Removes partitioner with <code>document</code>.
*
* @param document
* the document
*/
private static void removeStuff(Document document) {
document.setDocumentPartitioner(RutaPartitions.RUTA_PARTITIONING, null);
}
/**
* STRATEGIES
*/
/**
* Main indenting algorithm. Needs correct partitioning to work.
*
* @param d
* the processed document
* @param line
* line, indenting of which we wanna know
* @param newLine
* if <b>line</b> is new line, so we have pressed enter-key, and need indentation for new
* line
* @param offset
* position, where we have jumped to new line
* @return correct indent for line, or null if we should use "default" indent. So calling side
* should determine, change indent or not, or may be use indent of previous line.
* @throws BadLocationException
*/
private String calcLineIndent(IDocument d, int line, boolean newLine, int offset)
throws BadLocationException {
boolean isDocumentEnd = (offset == d.getLength());
// STRINGS
if (newLine) {
// if we wrap string
if (getRegionType(d, offset) == RutaPartitions.RUTA_STRING) {
int realLine = d.getLineOfOffset(offset);
String curIndent = getLineIndent(d, realLine);
// if we just closed string
if (d.getChar(offset - 1) != '"') {
// if we are fully in string
if (getRegionType(d, d.getLineOffset(realLine)) == RutaPartitions.RUTA_STRING) {
return curIndent;
}
// if we first time wrap string
return curIndent + getIndent();
}
}
} else {
// don't correct strings
if (getRegionType(d, d.getLineOffset(line)) == RutaPartitions.RUTA_STRING) {
return getLineIndent(d, line); // notice, that we don't use
// null
}
}
// LINE JOINING
if (newLine) {
int realLine = d.getLineOfOffset(offset);
if (line > 0) {
String previousLine = "";
if (realLine == line - 1) {
int start = d.getLineOffset(realLine);
previousLine = d.get(start, offset - start);
} else
previousLine = getDocumentLine(d, line - 1);
if (previousLine.trim().endsWith("\\")) {
String prePreviousLine = getDocumentLine(d, line - 2);
if (prePreviousLine.trim().endsWith("\\"))
return getLineIndent(d, line - 1);
return getLineIndent(d, line - 1) + getIndent() + getIndent();
}
if (line > 1) {
String prePreviousLine = getDocumentLine(d, line - 2);
if (prePreviousLine.trim().endsWith("\\")) {
// find start
int t = line - 2;
while (t > 0 && getDocumentLine(d, t - 1).trim().endsWith("\\")) {
t--;
}
return getLineIndent(d, t);
}
}
}
} else {
/*
* If this line is explicitly joined: If the previous line was also joined, line it up with
* that one, otherwise add two 'shiftwidth'
*/
if (line > 0) {
String previousLine = getDocumentLine(d, line - 1);
if (previousLine.trim().endsWith("\\")) {
if (line > 1) {
String prePreviousLine = getDocumentLine(d, line - 2);
if (prePreviousLine.trim().endsWith("\\"))
return getLineIndent(d, line - 1);
}
return getLineIndent(d, line - 1) + getIndent() + getIndent();
}
}
}
// Search backwards for the previous non-empty line.
int lastNonEmptyLine = getLastNonEmptyLine(d, line - 1);
if (lastNonEmptyLine < 0) {
// This is the first non-empty line, use zero indent.
return "";
}
// first check, if we not inside string, if yes, jump to start
ITypedRegion region = TextUtilities.getPartition(d, fPartitioning,
d.getLineOffset(lastNonEmptyLine), true);
if (region.getType() == RutaPartitions.RUTA_STRING) {
lastNonEmptyLine = d.getLineOfOffset(region.getOffset());
}
// If the previous line is inside parenthesis, use the indent of the
// starting line.
int plnumstart;
String previousLineIndent = "";
int pairOffset = searchPair(d, d.getLineOffset(lastNonEmptyLine), false, '(', ')', true, true);
if (pairOffset >= 0) {
plnumstart = d.getLineOfOffset(pairOffset);
previousLineIndent = getLineIndent(d, plnumstart);
} else {
plnumstart = lastNonEmptyLine;
previousLineIndent = getLineIndent(d, lastNonEmptyLine);
}
/*
* When inside parenthesis: If at the first line below the parenthesis add two 'shiftwidth',
* otherwise same as previous line. i = (a + b + c)
*/
int p = searchPair(d, offset - 1, false, '(', ')', true, true);
if (p >= 0) {
if (d.getLineOfOffset(p) == lastNonEmptyLine) {
// When the start is inside parenthesis, only indent one
// 'shiftwidth'.
int pp = searchPair(d, p, false, '(', ')', true, true);
if (pp >= 0)
return getLineIndent(d, lastNonEmptyLine) + getIndent();
return getLineIndent(d, lastNonEmptyLine) + getIndent() + getIndent();
}
if (d.getLineOfOffset(p) == plnumstart) {
return getLineIndent(d, lastNonEmptyLine);
}
if (d.getLineOfOffset(p) == line && !newLine)
return null;
return previousLineIndent;
}
// Get the line and remove a trailing comment.
String pline = "";
if (lastNonEmptyLine == line - 1 && newLine) {
pline = d.get(d.getLineOffset(line - 1), offset - d.getLineOffset(line - 1));
} else {
pline = getDocumentLine(d, lastNonEmptyLine);
}
int plineLen = pline.length();
int i;
for (i = 0; i < plineLen; i++) {
if (pline.charAt(i) == '#') {
pline = pline.substring(0, i);
break;
}
}
String plineTrimmed = pline.trim();
try {// If the current line begins with a keyword that lines up with
// "try"
String curLine = "";
if (lastNonEmptyLine == line - 1 && newLine) {
curLine = d.get(offset, d.getLineLength(line - 1) + d.getLineOffset(line - 1) - offset);
} else {
curLine = getDocumentLine(d, line).trim();
}
if (curLine.startsWith("except") || curLine.startsWith("finally")) {
int lnum = line - 1;
while (lnum >= 0) {
String temp = getDocumentLine(d, lnum).trim();
if (temp.startsWith("try") || temp.startsWith("except")) {
String ind = getLineIndent(d, lnum);
return ind;
}
lnum--;
}
return null;
}
// If the current line begins with a header keyword, dedent
if (curLine.startsWith("elif") || curLine.startsWith("else")) {
// Unless the previous line was a one-liner
String temp = getDocumentLine(d, lastNonEmptyLine).trim();
if (temp.startsWith("for") || temp.startsWith("if") || temp.startsWith("try")
|| temp.startsWith("while")) {
return previousLineIndent;
}
int sline = findIndentStart(d, lastNonEmptyLine);
String reqIndent = getLineIndent(d, sline);
return reqIndent;
}
} catch (BadLocationException e) {
// do nothing, we just don't have current line
}
// If the previous line was a stop-execution statement...
String regex = "^\\s*(break|continue|raise|pass|return)(\\s+.*$|$)";
if (Pattern.matches(regex, plineTrimmed)) {
// find indent
int sline = findIndentStart(d, lastNonEmptyLine);
String reqIndent = getLineIndent(d, sline);
if (newLine || isDocumentEnd
|| (getPhysicalLength(getLineIndent(d, line)) > getPhysicalLength(reqIndent))) {
return reqIndent;
}
// trust the user
return null;
}
// If the previous line ended with a colon, indent this line
if (plineTrimmed.endsWith(":"))
return previousLineIndent + getIndent();
if (pairOffset >= 0 && newLine) {
return previousLineIndent;
}
// after-string
int prevLine = getLastNonEmptyLine(d, line - 1);
if (getRegionType(d, d.getLineOffset(prevLine)) == RutaPartitions.RUTA_STRING)
return previousLineIndent;
return null;
}
/**
* If we have pressed ":" for example, than we need to reindent line. This function changes
* document and sets correct indent for current line.
*
* @param d
* @param c
*/
private void reindent(IDocument d, DocumentCommand c) {
try {
if (getRegionType(d, c.offset) != IDocument.DEFAULT_CONTENT_TYPE)
return;
int line = d.getLineOfOffset(c.offset);
String newIndent = calcLineIndent(d, line, false, c.offset);
if (newIndent == null)
return;
String curIndent = getLineIndent(d, line);
if (getPhysicalLength(curIndent) < getPhysicalLength(newIndent))
return;
d.replace(d.getLineOffset(line), curIndent.length(), newIndent);
c.offset += (newIndent.length() - curIndent.length());
} catch (BadLocationException e) {
}
}
/**
* Processes command in work with brackets, strings, etc
*
* @param d
* @param c
*/
private void autoClose(IDocument d, DocumentCommand c) {
if (c.offset == -1)
return;
try {
if (d.getChar(c.offset - 1) == '\\')
return;
} catch (BadLocationException e1) {
}
if ('\"' == c.text.charAt(0) && !closeStrings())
return;
if ('\'' == c.text.charAt(0) && !closeStrings())
return;
if (!closeBrackets()
&& ('[' == c.text.charAt(0) || '(' == c.text.charAt(0) || '{' == c.text.charAt(0)))
return;
try {
switch (c.text.charAt(0)) {
case '\"':
case '\'':
// if we close existing quote, do nothing
if ('\"' == c.text.charAt(0) && c.offset > 0 && "\"".equals(d.get(c.offset - 1, 1)))
return;
if ('\'' == c.text.charAt(0) && c.offset > 0 && "\'".equals(d.get(c.offset - 1, 1)))
return;
if (c.offset != d.getLength() && c.text.charAt(0) == d.get(c.offset, 1).charAt(0))
c.text = "";
else {
c.text += c.text;
c.length = 0;
}
c.shiftsCaret = false;
c.caretOffset = c.offset + 1;
break;
case '(':
case '{':
case '[':
// check partition
if (getRegionType(d, c.offset) != IDocument.DEFAULT_CONTENT_TYPE)
return;
if (c.offset != d.getLength() && c.text.charAt(0) == d.get(c.offset, 1).charAt(0))
return;
try { // in class closing
String regex = "^\\s*class\\s+.*";
String regex2 = ".*\\(.*\\).*";
int start = d.getLineOffset(d.getLineOfOffset(c.offset));
String curLine = d.get(start, c.offset - start);
if (Pattern.matches(regex, curLine) && !Pattern.matches(regex2, curLine)) {
c.text = "():";
c.shiftsCaret = false;
c.caretOffset = c.offset + 1;
return;
}
} catch (BadLocationException e) {
}
// add closing peer
c.text = c.text + getBracePair(c.text.charAt(0));
c.length = 0;
c.shiftsCaret = false;
c.caretOffset = c.offset + 1;
break;
case '}':
case ']':
case ')':
// check partition
if (getRegionType(d, c.offset) != IDocument.DEFAULT_CONTENT_TYPE)
return;
if (!closeBrackets())
return;
// if we already have bracket we should jump over it
if (c.offset != d.getLength() && c.text.charAt(0) == d.get(c.offset, 1).charAt(0)) {
c.text = "";
c.shiftsCaret = false;
c.caretOffset = c.offset + 1;
return;
}
break;
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/**
* When we have pressed \t, sometimes we wanna not to tabulate, and jump to correct line start
* position.
*
* @param d
* @param c
* @return
*/
private boolean smartIndentJump(IDocument d, DocumentCommand c) {
if (c.offset == -1 || d.getLength() == 0)
return false;
try {
// int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);
int line = d.getLineOfOffset(c.offset);
int start = d.getLineOffset(line);
// calculate indentation of this line
String resultIndent = calcLineIndent(d, line, false, start);
String currentIndent = getLineIndent(d, line);
if (resultIndent == null) { // we should save indentation
String curLine = getDocumentLine(d, line);
if (curLine.trim().length() > 0) // if indentation is "real",
// use it
resultIndent = currentIndent;
else {
// get current block level
int pl = getLastNonEmptyLine(d, line - 1); // find last
// code line
if (pl >= 0) {
String plStr = getDocumentLine(d, pl).trim();
// simple indent-guess strategy
String regex = "^\\s*(break|continue|raise|pass|return)(\\s+.*$|$)";
if (plStr.endsWith(":"))
resultIndent = getLineIndent(plStr) + getIndent();
else if (Pattern.matches(regex, plStr)) {
// find indent
int sline = findIndentStart(d, pl);
resultIndent = getLineIndent(d, sline);
} else
resultIndent = getLineIndent(d, pl);
} else
return false; // no indent is applicable, do nothing
}
}
if (c.offset >= start + resultIndent.length())
return false; // we already in the place
if (!currentIndent.startsWith(resultIndent)) { // create indent
c.offset = start;
c.length = currentIndent.length();
c.shiftsCaret = false;
c.text = resultIndent;
c.caretOffset = d.getLineOffset(line) + resultIndent.length();
return true;
}
c.length = 0;
c.shiftsCaret = false;
c.text = "";
c.caretOffset = d.getLineOffset(line) + resultIndent.length();
return true;
} catch (BadLocationException e) {
e.printStackTrace();
}
return false;
}
/**
* Reindents c.text when pasting.
*
* @param d
* @param c
*/
private void smartPaste(IDocument d, DocumentCommand c) {
try {
String content = d.get(0, c.offset) + c.text;
Document temp = new Document(content);
DocumentRewriteSession session = temp
.startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL);
installStuff(temp);
int offset = c.offset;
int line = temp.getLineOfOffset(offset);
String lastIndent = getLineIndent(temp, line);
int firstLineOffset = temp.getLineOffset(line);
String commonIndent = temp.get(firstLineOffset, c.offset - firstLineOffset);
if (StringUtils.isNotBlank(commonIndent)) {
// do not copy non whitespace content as indent
// and only use leading white spaces
String notWSContent = commonIndent.replaceAll("^\\s+", "");
commonIndent = StringUtils.removeEnd(commonIndent, notWSContent);
}
line++;
try {
while (getDocumentLine(temp, line).trim().length() == 0)
line++;
offset = temp.getLineOffset(line);
} catch (BadLocationException e) {
offset = temp.getLength();
}
while (offset < temp.getLength()) {
String resultIndent = calcLineIndent(temp, line, false, temp.getLineOffset(line));
String currentIndent = getLineIndent(temp, line);
if (resultIndent == null) {
resultIndent = commonIndent + currentIndent;
// TODO commented to retain indent of pasted blocks
// if (getPhysicalLength(resultIndent) > getPhysicalLength(lastIndent))
// resultIndent = lastIndent;
}
temp.replace(offset, currentIndent.length(), resultIndent);
String currentLine = getDocumentLine(temp, line);
if (currentLine.trim().length() > 0 && (!currentLine.trim().startsWith("//"))) {
lastIndent = resultIndent;
}
if (temp.getLineOffset(line) + temp.getLineLength(line) == temp.getLength())
break;
line++;
offset = temp.getLineOffset(line);
}
temp.stopRewriteSession(session);
removeStuff(temp);
c.text = temp.get(c.offset, temp.getLength() - c.offset);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.text.IAutoEditStrategy#customizeDocumentCommand(org.eclipse.jface.text.IDocument
* , org.eclipse.jface.text.DocumentCommand)
*/
@Override
public void customizeDocumentCommand(IDocument d, DocumentCommand c) {
if (c.doit == false)
return;
if (c.length == 0 && c.text != null && isLineDelimiter(d, c.text)) {
if (!isSmartMode()) {
super.customizeDocumentCommand(d, c);
return;
}
try {
String indent = calcLineIndent(d, d.getLineOfOffset(c.offset) + 1, true, c.offset);
if (indent == null)
super.customizeDocumentCommand(d, c);
else {
if (DLTKCore.DEBUG) {
System.err.println("Bug:PTN-9");
}
c.text = c.text + indent;
}
} catch (BadLocationException e) {
super.customizeDocumentCommand(d, c);
}
return;
} else {
if (c.length <= 1 && c.text.length() == 1) {
switch (c.text.charAt(0)) {
case ':':
reindent(d, c);
break;
case '\"':
case '\'':
case '(':
case '{':
case '[':
case '}':
case ']':
case ')':
autoClose(d, c);
break;
case '\t':
boolean jumped = false;
if (isSmartTab()) {
jumped = smartIndentJump(d, c);
}
if (!jumped) {
c.text = getIndent();
}
break;
}
} else if (c.text.length() >= 1 && isSmartPaste())
smartPaste(d, c); // no smart backspace for paste
}
}
}