Skip to content

Commit

Permalink
Add support for String Terminator to be ESC \
Browse files Browse the repository at this point in the history
This fixes support to properly identify the end of
OSC control sequences which can be terminated
with a BEL or ESC \.

Fixes #831
  • Loading branch information
jonahgraham committed Jun 20, 2024
1 parent ba16b70 commit 229c55c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public class VT100Emulator implements ControlListener {
*/
private static final int ANSISTATE_EXPECTING_CHARSET_DESIGNATION = 5;

/**
* For cases where the OSC (OS Command) ends with a multi-byte ST (i.e. ESC \)
* we use this extra state.
*/
private static final int ANSISTATE_EXPECTING_OS_COMMAND_END = 6;

/**
* This field holds the current state of the Finite TerminalState Automaton (FSA)
* that recognizes ANSI escape sequences.
Expand Down Expand Up @@ -428,16 +434,27 @@ private void processNewText() throws IOException {
break;

case ANSISTATE_EXPECTING_OS_COMMAND:
// A BEL (\u0007) character marks the end of the OSC sequence.
// A BEL (\u0007) or ESC \ ('\e\\') character marks the end of the OSC sequence.

if (character == '\u0007') {
ansiState = ANSISTATE_INITIAL;
processAnsiOsCommand();
} else if (character == '\u001b') {
ansiState = ANSISTATE_EXPECTING_OS_COMMAND_END;
} else {
ansiOsCommand.append(character);
}
break;

case ANSISTATE_EXPECTING_OS_COMMAND_END:
ansiState = ANSISTATE_INITIAL;
if (character == '\\') {
processAnsiOsCommand();
} else {
Logger.log("Unsupported escape sequence: escape '" + ansiOsCommand + " \\e" + character + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
break;

case ANSISTATE_EXPECTING_DEC_PRIVATE_COMMAND:
// Parameters can appear after the '[?' in an escape sequence, but they
// are optional.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,18 @@ public class VT100EmulatorTest {
private static final String CLEAR_ENTIRE_SCREEN = "\033[2J";
private static final String SCROLL_REVERSE = "\033M";

private static String TITLE(String title) {
private static String TITLE_ST_BEL(String title) {
return "\033]0;" + title + "\007";
}

private static String TITLE_ST_ESC_BACKSLASH(String title) {
return "\033]0;" + title + "\033\\";
}

private static String TITLE(String title) {
return TITLE_ST_BEL(title);
}

private static String SCROLL_REGION(int startRow, int endRow) {
return "\033[" + startRow + ";" + endRow + "r";
}
Expand Down Expand Up @@ -340,4 +348,31 @@ public void testScrollReverseScrollingRegion() {
assertAll(() -> assertCursorLocation(2, expected.get(2).length()), () -> assertTextEquals(expected));
}

@Test
public void testStringTerminator() {
run( //
TITLE_ST_BEL("TITLE1"), //
"HELLO1", //
TITLE_ST_ESC_BACKSLASH("TITLE2"), //
"HELLO2", //
TITLE_ST_BEL("TITLE3"), //
"HELLO3", //
TITLE_ST_ESC_BACKSLASH("TITLE4") //
);
assertAll(() -> assertTextEquals("HELLO1HELLO2HELLO3"),
() -> assertEquals(List.of("TITLE1", "TITLE2", "TITLE3", "TITLE4"), control.getAllTitles()));
}

@Test
public void testMalformedStringTerminator() {
run( //
TITLE_ST_ESC_BACKSLASH("TITLE1"), //
"\033]0;" + "TITLE1" + "\033X", //
TITLE_ST_ESC_BACKSLASH("TITLE2"), //
"HELLO" //
);
assertAll(() -> assertTextEquals("HELLO"),
() -> assertEquals(List.of("TITLE1", "TITLE2"), control.getAllTitles()));
}

}

0 comments on commit 229c55c

Please sign in to comment.