/*******************************************************************************
* Copyright (c) 2010, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.ide.core_text;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import static melnorme.utilbox.core.CoreUtil.areEqual;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.junit.Test;
import melnorme.lang.ide.core.text.BlockHeuristicsScannner;
import melnorme.lang.ide.core.text.DocumentCommand2;
import melnorme.lang.ide.core.text.TextSourceUtils;
import melnorme.lang.ide.core.text.format.FormatterIndentMode;
import melnorme.lang.ide.core.text.format.ILangAutoEditsPreferencesAccess;
import melnorme.lang.ide.core.text.format.ILastKeyInfoProvider;
import melnorme.lang.ide.core.text.format.LangAutoEditStrategy;
import melnorme.lang.ide.core.text.format.ILastKeyInfoProvider.KeyCommand;
import melnorme.utilbox.misc.MiscUtil;
import melnorme.utilbox.misc.StringUtil;
public class LangAutoEditStrategyTest extends Scanner_BaseTest {
public static class InstrumentedLastKeyInfoProvider implements ILastKeyInfoProvider {
public KeyCommand lastPressedKey = KeyCommand.OTHER;
@Override
public KeyCommand getLastPressedKey() {
return lastPressedKey;
}
}
public static class Mock_LangAutoEditsPreferencesAccess implements ILangAutoEditsPreferencesAccess {
@Override
public boolean isSmartIndent() {
return true;
}
@Override
public boolean isSmartDeIndent() {
return true;
}
@Override
public boolean closeBraces() {
return true;
}
@Override
public boolean isSmartPaste() {
return true;
}
@Override
public FormatterIndentMode getTabStyle() {
return FormatterIndentMode.TAB;
}
@Override
public int getIndentSize() {
return 4;
}
@Override
public boolean parenthesesAsBlocks() {
return true;
}
}
public static final String NEUTRAL_SRCX;
static {
NEUTRAL_SRCX = MiscUtil.getClassResource(LangAutoEditStrategyTest.class, "sample_block_code");
}
public static final String PENDING_WS1 = " ";
public static final String PENDING_WS2 = "\t ";
public static final String PENDING_TXT = "\tpending";
protected LangAutoEditStrategy autoEditStrategy;
protected final InstrumentedLastKeyInfoProvider lastKeyInfoProvider = new InstrumentedLastKeyInfoProvider();
protected LangAutoEditStrategy getAutoEditStrategy() {
if(autoEditStrategy == null) {
ILangAutoEditsPreferencesAccess preferences = new Mock_LangAutoEditsPreferencesAccess();
lastKeyInfoProvider.lastPressedKey = KeyCommand.OTHER;
autoEditStrategy = new LangAutoEditStrategy(lastKeyInfoProvider, preferences) {
@Override
protected BlockHeuristicsScannner createBlockHeuristicsScanner(IDocument doc) {
return Scanner_BaseTest.createBlockHeuristicScannerWithSamplePartitioning(doc);
};
};
}
return autoEditStrategy;
}
protected DocumentCommand2 createDocumentCommand(int start, int length, String text) {
DocumentCommand2 documentCommand = new DocumentCommand2() {};
documentCommand.doit = true;
documentCommand.text = text;
documentCommand.offset = start;
documentCommand.length = length;
documentCommand.caretOffset = -1;
documentCommand.shiftsCaret = true;
return documentCommand;
}
protected void testEnterEdit(String textBeforeCursor, String expectIndent) {
testEnterEdit(textBeforeCursor, null, expectIndent);
}
protected void testEnterEdit(String textBeforeCursor, String textAfterCursor, String expectIndent) {
int indent = 0;
while(indent < 3) {
if(textAfterCursor == null) {
if(indent == 0) {
textAfterCursor = "";
}
if(indent == 1) {
textAfterCursor += NL + ")}" + NEUTRAL_SRC1; // This source after should have no effect
}
if(indent == 2) {
textAfterCursor += "blah)}]"; // This source after should have no effect
}
}
String[] before_Lines = textBeforeCursor.split("\\\\n");
String textBeforeCursor_mod = StringUtil.collToString(before_Lines, TABn(indent));
testEnterAutoEdit(textBeforeCursor_mod, textAfterCursor, expectIndent);
indent++;
}
}
protected void testEnterAutoEdit(String textBefore, String textAfter, String expectedEdit) {
int caretOffset = textBefore.length();
testAutoEdit(textBefore, textAfter, NL+expectedEdit, caretOffset);
}
protected void testEnterEdit(String textBefore, String textAfter, String expInsert, String expInsertAfter) {
expInsert = NL + expInsert;
int caretOffset = textBefore.length() + expInsert.length();
testAutoEdit(textBefore, textAfter, expInsert+expInsertAfter, caretOffset);
}
protected void testAutoEdit(String textBefore, String textAfter, String expectedInsert, int caretOffset) {
testAutoEdit_____(textBefore, "", textAfter, expectedInsert, caretOffset, NL);
}
protected void testAutoEdit_____(String textBefore, String deletedText, String afterCursor,
String expectedInsert, int caretOffset, String insertedText) {
String beforeCursor = textBefore + deletedText;
Document document = setupDocument(beforeCursor + afterCursor);
int keypressOffset = beforeCursor.length();
DocumentCommand2 docCommand = createDocumentCommand(keypressOffset, 0, insertedText);
LangAutoEditStrategy autoEditStrategy = getAutoEditStrategy();
if(docCommand.length == 0 && areEqual(docCommand.text, NL)) {
lastKeyInfoProvider.lastPressedKey = KeyCommand.ENTER;
}
autoEditStrategy.customizeDocumentCommand(document, docCommand);
int replaceLength = deletedText.length();
if(caretOffset == textBefore.length()) {
caretOffset = -1;
}
checkCommand(docCommand, expectedInsert, textBefore.length(), replaceLength, caretOffset);
}
protected Document setupDocument(String textBefore, String textAfter) {
return setupDocument(textBefore + textAfter);
}
protected Document setupDocument(String contents) {
Document document = getDocument();
document.set(contents);
return document;
}
protected void checkCommand(DocumentCommand2 documentCommand, String text, int offset, int length) {
checkCommand(documentCommand, text, offset, length, -1);
}
protected void checkCommand(DocumentCommand2 documentCommand, String text, int offset, int length,
int caretOffset) {
assertEquals(documentCommand.text, text);
assertTrue(documentCommand.offset == offset);
assertTrue(documentCommand.length == length);
assertTrue(documentCommand.caretOffset == caretOffset);
assertTrue(documentCommand.shiftsCaret == (caretOffset == -1));
}
protected static String TABn(int indent) {
return TextSourceUtils.stringNTimes(TAB, indent);
}
protected static String expectInd(String indent) {
return indent;
}
protected static String expectInd(String nl, int indent) {
return nl+TABn(indent);
}
protected static String expectClose(int indent, String close) {
return NL+TABn(indent-1)+close;
}
@Test
public void testSmartIndent() throws Exception { testSmartIndent$(); }
public void testSmartIndent$() throws Exception {
testEnterEdit("void main(){}", "blah", ""); // balance 0 : 0
testEnterEdit("void main(){", NL+"}", TAB); // balance 0 : 1 (closed)
testEnterEdit("void main(){", "}", "");
String dNL = getDocument().getDefaultLineDelimiter();
// balance 0 : 1(unclosed)
testEnterEdit("void main{", "" , TAB, dNL+"}");
testEnterEdit("void main(", NL+"func(){}"+NL+"blah();", TAB, NL+")");
testEnterEdit("vo() main{", " "+NL+"func(){}"+NL+"blah();", TAB, NL+"}");
// balance 0 : 1(unclosed but don't close due to pending text)
testEnterEdit("void main(){", "func(){}"+NL+"blah();", TAB);
String s;
s = line("func{")+
TAB+"abc}"; // balance -1 : 0
testEnterEdit(s, "}"+NEUTRAL_SRC1, "");
s = line("func{{")+
TAB+"abc}}"; // balance -2 : 0
testEnterEdit(s, "}"+NEUTRAL_SRC1, "");
s = line(TAB+"func((")+
TAB+"abc))"; // balance -2 : 0 '('
testEnterEdit(s, NEUTRAL_SRC1+")", TAB);
testEnterEdit("func("+NL + "\tblah",
"\t");
/* ----------------- some boundary cases ----------------- */
testEnterEdit("", "", TABn(0));
testEnterEdit("", "}", TABn(0));
testEnterEdit("{", "", TABn(1), document.getDefaultLineDelimiter()+"}");
// test potential close
testEnterEdit("(",
NL +")", TABn(1));
// test potential close
testEnterEdit("}(",
NL +")", TABn(1));
// test potential close
testEnterEdit("{"+NL+"(",
NL +")", TABn(1));
// test empty line
testEnterEdit(line("func{")+"", "){"+NL+")",
TABn(1));
/* ----------------- ----------------- */
testEnterEdit(
line("func(") + "abc{",
NL+"}", TABn(1)); // test 0 : 1
testEnterEdit(
line("func{") + "}abc{",
PENDING_WS1+NL+"}", TABn(1)); // test -1 : 1
testEnterEdit(
line("func{") + "\t\t ", // test all WhiteSpace
PENDING_WS2+NL +")", "\t\t ");
// test another -1 : 1
testEnterEdit(
line("func{")+ "}blah(",
NL +")", TABn(1));
// Test deindentation due to postfix
testEnterEdit(
line("func{")+ "\tblah(",
")", "\t");
// Test deindentation due to postfix - multiple
testEnterEdit(line("{ {func("),
")}"+NL+"}", TABn(1));
testEnterEdit(line("{ {func("),
")}"+NL , TABn(1));
s = line("func({")+
"abc("; // test potential close (go outside dominating block?)
testEnterEdit(s,
NL+")"+ NEUTRAL_SRC1+"}", TABn(1));
s = line("func{")+
"abc("; // test potential close (unclosed dominating block)
testEnterEdit(s,
NL+")", TABn(1));
s = line("func{")+
"abc("; // test potential close (pending text)
testEnterEdit(s,
PENDING_TXT+NL+")", TABn(1));
s = line("func{")+
"}blah("; // test close, -1 : 1, right=(_
testEnterEdit(s,
"", TABn(1), expectClose(0+1, ")"));
s = line("func{")+
"}blah{{"; // test close, -1 : 2, right={{_
testEnterEdit(s,
PENDING_WS2+NL, TABn(0+2), expectClose(0+2, "}"));
s = line("func{")+
"}}blah{"; // test close, -2 : 1, right={_..
testEnterEdit(s,
NL+NEUTRAL_SRC1, TABn(1), expectClose(0+1, "}"));
s = line("func{")+
"}}blah{{"; // test close, -2 : 1, right= {{_..}
testEnterEdit(s,
NL+NEUTRAL_SRC1+"}", TABn(0+2), expectClose(0+2, "}"));
s = line("}}blah{")+
line("{func{")+
line(TABn(2) + NEUTRAL_SRC1)+
"}blah{"; // test close, -2 : 1, right=}} {{..}{_..}
testEnterEdit(s,
NL+NEUTRAL_SRC1+line("}"), TABn(1), expectClose(0+1, "}"));
s = line("func{{{")+
TAB+"abc}}}"; // test -3 : 0
testEnterEdit(s,
TABn(0));
s = line(TABn(7) + "func({{{")+ // start block still has : 2 open block
TAB+"abc}}"; // test -2 : 0
testEnterEdit(s,
TABn(0+7+2));
s = line("func")+
TAB+"abc}}}"; // test -3 : 0 with zero indent
testEnterEdit(s,
TABn(0));
s = line("func")+
"abc}}}"; // test -3 : 0 with zero indent
testEnterEdit(s,
TABn(0));
s = line("func{{{")+
line(TABn(4) + "func{()}")+ // test interim lines with irregular ident
TAB+"abc}}"; // -2 : 0
testEnterEdit(s,
TABn(1));
s = line(TABn(2) +NEUTRAL_SRC1)+ // more lines
line(TABn(2) +"}}func{{{")+ // matching start block is -2 : 3
line(TABn(2) +NEUTRAL_SRC1)+ // more lines
line(TABn(2-2) + "func{()}")+ // interim lines with irregular ident (negative)
TABn(2) + TAB+"abc(blah{}) blah}}"; // -2 : 0
testEnterEdit(s,
TABn(2+1));
testSmartIndent_withPartitioning$();
}
public void testSmartIndent_withPartitioning$() throws Exception {
assertContains(getDocument().getPartitionings(), SamplePartitionScanner.LANG_PARTITIONING);
final int indent = 1; // Needs to be greater than 1
String s;
s = line(TABn(indent) + "func()")+
"//"+TAB+"abc"; // test with line comment
testEnterEdit(s, NL +"})"+ NEUTRAL_SRC1, TABn(indent));
s = line(TABn(indent) + "func(")+
"//"+TAB+"abc)"; // test with line comment, with +1 indent
testEnterEdit(s, NL +")"+ NEUTRAL_SRC1, TABn(indent+1));
s = line(TABn(indent) + "func{")+
line(TABn(indent+1) + "blah}")+
"//"+TAB+"abc)"; // test with line comment, with -1 indent
testEnterEdit(s, NL +")"+ NEUTRAL_SRC1, TABn(indent));
s = line(TABn(indent) + "{func(")+
"//"+TAB+"abc"; // test with line comment, characters after
testEnterEdit(s, ")"+NL+ NEUTRAL_SRC1, TABn(indent+2));
s = line(TABn(indent) + "func({")+
"/**/"; // test with block comment, with +2 indent Close
testEnterEdit(s, NL +"blah"+ NEUTRAL_SRC1, TABn(indent+2), expectClose(indent+2, "}"));
s = line(TABn(indent) + "func(((")+
TABn(indent) + "// blah"; // test line comment with whitespace before, (This-Line)
testEnterEdit(s, NL +"}}}"+ NEUTRAL_SRC1, TABn(indent));
s = line(TABn(indent) + "func(((")+
TABn(indent) + "/**/"; // test block comment with whitespace before, (This-Line)
testEnterEdit(s, NL +"}}}"+ NEUTRAL_SRC1, TABn(indent));
s = line(TABn(indent) + "func(")+
"/* */"+TAB+"abc{{{"; // test block comment with characters after, (This-Line)
testEnterEdit(s, NL +"}}})"+ NEUTRAL_SRC1, TABn(0+3));
s = "//abc{"; // test line comment, no valid line before
testEnterEdit(s, NL +"})"+ NEUTRAL_SRC1, TABn(0));
s = "/*abc{*/"; // test block comment, no valid line before
testEnterEdit(s, NL +"})"+ NEUTRAL_SRC1, TABn(0));
s = line(TABn(indent) + "func((()))")+
"/**/"; // test block comment at EOF
testEnterEdit(s, "", TABn(indent));
/* ------- These cases are tricky, might change in the future */
s = line(TABn(indent) + "{func(")+
"// foobar"; // test line comment, characters after that afect block balance
testEnterEdit(s, ")}"+NL+ NEUTRAL_SRC1, TABn(indent+2));
s = line(TABn(indent) + "{func(")+
"// foobar{"; // test line comment, characters after that afect block balance
testEnterEdit(s, ")"+NL+ NEUTRAL_SRC1, TABn(indent+2));
s = line(TABn(indent) + "(func{")+
TABn(indent) + "/* foobar"; // test edit inside block comment
testEnterEdit(s, NL+"})*/})"+ NEUTRAL_SRC1, TABn(indent));
s = line(TABn(indent) + "{func(")+
"/* foobar"; // test edit inside block comment
testEnterEdit(s, NL+ ")}*/"+ NEUTRAL_SRC1, TABn(indent+2), expectClose(indent+2, ")"));
s = line(TABn(indent) + "{func}")+
TABn(indent) + "{func{/* foobar}"; // test edit inside block comment
testEnterEdit(s, NL+"}}*/}"+ NEUTRAL_SRC1, TABn(indent+2), expectClose(indent+2, "}"));
}
@Test
public void testSmartIdent_SyntaxErrors() throws Exception { testSmartIdent_SyntaxErrors$(); }
public void testSmartIdent_SyntaxErrors$() throws Exception {
String s;
s = line("func")+
"abc{"; // test 0 : 1 (with syntax error)
testEnterEdit(s, NL +"})"+ NEUTRAL_SRC1, TABn(1));
s = line("func{")+
TAB+"{ab(c}"; // test 0 : 0 (corrected)
testEnterEdit(s, PENDING_WS1+NL+"}"+ NEUTRAL_SRCX, TABn(1+0));
s = line("func{")+
TAB+"{ab)c}"; // test 0 : 0 (corrected)
testEnterEdit(s, NL +"}"+ NEUTRAL_SRC3, TABn(1+0));
s = line("func{")+
TAB+"(ab{c)"; // test 0 : 2 (corrected)
testEnterEdit(s, NL +"}"+NEUTRAL_SRC1+"}", TABn(1+0+2));
s = line("func{")+
TAB+"(ab}c)"; // test -1 : 0 (corrected)
testEnterEdit(s, PENDING_WS2+NL +"}"+ NEUTRAL_SRCX, TABn(0));
s = line("func{")+
"}blah{)"; // test -1 : 1 (corrected)
testEnterEdit(s, NL +"}"+ NEUTRAL_SRC3, TABn(1));
s = line("func{")+
"}blah{)"; // test -1 : 1 with close, right={)_..
testEnterEdit(s, NL+/*}*/ NEUTRAL_SRC1, TABn(1), expectClose(0+1, "}"));
s = line("func{")+
"}blah{)"; // test -1 : 1 with close, right={)_({..(}
testEnterEdit(s, NL+/*}*/ "({"+NEUTRAL_SRC1+"(}", TABn(1), expectClose(0+1, "}"));
s = line("func{")+
line(TABn(0+4) + "func{()}")+ // test interim lines with irregular ident
TABn(1) + "}blah("; // test close, -1 : 1, right=(_..}
testEnterEdit(s, PENDING_WS2+NL+NEUTRAL_SRC1+"}", TABn(2), expectClose(0+2, ")"));
s = line("func{{){")+ // (corrected)
TAB+"abc}}(}"; // test -3 : 0 (corrected)
testEnterEdit(s, PENDING_TXT+NL+NEUTRAL_SRCX, TABn(0));
s = line("func{({")+ // (corrected on EOF)
TAB+"aaa}})"; // test -3 : 0
testEnterEdit(s, NL+NEUTRAL_SRC3, TABn(0));
s = line("func(")+ // decoy
line(TABn(0+7) + "{func{")+ // (corrected on '{' superblock )
"aaa})";
testEnterEdit(s, NL+NEUTRAL_SRC1, TABn(0+7+1));
// A boundary case, unbalanced close
s = line("func}");
testEnterEdit(s, ""+ NEUTRAL_SRC1, TABn(0));
s = line(TABn(2) + "func}");
testEnterEdit(s, ""+ NEUTRAL_SRC1, TABn(0));
}
/* ---------------------------------------*/
@Test
public void testSmartDeIndent() throws Exception { testSmartDeIndent$(); }
public void testSmartDeIndent$() throws Exception {
testSmartDeIndent$("\n");
testSmartDeIndent$(NL);
}
protected void testSmartDeIndent$(String pNL) {
String s;
int indent = 0;
s = "void main() {";
testDeIndentAutoEdit(s, NL+TAB, pNL+"}");
indent = 1;
s = NEUTRAL_SRC1+
TABn(indent) + "void main{} (";
testDeIndentAutoEdit(s, expectInd(pNL, indent+1), pNL+")");
s = NEUTRAL_SRC1+
TABn(indent) + "void main{({";
testDeIndentAutoEdit(s, expectInd(pNL, indent+3), "{{"+NL+TABn(indent+3+2));
s = NEUTRAL_SRC1+
TABn(indent) + "void main{({"; // Less indent than expected
testDeIndentAutoEdit(s, expectInd(pNL, indent+1), "|{{", false);
s = line("")+
TABn(indent) + "\t\t"; // Test all Whitespace
testDeIndentAutoEdit(s, expectInd(pNL, indent+2), PENDING_WS1+pNL+")");
s = NEUTRAL_SRC1+
""; // Test empty line
testDeIndentAutoEdit(s, expectInd(pNL, 0), PENDING_WS2+pNL+")");
s = NEUTRAL_SRC1+
line(TABn(indent) + "void func{({")+
TABn(indent+1) + "void main()"; // test with 0 : 0 balance
testDeIndentAutoEdit(s, expectInd(pNL, indent+1), PENDING_TXT+pNL+"}");
s = NEUTRAL_SRC3+
TABn(indent) + "void main{{)(";
testDeIndentAutoEdit(s, expectInd(pNL, indent+3), "");
s = "void main() }";
testBackSpaceDeindent(s + NL, TAB, pNL);
// Some boundary cases
testDeIndentAutoEdit("", pNL+"", "");
testDeIndentAutoEdit(TAB, pNL+"", "", false);
testDeIndentAutoEdit(TAB+"func{", pNL+TAB, "", false);
testBackSpaceCommandWithNoEffect(TAB, "" ); // backspace on first line
testBackSpaceCommandWithNoEffect(TAB, "{" );
testBackSpaceCommandWithNoEffect(" ", " {" );
testBackSpaceCommandWithNoEffect(pNL+TAB, TAB+"{" );
testBackSpaceCommandWithNoEffect(TAB+pNL+TAB+TAB, "");
testDeleteCommandWithNoEffect("", pNL);
testDeleteCommandWithNoEffect("", " ");
testDeleteCommandWithNoEffect(TAB, pNL);
testDeleteCommandWithNoEffect(NEUTRAL_SRC1, pNL);
testArtificialNoopCommand("", ""); // Extreme boundary case
testArtificialNoopCommand("", NL);
testArtificialNoopCommand("", TAB);
testArtificialNoopCommand(TAB, NL);
}
protected void testDeIndentAutoEdit(String srcPre, String srcIndent, String sourceAfter) {
testDeIndentAutoEdit(srcPre, srcIndent, sourceAfter, true);
}
protected void testDeIndentAutoEdit(String srcPre, String srcIndent, String sourceAfter,
boolean indentNotSmaller) {
testBackSpaceDeindent(srcPre, srcIndent, sourceAfter);
testDeleteDeindent(srcPre, srcIndent, sourceAfter);
if(indentNotSmaller) {
testBackSpaceCommandWithNoEffect(srcPre + srcIndent +TAB, sourceAfter);
}
String pureIndent = srcIndent.replaceFirst("(\r)?\n", "");
if(pureIndent.length() == 0) {
return; // There is no middle of indent available for further tests
}
// AutoEdit should not apply in the middle of indent element, test that
String srcPre2 = srcPre + srcIndent.substring(0, srcIndent.length()-1);
String srcAfter2 = srcIndent.substring(srcIndent.length()-1, srcIndent.length()) + sourceAfter;
testBackSpaceCommandWithNoEffect(srcPre2, srcAfter2);
int nlSize = srcIndent.length() - pureIndent.length();
String srcPre3 = srcPre + srcIndent.substring(0, nlSize);
String srcAfter3 = srcIndent.substring(nlSize, srcIndent.length()) + sourceAfter;
testDeleteCommandWithNoEffect(srcPre3, srcAfter3);
}
protected void testDeleteDeindent(String srcPre, String srcIndent, String sourceAfter) {
DocumentCommand2 delCommand = applyDelCommand(srcPre, srcIndent + sourceAfter);
getAutoEditStrategy().customizeDocumentCommand(getDocument(), delCommand);
checkCommand(delCommand, "", srcPre.length(), srcIndent.length());
}
protected void testBackSpaceDeindent(String srcPre, String srcIndent, String sourceAfter) {
DocumentCommand2 bsCommand = applyBackSpaceCommand(srcPre + srcIndent, sourceAfter);
getAutoEditStrategy().customizeDocumentCommand(getDocument(), bsCommand);
checkCommand(bsCommand, "", srcPre.length(), srcIndent.length());
}
protected DocumentCommand2 applyBackSpaceCommand(String srcPre, String sourceAfter) {
getDocument().set(srcPre + sourceAfter);
int keypressOffset = srcPre.length();
int length;
try {
IRegion lineInfo = getDocument().getLineInformationOfOffset(keypressOffset);
int lineLimit = lineInfo.getOffset();
int line = getDocument().getLineOfOffset(keypressOffset);
length = (keypressOffset == lineLimit) ? getDocument().getLineDelimiter(line - 1).length() : 1;
} catch (BadLocationException e) {
throw melnorme.utilbox.core.ExceptionAdapter.unchecked(e);
}
lastKeyInfoProvider.lastPressedKey = KeyCommand.BACKSPACE;
DocumentCommand2 docCommand = createDocumentCommand(keypressOffset - length, length, "");
return docCommand;
}
protected DocumentCommand2 applyDelCommand(String sourcePre, String sourceAfter) {
getDocument().set(sourcePre + sourceAfter);
int keypressOffset = sourcePre.length();
int length;
try {
IRegion lineInfo = getDocument().getLineInformationOfOffset(keypressOffset);
int lineEnd = lineInfo.getOffset() + lineInfo.getLength();
int line = getDocument().getLineOfOffset(keypressOffset);
length = (keypressOffset == lineEnd) ? getDocument().getLineDelimiter(line).length() : 1;
} catch (BadLocationException e) {
throw melnorme.utilbox.core.ExceptionAdapter.unchecked(e);
}
lastKeyInfoProvider.lastPressedKey = KeyCommand.DELETE;
DocumentCommand2 docCommand = createDocumentCommand(keypressOffset, length, "");
return docCommand;
}
protected void testBackSpaceCommandWithNoEffect(String sourcePre, String sourceAfter) {
DocumentCommand2 bsCommand = applyBackSpaceCommand(sourcePre, sourceAfter);
testCommandWithNoEffect(bsCommand);
}
protected void testDeleteCommandWithNoEffect(String sourcePre, String sourceAfter) {
DocumentCommand2 delCommand = applyDelCommand(sourcePre, sourceAfter);
testCommandWithNoEffect(delCommand);
}
protected void testCommandWithNoEffect(DocumentCommand2 bsCommand) {
int length = bsCommand.length;
int offset = bsCommand.offset;
String text = bsCommand.text;
getAutoEditStrategy().customizeDocumentCommand(getDocument(), bsCommand);
checkCommand(bsCommand, text, offset, length);
}
protected void testArtificialNoopCommand(String sourcePre, String sourceAfter) {
String text = sourcePre + sourceAfter;
getDocument().set(text);
testCommandWithNoEffect(createDocumentCommand(sourcePre.length(), 0, ""));
testCommandWithNoEffect(createDocumentCommand(sourceAfter.length(), 0, ""));
testCommandWithNoEffect(createDocumentCommand(text.length(), 0, ""));
}
/* ----------------- ----------------- */
@Test
public void testDeindent_onBraceKeypres() throws Exception { testDeindent_onBraceKeypres$(); }
public void testDeindent_onBraceKeypres$() throws Exception {
// No-op case
testAutoEdit_____(line("func() {" + TABn(1)), "", "---", ">", -1, ">");
// A basic case
testBraceKeyPress(
line("func() {"),
TABn(1),
"}");
// Test no deletion happens if beforeCursor is not indent
testBraceKeyPress(
line("func() {") + "\tfoo",
"",
"}");
// Test that ident of block start is used
testBraceKeyPress(
line(TABn(4) + "func{} {"),
TABn(1),
TABn(4) + "}");
}
protected void testBraceKeyPress(String textBefore, String deletedText, String expectedInsert) {
testAutoEdit_____(textBefore, deletedText, "---", expectedInsert, -1, "}");
}
}