From 229c55c9e2cdcd41ffa4400b7ce4444bd9efbad1 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Wed, 19 Jun 2024 14:11:12 -0400 Subject: [PATCH] Add support for String Terminator to be ESC \ This fixes support to properly identify the end of OSC control sequences which can be terminated with a BEL or ESC \. Fixes https://github.com/eclipse-cdt/cdt/issues/831 --- .../terminal/emulator/VT100Emulator.java | 19 +++++++++- .../terminal/emulator/VT100EmulatorTest.java | 37 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java index af7eadd8254..e75a0f6d75d 100644 --- a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java @@ -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. @@ -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. diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorTest.java index b32128bf928..66aa5941f0c 100644 --- a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorTest.java +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorTest.java @@ -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"; } @@ -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())); + } + }