Skip to content

Commit fbf55fd

Browse files
Fixed: Fix CSI parameters parsing like for SGR sequences that start with a ; or have sequential ; characters
https://vt100.net/docs/vt510-rm/chapter4.html#S4.3.3 https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences Credits for finding the issue belongs to @Screwtapello mawww/kakoune#4339 (comment) Closes #2272, Closes mawww/kakoune#4339
1 parent 160ab68 commit fbf55fd

File tree

2 files changed

+66
-20
lines changed

2 files changed

+66
-20
lines changed

terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java

+53-20
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ public final class TerminalEmulator {
126126
private String mTitle;
127127
private final Stack<String> mTitleStack = new Stack<>();
128128

129+
/** If processing first character of first parameter of {@link #ESC_CSI}. */
130+
private boolean mIsCSIStart;
131+
/** The last character processed of a parameter of {@link #ESC_CSI}. */
132+
private Integer mLastCSIArg;
129133

130134
/** The cursor position. Between (0,0) and (mRows-1, mColumns-1). */
131135
private int mCursorRow, mCursorCol;
@@ -1386,6 +1390,8 @@ private void doEsc(int b) {
13861390
break;
13871391
case '[':
13881392
continueSequence(ESC_CSI);
1393+
mIsCSIStart = true;
1394+
mLastCSIArg = null;
13891395
break;
13901396
case '=': // DECKPAM
13911397
setDecsetinternalBit(DECSET_BIT_APPLICATION_KEYPAD, true);
@@ -2093,28 +2099,55 @@ private void scrollDownOneLine() {
20932099
}
20942100
}
20952101

2096-
/** Process the next ASCII character of a parameter. */
2097-
private void parseArg(int b) {
2098-
if (b >= '0' && b <= '9') {
2099-
if (mArgIndex < mArgs.length) {
2100-
int oldValue = mArgs[mArgIndex];
2101-
int thisDigit = b - '0';
2102-
int value;
2103-
if (oldValue >= 0) {
2104-
value = oldValue * 10 + thisDigit;
2105-
} else {
2106-
value = thisDigit;
2107-
}
2108-
mArgs[mArgIndex] = value;
2102+
/**
2103+
* Process the next ASCII character of a parameter.
2104+
*
2105+
* Parameter characters modify the action or interpretation of the sequence. You can use up to
2106+
* 16 parameters per sequence. You must use the ; character to separate parameters.
2107+
* All parameters are unsigned, positive decimal integers, with the most significant
2108+
* digit sent first. Any parameter greater than 9999 (decimal) is set to 9999
2109+
* (decimal). If you do not specify a value, a 0 value is assumed. A 0 value
2110+
* or omitted parameter indicates a default value for the sequence. For most
2111+
* sequences, the default value is 1.
2112+
*
2113+
* https://vt100.net/docs/vt510-rm/chapter4.html#S4.3.3
2114+
* */
2115+
private void parseArg(int inputByte) {
2116+
int[] bytes = new int[]{inputByte};
2117+
// Only doing this for ESC_CSI and not for other ESC_CSI_* since they seem to be using their
2118+
// own defaults with getArg*() calls, but there may be missed cases
2119+
if (mEscapeState == ESC_CSI) {
2120+
if ((mIsCSIStart && inputByte == ';') || // If sequence starts with a ; character, like \033[;m
2121+
(!mIsCSIStart && mLastCSIArg != null && mLastCSIArg == ';' && inputByte == ';')) { // If sequence contains sequential ; characters, like \033[;;m
2122+
bytes = new int[]{'0', ';'}; // Assume 0 was passed
21092123
}
2110-
continueSequence(mEscapeState);
2111-
} else if (b == ';') {
2112-
if (mArgIndex < mArgs.length) {
2113-
mArgIndex++;
2124+
}
2125+
2126+
mIsCSIStart = false;
2127+
2128+
for (int b : bytes) {
2129+
if (b >= '0' && b <= '9') {
2130+
if (mArgIndex < mArgs.length) {
2131+
int oldValue = mArgs[mArgIndex];
2132+
int thisDigit = b - '0';
2133+
int value;
2134+
if (oldValue >= 0) {
2135+
value = oldValue * 10 + thisDigit;
2136+
} else {
2137+
value = thisDigit;
2138+
}
2139+
mArgs[mArgIndex] = value;
2140+
}
2141+
continueSequence(mEscapeState);
2142+
} else if (b == ';') {
2143+
if (mArgIndex < mArgs.length) {
2144+
mArgIndex++;
2145+
}
2146+
continueSequence(mEscapeState);
2147+
} else {
2148+
unknownSequence(b);
21142149
}
2115-
continueSequence(mEscapeState);
2116-
} else {
2117-
unknownSequence(b);
2150+
mLastCSIArg = b;
21182151
}
21192152
}
21202153

terminal-emulator/src/test/java/com/termux/terminal/TerminalTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,19 @@ public void testSelectGraphics() {
151151
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
152152
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
153153

154+
// Test CSI resetting to default if sequence starts with ; or has sequential ;;
155+
// Check TerminalEmulator.parseArg()
156+
enterString("\033[31m\033[m");
157+
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
158+
enterString("\033[31m\033[;m");
159+
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
160+
enterString("\033[31m\033[0m");
161+
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
162+
enterString("\033[31m\033[0;m");
163+
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
164+
enterString("\033[31;;m");
165+
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
166+
154167
// 256 colors:
155168
enterString("\033[38;5;119m");
156169
assertEquals(119, mTerminal.mForeColor);

0 commit comments

Comments
 (0)