Skip to content

Commit f35063d

Browse files
fornwallagnostic-apollo
authored andcommitted
Fixed: Parse (but ignore for now) terminal APC sequences
1 parent 043923e commit f35063d

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

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

+40
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public final class TerminalEmulator {
7979
private static final int ESC_CSI_SINGLE_QUOTE = 18;
8080
/** Escape processing: CSI ! */
8181
private static final int ESC_CSI_EXCLAMATION = 19;
82+
/** Escape processing: "ESC _" or Application Program Command (APC). */
83+
private static final int ESC_APC = 20;
84+
/** Escape processing: "ESC _" or Application Program Command (APC), followed by Escape. */
85+
private static final int ESC_APC_ESCAPE = 21;
8286

8387
/** The number of parameter arguments. This name comes from the ANSI standard for terminal escape codes. */
8488
private static final int MAX_ESCAPE_PARAMETERS = 16;
@@ -545,6 +549,15 @@ private void processByte(byte byteToProcess) {
545549
}
546550

547551
public void processCodePoint(int b) {
552+
// The Application Program-Control (APC) string might be arbitrary non-printable characters, so handle that early.
553+
if (mEscapeState == ESC_APC) {
554+
doApc(b);
555+
return;
556+
} else if (mEscapeState == ESC_APC_ESCAPE) {
557+
doApcEscape(b);
558+
return;
559+
}
560+
548561
switch (b) {
549562
case 0: // Null character (NUL, ^@). Do nothing.
550563
break;
@@ -1001,6 +1014,30 @@ private void doDeviceControl(int b) {
10011014
}
10021015
}
10031016

1017+
/**
1018+
* When in {@link #ESC_APC} (APC, Application Program Command) sequence.
1019+
*/
1020+
private void doApc(int b) {
1021+
if (b == 27) {
1022+
continueSequence(ESC_APC_ESCAPE);
1023+
}
1024+
// Eat APC sequences silently for now.
1025+
}
1026+
1027+
/**
1028+
* When in {@link #ESC_APC} (APC, Application Program Command) sequence.
1029+
*/
1030+
private void doApcEscape(int b) {
1031+
if (b == '\\') {
1032+
// A String Terminator (ST), ending the APC escape sequence.
1033+
finishSequence();
1034+
} else {
1035+
// The Escape character was not the start of a String Terminator (ST),
1036+
// but instead just data inside of the APC escape sequence.
1037+
continueSequence(ESC_APC);
1038+
}
1039+
}
1040+
10041041
private int nextTabStop(int numTabs) {
10051042
for (int i = mCursorCol + 1; i < mColumns; i++)
10061043
if (mTabStop[i] && --numTabs == 0) return Math.min(i, mRightMargin);
@@ -1396,6 +1433,9 @@ private void doEsc(int b) {
13961433
case '>': // DECKPNM
13971434
setDecsetinternalBit(DECSET_BIT_APPLICATION_KEYPAD, false);
13981435
break;
1436+
case '_': // APC - Application Program Command.
1437+
continueSequence(ESC_APC);
1438+
break;
13991439
default:
14001440
unknownSequence(b);
14011441
break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.termux.terminal;
2+
3+
public class ApcTest extends TerminalTestCase {
4+
5+
public void testApcConsumed() {
6+
// At time of writing this is part of what yazi sends for probing for kitty graphics protocol support:
7+
// https://github.com/sxyazi/yazi/blob/0cdaff98d0b3723caff63eebf1974e7907a43a2c/yazi-adapter/src/emulator.rs#L129
8+
// This should not result in anything being written to the screen: If kitty graphics protocol support
9+
// is implemented it should instead result in an error code on stdin, and if not it should be consumed
10+
// silently just as xterm does. See https://sw.kovidgoyal.net/kitty/graphics-protocol/.
11+
withTerminalSized(2, 2)
12+
.enterString("\033_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\033\\")
13+
.assertLinesAre(" ", " ");
14+
15+
// It is ok for the APC content to be non printable characters:
16+
withTerminalSized(12, 2)
17+
.enterString("hello \033_some\023\033_\\apc#end\033\\ world")
18+
.assertLinesAre("hello world", " ");
19+
}
20+
21+
}

0 commit comments

Comments
 (0)