Skip to content

Commit

Permalink
Fixed: Parse (but ignore for now) terminal APC sequences
Browse files Browse the repository at this point in the history
  • Loading branch information
fornwall committed Sep 17, 2024
1 parent c2d57f2 commit 8acc8cc
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ public final class TerminalEmulator {
private static final int ESC_CSI_SINGLE_QUOTE = 18;
/** Escape processing: CSI ! */
private static final int ESC_CSI_EXCLAMATION = 19;
/** Escape processing: "ESC _" or Application Program Command (APC). */
private static final int ESC_APC = 20;
/** Escape processing: "ESC _" or Application Program Command (APC), following by an Escape. */
private static final int ESC_APC_ESCAPE = 21;

/** The number of parameter arguments. This name comes from the ANSI standard for terminal escape codes. */
private static final int MAX_ESCAPE_PARAMETERS = 16;
Expand Down Expand Up @@ -548,6 +552,15 @@ private void processByte(byte byteToProcess) {
}

public void processCodePoint(int b) {
// The Application Program-Control (APC) string might be arbitrary non-printable characters, so handle that early.
if (mEscapeState == ESC_APC) {
doApc(b);
return;
} else if (mEscapeState == ESC_APC_ESCAPE) {
doApcEscape(b);
return;
}

switch (b) {
case 0: // Null character (NUL, ^@). Do nothing.
break;
Expand Down Expand Up @@ -1004,6 +1017,30 @@ private void doDeviceControl(int b) {
}
}

/**
* When in {@link #ESC_APC} (APC, Application Program Command) sequence.
*/
private void doApc(int b) {
if (b == 27) {
continueSequence(ESC_APC_ESCAPE);
}
// Eat APC sequences silently for now.
}

/**
* When in {@link #ESC_APC} (APC, Application Program Command) sequence.
*/
private void doApcEscape(int b) {
if (b == '\\') {
// A String Terminator (ST), ending the APC escape sequence.
finishSequence();
} else {
// The Escape character was not the start of a String Terminator (ST),
// but instead just data inside of the APC escape sequence.
continueSequence(ESC_APC);
}
}

private int nextTabStop(int numTabs) {
for (int i = mCursorCol + 1; i < mColumns; i++)
if (mTabStop[i] && --numTabs == 0) return Math.min(i, mRightMargin);
Expand Down Expand Up @@ -1399,6 +1436,9 @@ private void doEsc(int b) {
case '>': // DECKPNM
setDecsetinternalBit(DECSET_BIT_APPLICATION_KEYPAD, false);
break;
case '_': // APC - Application Program Command.
continueSequence(ESC_APC);
break;
default:
unknownSequence(b);
break;
Expand Down
21 changes: 21 additions & 0 deletions terminal-emulator/src/test/java/com/termux/terminal/ApcTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.termux.terminal;

public class ApcTest extends TerminalTestCase {

public void testApcConsumed() {
// At time of writing this is part of what yazi sends for probing for kitty graphics protocol support:
// https://github.com/sxyazi/yazi/blob/0cdaff98d0b3723caff63eebf1974e7907a43a2c/yazi-adapter/src/emulator.rs#L129
// This should not result in anything being written to the screen: If kitty graphics protocol support
// is implemented it should instead result in an error code on stdin, and if not it should be consumed
// silently just as xterm does. See https://sw.kovidgoyal.net/kitty/graphics-protocol/.
withTerminalSized(2, 2)
.enterString("\033_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\033\\")
.assertLinesAre(" ", " ");

// It is ok for the APC content to be non printable characters:
withTerminalSized(12, 2)
.enterString("hello \033_some\023\033_\\apc#end\033\\ world")
.assertLinesAre("hello world", " ");
}

}

0 comments on commit 8acc8cc

Please sign in to comment.