Skip to content

Commit 8e1b67b

Browse files
committedDec 25, 2020
Generalize cursor movement
1 parent d386c6a commit 8e1b67b

File tree

3 files changed

+155
-8
lines changed

3 files changed

+155
-8
lines changed
 

‎pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@
318318
<dependencies>
319319
<dependency>
320320
<groupId>org.junit.jupiter</groupId>
321-
<artifactId>junit-jupiter-engine</artifactId>
321+
<artifactId>junit-jupiter</artifactId>
322322
<version>5.7.0</version>
323323
<scope>test</scope>
324324
</dependency>

‎src/main/java/org/fusesource/jansi/Ansi.java

+73-7
Original file line numberDiff line numberDiff line change
@@ -556,46 +556,112 @@ public Ansi a(Attribute attribute) {
556556
*
557557
* @param row row (1-based) from top
558558
* @param column column (1 based) from left
559-
* @return Ansi
559+
* @return this Ansi instance
560560
*/
561561
public Ansi cursor(final int row, final int column) {
562562
return appendEscapeSequence('H', row, column);
563563
}
564564

565+
/**
566+
* Moves the cursor to column n. If n is negative it is not moved.
567+
*
568+
* @param x the index of the column to move to
569+
* @return this Ansi instance
570+
*/
565571
public Ansi cursorToColumn(final int x) {
566572
return x >= 0 ? appendEscapeSequence('G', x) : this;
567573
}
568574

575+
/**
576+
* Moves the cursor up. If the parameter y is negative it moves the cursor down.
577+
*
578+
* @param y the number of lines to move up
579+
* @return this Ansi instance
580+
*/
569581
public Ansi cursorUp(final int y) {
570-
return appendEscapeSequence('A', y);
582+
return y > 0 ? appendEscapeSequence('A', y) : y < 0 ? cursorDown(-y) : this;
571583
}
572584

585+
/**
586+
* Moves the cursor down. If the parameter y is negative it moves the cursor up.
587+
*
588+
* @param y the number of lines to move down
589+
* @return this Ansi instance
590+
*/
573591
public Ansi cursorDown(final int y) {
574-
return y > 0 ? appendEscapeSequence('B', y) : this;
592+
return y > 0 ? appendEscapeSequence('B', y) : y < 0 ? cursorUp(-y) : this;
575593
}
576594

595+
/**
596+
* Moves the cursor right. If the parameter x is negative it moves the cursor left.
597+
*
598+
* @param x the number of characters to move right
599+
* @return this Ansi instance
600+
*/
577601
public Ansi cursorRight(final int x) {
578-
return x > 0 ? appendEscapeSequence('C', x) : this;
602+
return x > 0 ? appendEscapeSequence('C', x) : x < 0 ? cursorLeft(-x) : this;
579603
}
580604

605+
/**
606+
* Moves the cursor left. If the parameter x is negative it moves the cursor right.
607+
*
608+
* @param x the number of characters to move left
609+
* @return this Ansi instance
610+
*/
581611
public Ansi cursorLeft(final int x) {
582-
return x > 0 ? appendEscapeSequence('D', x) : this;
612+
return x > 0 ? appendEscapeSequence('D', x) : x < 0 ? cursorRight(-x) : this;
613+
}
614+
615+
/**
616+
* Moves the cursor relative to the current position. The cursor is moved right if x is
617+
* positive, left if negative and down if y is positive and up if negative.
618+
*
619+
* @param x the number of characters to move horizontally
620+
* @param y the number of lines to move vertically
621+
* @return this Ansi instance
622+
*/
623+
public Ansi cursorMove(final int x, final int y) {
624+
return cursorRight(x).cursorDown(y);
583625
}
584626

627+
/**
628+
* Moves the cursor to the beginning of the line below.
629+
*
630+
* @return this Ansi instance
631+
*/
585632
public Ansi cursorDownLine() {
586633
return appendEscapeSequence('E');
587634
}
588635

636+
/**
637+
* Moves the cursor to the beginning of the n-th line below. If the parameter n is negative it
638+
* moves the cursor to the beginning of the n-th line above.
639+
*
640+
* @param n the number of lines to move the cursor
641+
* @return this Ansi instance
642+
*/
589643
public Ansi cursorDownLine(final int n) {
590-
return n > 0 ? appendEscapeSequence('E', n) : this;
644+
return n > 0 ? appendEscapeSequence('E', n) : n < 0 ? cursorUpLine(-n) : this;
591645
}
592646

647+
/**
648+
* Moves the cursor to the beginning of the line above.
649+
*
650+
* @return this Ansi instance
651+
*/
593652
public Ansi cursorUpLine() {
594653
return appendEscapeSequence('F');
595654
}
596655

656+
/**
657+
* Moves the cursor to the beginning of the n-th line above. If the parameter n is negative it
658+
* moves the cursor to the beginning of the n-th line below.
659+
*
660+
* @param n the number of lines to move the cursor
661+
* @return this Ansi instance
662+
*/
597663
public Ansi cursorUpLine(final int n) {
598-
return n > 0 ? appendEscapeSequence('F', n) : this;
664+
return n > 0 ? appendEscapeSequence('F', n) : n < 0 ? cursorDownLine(-n) : this;
599665
}
600666

601667
public Ansi eraseScreen() {

‎src/test/java/org/fusesource/jansi/AnsiTest.java

+81
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import org.fusesource.jansi.Ansi.Color;
1919
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.params.ParameterizedTest;
21+
import org.junit.jupiter.params.provider.CsvSource;
2022

2123
import static org.junit.jupiter.api.Assertions.assertEquals;
2224

@@ -52,4 +54,83 @@ public void testClone() throws CloneNotSupportedException {
5254

5355
assertEquals(ansi.a("test").reset().toString(), clone.a("test").reset().toString());
5456
}
57+
58+
@ParameterizedTest
59+
@CsvSource({
60+
"-1,-1,ESC[-1;-1H", "-1,0,ESC[-1;0H", "-1,1,ESC[-1;1H", "-1,2,ESC[-1;2H",
61+
"0,-1,ESC[0;-1H", "0,0,ESC[0;0H", "0,1,ESC[0;1H", "0,2,ESC[0;2H",
62+
"1,-1,ESC[1;-1H", "1,0,ESC[1;0H", "1,1,ESC[1;1H", "1,2,ESC[1;2H",
63+
"2,-1,ESC[2;-1H", "2,0,ESC[2;0H", "2,1,ESC[2;1H", "2,2,ESC[2;2H"
64+
})
65+
public void testCursor(int x, int y, String expected) {
66+
assertAnsi(expected, new Ansi().cursor(x, y));
67+
}
68+
69+
@ParameterizedTest
70+
@CsvSource({"-2,''", "-1,''", "0,ESC[0G", "1,ESC[1G", "2,ESC[2G"})
71+
public void testCursorToColumn(int x, String expected) {
72+
assertAnsi(expected, new Ansi().cursorToColumn(x));
73+
}
74+
75+
@ParameterizedTest
76+
@CsvSource({"-2,ESC[2B", "-1,ESC[1B", "0,''", "1,ESC[1A", "2,ESC[2A"})
77+
public void testCursorUp(int y, String expected) {
78+
assertAnsi(expected, new Ansi().cursorUp(y));
79+
}
80+
81+
@ParameterizedTest
82+
@CsvSource({"-2,ESC[2A", "-1,ESC[1A", "0,''", "1,ESC[1B", "2,ESC[2B"})
83+
public void testCursorDown(int y, String expected) {
84+
assertAnsi(expected, new Ansi().cursorDown(y));
85+
}
86+
87+
@ParameterizedTest
88+
@CsvSource({"-2,ESC[2D", "-1,ESC[1D", "0,''", "1,ESC[1C", "2,ESC[2C"})
89+
public void testCursorRight(int x, String expected) {
90+
assertAnsi(expected, new Ansi().cursorRight(x));
91+
}
92+
93+
@ParameterizedTest
94+
@CsvSource({"-2,ESC[2C", "-1,ESC[1C", "0,''", "1,ESC[1D", "2,ESC[2D"})
95+
public void testCursorLeft(int x, String expected) {
96+
assertAnsi(expected, new Ansi().cursorLeft(x));
97+
}
98+
99+
@ParameterizedTest
100+
@CsvSource({
101+
"-2,-2,ESC[2DESC[2A", "-2,-1,ESC[2DESC[1A", "-2,0,ESC[2D", "-2,1,ESC[2DESC[1B", "-2,2,ESC[2DESC[2B",
102+
"-1,-2,ESC[1DESC[2A", "-1,-1,ESC[1DESC[1A", "-1,0,ESC[1D", "-1,1,ESC[1DESC[1B", "-1,2,ESC[1DESC[2B",
103+
"0,-2,ESC[2A", "0,-1,ESC[1A", "0,0,''", "0,1,ESC[1B", "0,2,ESC[2B",
104+
"1,-2,ESC[1CESC[2A", "1,-1,ESC[1CESC[1A", "1,0,ESC[1C", "1,1,ESC[1CESC[1B", "1,2,ESC[1CESC[2B",
105+
"2,-2,ESC[2CESC[2A", "2,-1,ESC[2CESC[1A", "2,0,ESC[2C", "2,1,ESC[2CESC[1B", "2,2,ESC[2CESC[2B"
106+
})
107+
public void testCursorMove(int x, int y, String expected) {
108+
assertAnsi(expected, new Ansi().cursorMove(x, y));
109+
}
110+
111+
@Test
112+
public void testCursorDownLine() {
113+
assertAnsi("ESC[E", new Ansi().cursorDownLine());
114+
}
115+
116+
@ParameterizedTest
117+
@CsvSource({"-2,ESC[2F", "-1,ESC[1F", "0,''", "1,ESC[1E", "2,ESC[2E"})
118+
public void testCursorDownLine(int n, String expected) {
119+
assertAnsi(expected, new Ansi().cursorDownLine(n));
120+
}
121+
122+
@Test
123+
public void testCursorUpLine() {
124+
assertAnsi("ESC[F", new Ansi().cursorUpLine());
125+
}
126+
127+
@ParameterizedTest
128+
@CsvSource({"-2,ESC[2E", "-1,ESC[1E", "0,''", "1,ESC[1F", "2,ESC[2F"})
129+
public void testCursorUpLine(int n, String expected) {
130+
assertAnsi(expected, new Ansi().cursorUpLine(n));
131+
}
132+
133+
private static void assertAnsi(String expected, Ansi actual) {
134+
assertEquals(expected.replace("ESC", "\033"), actual.toString());
135+
}
55136
}

0 commit comments

Comments
 (0)
Please sign in to comment.