Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Reimplemented paragraph text object

  • Loading branch information...
commit f093f9906c7c34bb71c6c0983c689b9e54e3ae66 1 parent b24910a
@modosist modosist authored
View
165 net.sourceforge.vrapper.core.tests/src/net/sourceforge/vrapper/core/tests/cases/NormalModeTests.java
@@ -586,6 +586,169 @@ public void test_dt() {
}
@Test
+ public void test_dap() {
+ // "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac"
+ checkCommand(forKeySeq("dap"),
+ "",'1',"ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dap"),
+ "1ac\n",'\n',"3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n",'\n'," \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n",'7',"ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n",'4',"ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n",'7',"ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n",'1',"1ac\n12ac");
+
+ // Special cases for file end sections ("do nothing")
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac\n",'\n',"\n",
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac\n",'\n',"\n");
+
+ checkCommand(forKeySeq("dap"),
+ "\n\n\n",'f',"oo\nbar\n\n\n\n",
+ "\n\n\n",EOF,"");
+ checkCommand(forKeySeq("dap"),
+ "\n",'\n',"",
+ "\n",'\n',"");
+ checkCommand(forKeySeq("dap"),
+ "hello\n",'w',"orld",
+ "",EOF,"");
+ checkCommand(forKeySeq("dap"),
+ "hello\n",'w',"orld\n",
+ "",EOF,"");
+ checkCommand(forKeySeq("dap"),
+ "",'\n',"\nhello\nworld\n",
+ "",EOF,"");
+ checkCommand(forKeySeq("dap"),
+ "\n\n",'h',"ello\nworld",
+ "",EOF,"");
+ checkCommand(forKeySeq("dap"),
+ "",'h',"ello",
+ "",EOF,"");
+ checkCommand(forKeySeq("dap"),
+ "",EOF,"",
+ "",EOF,"");
+
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n",' '," \n\n11ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac");
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n",'\n',"11ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac");
+
+ // Special cases for file end sections
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n",'1',"1ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac");
+ checkCommand(forKeySeq("dap"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n",'1',"2ac",
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac");
+ }
+
+ @Test
+ public void test_2dap() {
+ checkCommand(forKeySeq("2dap"),
+ "",'1',"ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "",'7',"ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("2dap"),
+ "1ac\n",'\n',"3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n",'\n'," \n\n11ac\n12ac");
+ checkCommand(forKeySeq("2dap"),
+ "1ac\n\n",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n",'1',"1ac\n12ac");
+
+ checkCommand(forKeySeq("2dap"),
+ "1ac\n\n3ac\n4ac\n",'\n'," \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n3ac\n",'4',"ac");
+ checkCommand(forKeySeq("2dap"),
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n3ac\n",'4',"ac");
+ }
+
+ @Test
+ public void test_dip() {
+ checkCommand(forKeySeq("dip"),
+ "",'1',"ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "",'\n',"3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dip"),
+ "1ac\n",'\n',"3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dip"),
+ "1ac\n\n",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n",'\n'," \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dip"),
+ "1ac\n\n3ac\n",'4',"ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n",'\n'," \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("dip"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n",' '," \n\n11ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n",'1',"1ac\n12ac");
+
+ // Special cases for file end sections
+ checkCommand(forKeySeq("dip"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n",'1',"1ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n",'1',"2ac",
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n",EOF,"");
+
+ checkCommand(forKeySeq("dip"),
+ "\n\n\n",'f',"oo\nbar\n\n\n\n",
+ "\n\n\n",'\n',"\n\n");
+ checkCommand(forKeySeq("dip"),
+ "\n",'\n',"",
+ "",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "hello\n",'w',"orld",
+ "",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "hello\n",'w',"orld\n",
+ "",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "\n\n",'h',"ello\nworld",
+ "\n",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "",'h',"ello",
+ "",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "",EOF,"",
+ "",EOF,"");
+
+ // Cases for buffers with EOL at the end
+ checkCommand(forKeySeq("dip"),
+ "\n\n",'h',"ello\nworld\n",
+ "\n\n",EOF,"");
+ checkCommand(forKeySeq("dip"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac\n",'\n',"\n",
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac\n",EOF,"");
+ }
+
+ @Test
+ public void test_2dip() {
+ checkCommand(forKeySeq("2dip"),
+ "",'1',"ac\n\n3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("2dip"),
+ "1ac\n",'\n',"3ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n",'\n'," \n7ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("2dip"),
+ "1ac\n\n",'3',"ac\n4ac\n\n \n7ac\n\n \n\n11ac\n12ac",
+ "1ac\n\n",'7',"ac\n\n \n\n11ac\n12ac");
+ checkCommand(forKeySeq("2dip"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n",'\n'," \n\n11ac\n12ac",
+ "1ac\n\n3ac\n4ac\n\n \n",'7',"ac");
+
+ // Cases for buffers with EOL at the end
+ checkCommand(forKeySeq("2dip"),
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n",'\n'," \n\n11ac\n12ac\n",
+ "1ac\n\n3ac\n4ac\n\n \n7ac\n",EOF,"");
+ }
+
+ @Test
public void test_gq_mergeLines() {
//Some of these tests move the cursor when they shouldn't;
//some of these tests append a newline when they shouldn't.
@@ -693,7 +856,7 @@ public void test_gq_splitLines() {
"/* this",' ',"line will be split multiple times */",
"", '/', "* this\n* line\n* will\n* be\n* split\n* multiple\n* times\n* */\n");
}
-
+
@Test
public void testSurroundPlugin_ds() {
when(platform.getPlatformSpecificStateProvider()).thenReturn(SurroundStateProvider.INSTANCE);
View
17 net.sourceforge.vrapper.core/src/net/sourceforge/vrapper/utils/VimUtils.java
@@ -93,6 +93,23 @@ public static boolean isPatternDelimiter(String s) {
public static boolean isBlank(String s) {
return s == null || s.trim().equals("");
}
+
+ /**
+ * @return true, if line contains only whitespace characters
+ */
+ public static boolean isLineBlank(TextContent content, int lineNo) {
+ LineInformation line = content.getLineInformation(lineNo);
+ return VimUtils.isBlank(content.getText(line.getBeginOffset(), line.getLength()));
+ }
+
+ /**
+ * @return true, if the last character in the text buffer is newline
+ */
+ public static boolean endsWithEOL(EditorAdaptor editor) {
+ TextContent content = editor.getModelContent();
+ LineInformation line = content.getLineInformation(content.getNumberOfLines() - 1);
+ return line.getNumber() > 0 && line.getLength() == 0;
+ }
/**
* Calculates an offset position. Line breaks are not counted.
View
16 net.sourceforge.vrapper.core/src/net/sourceforge/vrapper/vim/commands/SelectTextObjectCommand.java
@@ -22,7 +22,21 @@ public void execute(EditorAdaptor editorAdaptor, int count) throws CommandExecut
switch (textObject.getContentType(editorAdaptor.getConfiguration())) {
case TEXT_RECTANGLE: throw new UnsupportedOperationException("rectangular selection");
case LINES:
- selection = new LineWiseSelection(editorAdaptor, region.getStart(), region.getEnd());
+ /**
+ * TODO: ugly casting. The problem is, that if textObject already
+ * returns a LineWiseSelection, then by creating new instance of
+ * LineWiseSelection from the old one we extend the selected range
+ * by one line. This is due implementation of LineWiseSelection,
+ * whose getEnd() points to the line AFTER the actual selection. It
+ * might be solved by refactoring TextRange with introduction of
+ * linewise range (by line numbers)
+ */
+ if (region instanceof LineWiseSelection) {
+ selection = (LineWiseSelection) region;
+ }
+ else {
+ selection = new LineWiseSelection(editorAdaptor, region.getStart(), region.getEnd());
+ }
newMode = LinewiseVisualMode.NAME;
break;
case TEXT:
View
7 net.sourceforge.vrapper.core/src/net/sourceforge/vrapper/vim/commands/SimpleTextOperation.java
@@ -8,7 +8,12 @@
public void execute(EditorAdaptor editorAdaptor, int count, TextObject textObject)
throws CommandExecutionException {
- execute(editorAdaptor, textObject.getRegion(editorAdaptor, count), textObject.getContentType(editorAdaptor.getConfiguration()));
+ TextRange range = textObject.getRegion(editorAdaptor, count);
+
+ // Some text objects may (for some cases) decide to do nothing (e.g. ParagraphTextObject)
+ if (range != null) {
+ execute(editorAdaptor, range, textObject.getContentType(editorAdaptor.getConfiguration()));
+ }
}
public abstract void execute(EditorAdaptor editorAdaptor, TextRange region,
View
182 net.sourceforge.vrapper.core/src/net/sourceforge/vrapper/vim/commands/motions/ParagraphMotion.java
@@ -1,27 +1,22 @@
package net.sourceforge.vrapper.vim.commands.motions;
+import static net.sourceforge.vrapper.utils.VimUtils.isLineBlank;
+import net.sourceforge.vrapper.platform.Configuration;
import net.sourceforge.vrapper.platform.TextContent;
+import net.sourceforge.vrapper.utils.ContentType;
import net.sourceforge.vrapper.utils.LineInformation;
import net.sourceforge.vrapper.utils.Position;
+import net.sourceforge.vrapper.utils.TextRange;
+import net.sourceforge.vrapper.utils.VimUtils;
import net.sourceforge.vrapper.vim.EditorAdaptor;
+import net.sourceforge.vrapper.vim.commands.AbstractTextObject;
import net.sourceforge.vrapper.vim.commands.BorderPolicy;
import net.sourceforge.vrapper.vim.commands.CommandExecutionException;
+import net.sourceforge.vrapper.vim.commands.LineWiseSelection;
public class ParagraphMotion extends CountAwareMotion {
public static final ParagraphMotion FORWARD = new ParagraphMotion(true);
public static final ParagraphMotion BACKWARD = new ParagraphMotion(false);
- public static final ParagraphMotion TO_FORWARD = new ParagraphMotion(true) {
- protected int moveMore(TextContent modelContent, int lineNo) {
- while (isInRange(modelContent, lineNo) && isLineEmpty(modelContent, lineNo))
- lineNo += step;
- return lineNo;
- };
- };
- public static final ParagraphMotion TO_BACKWARD = new ParagraphMotion(false) {
- public Position destination(EditorAdaptor editorAdaptor, int count) throws CommandExecutionException {
- return super.destination(editorAdaptor, count).addModelOffset(1);
- };
- };
protected final int step;
@@ -77,7 +72,7 @@ private boolean doesLineEmptinessEqual(boolean equalWhat, TextContent content, i
boolean isEmpty = content.getLineInformation(lineNo).getLength() == 0;
return isEmpty == equalWhat;
}
-
+
public BorderPolicy borderPolicy() {
return BorderPolicy.EXCLUSIVE;
}
@@ -86,4 +81,163 @@ public boolean updateStickyColumn() {
return true;
}
-}
+ public static class ParagraphTextObject extends AbstractTextObject {
+
+ private boolean outer;
+
+ public ParagraphTextObject(boolean outer) {
+ super();
+ this.outer = outer;
+ }
+
+ public TextRange getRegion(EditorAdaptor editorAdaptor, int count)
+ throws CommandExecutionException {
+ if (count == NO_COUNT_GIVEN) {
+ count = 1;
+ }
+
+ // EOL "lines" at the end of the text buffer will be of the same
+ // type (blank, non-blank) as the previous line
+ boolean endsWithEOL = VimUtils.endsWithEOL(editorAdaptor);
+
+ TextContent content = editorAdaptor.getModelContent();
+ int startLineNo = content.getLineInformationOfOffset(editorAdaptor.getPosition().getModelOffset()).getNumber();
+ if (endsWithEOL && startLineNo > 0 &&
+ (startLineNo + 1) == content.getNumberOfLines()) {
+ startLineNo--;
+ }
+
+ boolean cursorOnBlank = isLineBlank(content, startLineNo);
+ while (startLineNo > 0) {
+ boolean upperLineIsBlank = isLineBlank(content, startLineNo - 1);
+ if (cursorOnBlank ^ upperLineIsBlank) {
+ break;
+ }
+
+ startLineNo--;
+ }
+
+ // Either a special case for blank lines in the last section of
+ // file, or fail case (in both cases, the cursor remain in the
+ // same position)
+ boolean doNothing = false;
+ int endLineNo = startLineNo;
+ if (outer) {
+ boolean noMoreRepeat = false;
+ for (int i = count; i > 0; i--) {
+ if (noMoreRepeat) {
+ // Fail
+ doNothing = true;
+ break;
+ }
+ else {
+ // if cursorOnBlank==true, then eat blanks
+ // if cursorOnBlank==false, then eat non-blanks
+ while ((endLineNo + 1) < content.getNumberOfLines() &&
+ (!cursorOnBlank || isLineBlank(content, endLineNo + 1)) &&
+ (cursorOnBlank || !isLineBlank(content, endLineNo + 1)))
+ endLineNo++;
+
+ if (endsWithEOL && (endLineNo + 2) == content.getNumberOfLines()) {
+ endLineNo++;
+ }
+
+ if ((endLineNo + 1) >= content.getNumberOfLines()) {
+ if (cursorOnBlank) {
+ doNothing = true;
+ noMoreRepeat = true;
+ }
+ else {
+ // This is a special case, where we eat blank
+ // lines above the current start line
+ while (startLineNo > 0) {
+ if (!isLineBlank(content, startLineNo - 1)) {
+ break;
+ }
+
+ startLineNo--;
+ }
+
+ noMoreRepeat = true;
+ }
+ }
+
+ if ((endLineNo + 1) < content.getNumberOfLines()) {
+ endLineNo++;
+
+ // if cursorOnBlank==true, then eat non-blanks
+ // if cursorOnBlank==false, then eat blanks
+ while ((endLineNo + 1) < content.getNumberOfLines() &&
+ (!cursorOnBlank || !isLineBlank(content, endLineNo + 1)) &&
+ (cursorOnBlank || isLineBlank(content, endLineNo + 1)))
+ endLineNo++;
+
+ if ((endLineNo + 1) >= content.getNumberOfLines()) {
+ noMoreRepeat = true;
+ } else {
+ endLineNo++;
+ }
+ }
+ }
+ }
+ }
+ else {
+ boolean isCurrentSectionBlank = cursorOnBlank;
+ boolean noMoreRepeat = false;
+ for (int i = count; i > 0; i--) {
+ if (noMoreRepeat) {
+ // Fail
+ doNothing = true;
+ break;
+ }
+ else {
+ while (true) {
+ if ((endLineNo + 1) >= content.getNumberOfLines()) {
+ noMoreRepeat = true;
+ break;
+ }
+
+ if (endsWithEOL && (endLineNo + 2) == content.getNumberOfLines()) {
+ endLineNo++;
+ }
+ else {
+ boolean lowerLineIsBlank = isLineBlank(content, endLineNo + 1);
+ if (isCurrentSectionBlank ^ lowerLineIsBlank) {
+ break;
+ }
+ else {
+ endLineNo++;
+ }
+ }
+ }
+
+ isCurrentSectionBlank = !isCurrentSectionBlank;
+ }
+ }
+
+ if ((endLineNo + 1) < content.getNumberOfLines()) {
+ endLineNo++;
+ }
+ }
+
+ if (doNothing) {
+ return null;
+ }
+
+ // if endLineNo is not pointing at the last line of the buffer, then
+ // it is always pointing one line after the selected paragraph, so
+ // we decrement it
+ if ((endLineNo + 1) < content.getNumberOfLines() && endLineNo > 0) {
+ endLineNo--;
+ }
+
+ Position startPos = editorAdaptor.getPosition().setModelOffset(content.getLineInformation(startLineNo).getBeginOffset());
+ Position endPos = editorAdaptor.getPosition().setModelOffset(content.getLineInformation(endLineNo).getEndOffset()); ;
+ return new LineWiseSelection(editorAdaptor, startPos, endPos);
+ }
+
+ public ContentType getContentType(Configuration configuration) {
+ return ContentType.LINES;
+ }
+ }
+}
View
10 net.sourceforge.vrapper.core/src/net/sourceforge/vrapper/vim/modes/LinewiseVisualMode.java
@@ -8,8 +8,10 @@
import net.sourceforge.vrapper.keymap.vim.VisualMotionState;
import net.sourceforge.vrapper.keymap.vim.VisualMotionState.Motion2VMC;
import net.sourceforge.vrapper.utils.CaretType;
+import net.sourceforge.vrapper.utils.ContentType;
import net.sourceforge.vrapper.utils.Position;
import net.sourceforge.vrapper.vim.EditorAdaptor;
+import net.sourceforge.vrapper.vim.LocalConfiguration;
import net.sourceforge.vrapper.vim.Options;
import net.sourceforge.vrapper.vim.commands.ChangeModeCommand;
import net.sourceforge.vrapper.vim.commands.ChangeToSearchModeCommand;
@@ -72,9 +74,11 @@ public String getDisplayName() {
@Override
protected void fixSelection() {
Selection selection = editorAdaptor.getSelection();
- Position start = selection.getStart();
- Position end = selection.getEnd();
- editorAdaptor.setSelection(new LineWiseSelection(editorAdaptor, start, end));
+ if (!selection.getContentType(editorAdaptor.getConfiguration()).equals(ContentType.LINES)) {
+ Position start = selection.getStart();
+ Position end = selection.getEnd();
+ editorAdaptor.setSelection(new LineWiseSelection(editorAdaptor, start, end));
+ }
}
}
View
5 net.sourceforge.vrapper.core/src/net/sourceforge/vrapper/vim/modes/NormalMode.java
@@ -88,6 +88,7 @@
import net.sourceforge.vrapper.vim.commands.motions.MoveWordRight;
import net.sourceforge.vrapper.vim.commands.motions.MoveWordRightForUpdate;
import net.sourceforge.vrapper.vim.commands.motions.ParagraphMotion;
+import net.sourceforge.vrapper.vim.commands.motions.ParagraphMotion.ParagraphTextObject;
import net.sourceforge.vrapper.vim.modes.commandline.CommandLineMode;
public class NormalMode extends CommandBasedMode {
@@ -174,8 +175,8 @@ protected KeyMapResolver buildKeyMapResolver() {
final TextObject aWord = new MotionPairTextObject(MoveWordLeft.BAILS_OFF, MoveWordRight.BAILS_OFF);
final TextObject innerWORD = new MotionPairTextObject(MoveBigWORDLeft.BAILS_OFF, MoveBigWORDEndRight.BAILS_OFF);
final TextObject aWORD = new MotionPairTextObject(MoveBigWORDLeft.BAILS_OFF, MoveBigWORDRight.BAILS_OFF);
- final TextObject innerParagraph = new MotionPairTextObject(ParagraphMotion.TO_BACKWARD, ParagraphMotion.FORWARD);
- final TextObject aParagraph = new MotionPairTextObject(ParagraphMotion.TO_BACKWARD, ParagraphMotion.TO_FORWARD);
+ final TextObject innerParagraph = new ParagraphTextObject(false);
+ final TextObject aParagraph = new ParagraphTextObject(true);
textObjects = union(
state(
Please sign in to comment.
Something went wrong with that request. Please try again.