Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/src/com/jediterm/terminal/Terminal.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ public interface Terminal {

void setTabStopAtCursor();

int previousTab(int position);

int nextTab(int position);

void writeUnwrappedString(String string);

void setTerminalOutput(@Nullable TerminalOutputStream terminalOutput);
Expand Down
31 changes: 31 additions & 0 deletions core/src/com/jediterm/terminal/emulator/JediEmulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@ private boolean processControlSequence(ControlSequence args) {
case 'f':
case 'H': //CUP
return cursorPosition(args);
case 'I': //CHT
return cursorForwardTab(args.getArg(0, 1));
case 'J': //DECSED
return eraseInDisplay(args);
case 'K': //EL
Expand All @@ -482,6 +484,8 @@ private boolean processControlSequence(ControlSequence args) {
return scrollUp(args);
case 'T': //SD
return scrollDown(args);
case 'Z': //CBT
return cursorBackwardTab(args.getArg(0, 1));
case 'c': //Send Device Attributes (Primary DA)
if (args.startsWithMoreMark()) { //Send Device Attributes (Secondary DA)
return sendSecondaryDeviceAttributes(args);
Expand Down Expand Up @@ -1177,4 +1181,31 @@ private void setModeEnabled(final TerminalMode mode, final boolean enabled) {
public void setMouseMode(MouseMode mouseMode) {
myTerminal.setMouseMode(mouseMode);
}

private boolean cursorBackwardTab(int count) {
if (count == 0) count = 1;
int curX = myTerminal.getCursorX() - 1;
for (int i = 0; i < count && curX > 0; i++) {
curX = myTerminal.previousTab(curX);
if (curX < 0) {
curX = 0;
}
}
myTerminal.cursorPosition(curX + 1, myTerminal.getCursorY());
return true;
}

private boolean cursorForwardTab(int count) {
if (count == 0) count = 1;
int curX = myTerminal.getCursorX() - 1;
int width = myTerminal.getTerminalWidth();
for (int i = 0; i < count && curX < width - 1; i++) {
curX = myTerminal.nextTab(curX);
if (curX >= width) {
curX = width - 1;
}
}
myTerminal.cursorPosition(curX + 1, myTerminal.getCursorY());
return true;
}
}
10 changes: 10 additions & 0 deletions core/src/com/jediterm/terminal/model/JediTerminal.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,16 @@ public void horizontalTab() {
myDisplay.setCursor(myCursorX, myCursorY);
}

@Override
public int previousTab(int position) {
return myTabulator.previousTab(position);
}

@Override
public int nextTab(int position) {
return myTabulator.nextTab(position);
}

@Override
public void eraseInDisplay(final int arg) {
// ED (Erase in Display) https://vt100.net/docs/vt510-rm/ED.html
Expand Down
22 changes: 22 additions & 0 deletions core/tests/src/com/jediterm/EmulatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,28 @@ public void testNoScrollWhenOutsideScrollRegion() throws IOException {
));
}

public void testCursorBackwardTab() throws IOException {
TestSession session = new TestSession(24, 3);
session.process("\u001b[1;1H"); // move cursor to column 1
session.process("\t"); // tab to column 9
session.process("\t"); // tab to column 17
session.assertCursorPosition(17, 1);
session.process("\u001b[Z"); // CBT: back one tab stop
session.assertCursorPosition(9, 1);
session.process("\u001b[2Z"); // CBT: back two tab stops
session.assertCursorPosition(1, 1);
}

public void testCursorForwardTab() throws IOException {
TestSession session = new TestSession(24, 3);
session.process("\u001b[1;1H"); // move cursor to column 1
session.assertCursorPosition(1, 1);
session.process("\u001b[I"); // CHT: forward one tab stop
session.assertCursorPosition(9, 1);
session.process("\u001b[2I"); // CHT: forward two tab stops
session.assertCursorPosition(24, 1); // clamped at terminal width (last column)
}

private void assertScreenLines(@NotNull TestSession session, @NotNull List<String> expectedScreenLines) {
Assert.assertEquals(expectedScreenLines, TerminalLinesUtilKt.getLineTexts(session.getTerminalTextBuffer().getScreenLinesStorage()));
}
Expand Down
Loading