Commit cd598805 authored by Waqar Ahmed's avatar Waqar Ahmed Committed by Tomaz Canabrava
Browse files

Emulation: change receiveChar to receiveChars

No functional change.

Instead of sending one char at a time through a virtual function, send
all at once and process them in a loop inside the function. The perf
improvement is not that big from this (+100ms), but it lays down path
for more possible optimizations
parent 4ddd6bca
Pipeline #102636 passed with stage
in 1 minute and 54 seconds
......@@ -192,28 +192,30 @@ QString Emulation::keyBindings() const
// process application unicode input to terminal
// this is a trivial scanner
void Emulation::receiveChar(uint c)
void Emulation::receiveChars(const QVector<uint> &chars)
{
c &= 0xff;
switch (c) {
case '\b':
_currentScreen->backspace();
break;
case '\t':
_currentScreen->tab();
break;
case '\n':
_currentScreen->newLine();
break;
case '\r':
_currentScreen->toStartOfLine();
break;
case 0x07:
Q_EMIT bell();
break;
default:
_currentScreen->displayCharacter(c);
break;
for (uint c : chars) {
c &= 0xff;
switch (c) {
case '\b':
_currentScreen->backspace();
break;
case '\t':
_currentScreen->tab();
break;
case '\n':
_currentScreen->newLine();
break;
case '\r':
_currentScreen->toStartOfLine();
break;
case 0x07:
Q_EMIT bell();
break;
default:
_currentScreen->displayCharacter(c);
break;
}
}
}
......@@ -234,9 +236,8 @@ void Emulation::receiveData(const char *text, int length)
bufferedUpdate();
// send characters to terminal emulator
for (const uint i : _decoder->toUnicode(text, length).toUcs4()) {
receiveChar(i);
}
const QVector<uint> chars = _decoder->toUnicode(text, length).toUcs4();
receiveChars(chars);
// look for z-modem indicator
//-- someone who understands more about z-modems that I do may be able to move
......
......@@ -408,7 +408,7 @@ protected:
* Processes an incoming character. See receiveData()
* @p c A unicode character code.
*/
virtual void receiveChar(uint c);
virtual void receiveChars(const QVector<uint> &c);
/**
* Sets the active screen. The terminal has two screens, primary and alternate.
......
......@@ -353,164 +353,166 @@ const int DEL = 127;
const int SP = 32;
// process an incoming unicode character
void Vt102Emulation::receiveChar(uint cc)
void Vt102Emulation::receiveChars(const QVector<uint> &chars)
{
if (cc == DEL) {
return; // VT100: ignore.
}
if (ces(CTL)) {
// ignore control characters in the text part of osc (aka OSC) "ESC]"
// escape sequences; this matches what XTERM docs say
// Allow BEL and ESC here, it will either end the text or be removed later.
if (osc && cc != 0x1b && cc != 0x07) {
return;
for (uint cc : chars) {
if (cc == DEL) {
continue; // VT100: ignore.
}
if (!osc) {
// DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100
// This means, they do neither a resetTokenizer() nor a pushToToken(). Some of them, do
// of course. Guess this originates from a weakly layered handling of the X-on
// X-off protocol, which comes really below this level.
if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) {
resetTokenizer(); // VT100: CAN or SUB
if (ces(CTL)) {
// ignore control characters in the text part of osc (aka OSC) "ESC]"
// escape sequences; this matches what XTERM docs say
// Allow BEL and ESC here, it will either end the text or be removed later.
if (osc && cc != 0x1b && cc != 0x07) {
continue;
}
if (cc != ESC) {
processToken(token_ctl(cc + '@'), 0, 0);
return;
if (!osc) {
// DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100
// This means, they do neither a resetTokenizer() nor a pushToToken(). Some of them, do
// of course. Guess this originates from a weakly layered handling of the X-on
// X-off protocol, which comes really below this level.
if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) {
resetTokenizer(); // VT100: CAN or SUB
}
if (cc != ESC) {
processToken(token_ctl(cc + '@'), 0, 0);
continue;
}
}
}
}
// advance the state
addToCurrentToken(cc);
// advance the state
addToCurrentToken(cc);
uint *s = tokenBuffer;
const int p = tokenBufferPos;
uint *s = tokenBuffer;
const int p = tokenBufferPos;
if (getMode(MODE_Ansi)) {
if (lec(1, 0, ESC)) {
return;
}
if (lec(1, 0, ESC + 128)) {
s[0] = ESC;
receiveChar('[');
return;
}
if (les(2, 1, GRP)) {
return;
}
// Operating System Command
if (p > 2 && s[1] == ']') {
// <ESC> ']' ... <ESC> '\'
if (s[p - 2] == ESC && s[p - 1] == '\\') {
// This runs two times per link, the first prepares the link to be read,
// the second finalizes it. The escape sequence is in two parts
// start: '\e ] 8 ; <id-path> ; <url-part> \e \\'
// end: '\e ] 8 ; ; \e \\'
// GNU libtextstyle inserts the IDs, for instance; many examples
// do not.
if (s[2] == XTERM_EXTENDED::URL_LINK) {
// printf '\e]8;;https://example.com\e\\This is a link\e]8;;\e\\\n'
_currentScreen->urlExtractor()->toggleUrlInput();
}
processSessionAttributeRequest(p - 1);
resetTokenizer();
return;
if (getMode(MODE_Ansi)) {
if (lec(1, 0, ESC)) {
continue;
}
// <ESC> ']' ... <ESC> + one character for reprocessing
if (s[p - 2] == ESC) {
processSessionAttributeRequest(p - 1);
resetTokenizer();
receiveChar(cc);
return;
if (lec(1, 0, ESC + 128)) {
s[0] = ESC;
receiveChars(QVector<uint>{'['});
continue;
}
// <ESC> ']' ... <BEL>
if (s[p - 1] == 0x07) {
processSessionAttributeRequest(p);
resetTokenizer();
return;
if (les(2, 1, GRP)) {
continue;
}
// Operating System Command
if (p > 2 && s[1] == ']') {
// <ESC> ']' ... <ESC> '\'
if (s[p - 2] == ESC && s[p - 1] == '\\') {
// This runs two times per link, the first prepares the link to be read,
// the second finalizes it. The escape sequence is in two parts
// start: '\e ] 8 ; <id-path> ; <url-part> \e \\'
// end: '\e ] 8 ; ; \e \\'
// GNU libtextstyle inserts the IDs, for instance; many examples
// do not.
if (s[2] == XTERM_EXTENDED::URL_LINK) {
// printf '\e]8;;https://example.com\e\\This is a link\e]8;;\e\\\n'
_currentScreen->urlExtractor()->toggleUrlInput();
}
processSessionAttributeRequest(p - 1);
resetTokenizer();
continue;
}
// <ESC> ']' ... <ESC> + one character for reprocessing
if (s[p - 2] == ESC) {
processSessionAttributeRequest(p - 1);
resetTokenizer();
receiveChars(QVector<uint>{cc});
continue;
}
// <ESC> ']' ... <BEL>
if (s[p - 1] == 0x07) {
processSessionAttributeRequest(p);
resetTokenizer();
continue;
}
}
}
/* clang-format off */
// <ESC> ']' ...
if (osc ) { return; }
if (lec(3,2,'?')) { return; }
if (lec(3,2,'=')) { return; }
if (lec(3,2,'>')) { return; }
if (lec(3,2,'!')) { return; }
if (lec(3,2,SP )) { return; }
if (lec(4,3,SP )) { return; }
if (lun( )) { processToken(token_chr(), applyCharset(cc), 0); resetTokenizer(); return; }
if (dcs ) { return; /* TODO We don't xterm DCS, so we just eat it */ }
if (lec(2,0,ESC)) { processToken(token_esc(s[1]), 0, 0); resetTokenizer(); return; }
if (les(3,1,SCS)) { processToken(token_esc_cs(s[1],s[2]), 0, 0); resetTokenizer(); return; }
if (lec(3,1,'#')) { processToken(token_esc_de(s[2]), 0, 0); resetTokenizer(); return; }
if (eps( CPN)) { processToken(token_csi_pn(cc), argv[0],argv[1]); resetTokenizer(); return; }
// resize = \e[8;<row>;<col>t
if (eps(CPS)) {
processToken(token_csi_ps(cc, argv[0]), argv[1], argv[2]);
resetTokenizer();
return;
}
if (epe( )) { processToken(token_csi_pe(cc), 0, 0); resetTokenizer(); return; }
if (esp ( )) { processToken(token_csi_sp(cc), 0, 0); resetTokenizer(); return; }
if (epsp( )) { processToken(token_csi_psp(cc, argv[0]), 0, 0); resetTokenizer(); return; }
if (ees(DIG)) { addDigit(cc-'0'); return; }
if (eec(';')) { addArgument(); return; }
if (ees(INT)) { return; }
if (p >= 3 && cc == 'y' && s[p - 2] == '*') { processChecksumRequest(argc, argv); resetTokenizer(); return; }
for (int i = 0; i <= argc; i++) {
if (epp()) {
processToken(token_csi_pr(cc,argv[i]), 0, 0);
} else if (eeq()) {
processToken(token_csi_pq(cc), 0, 0); // spec. case for ESC[=0c or ESC[=c
} else if (egt()) {
processToken(token_csi_pg(cc), 0, 0); // spec. case for ESC[>0c or ESC[>c
} else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2)
{
// ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
i += 2;
processToken(token_csi_ps(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]);
i += 2;
} else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5) {
// ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
i += 2;
processToken(token_csi_ps(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
} else if (p < 2 || (charClass[s[p-2]] & (INT)) != (INT)) {
processToken(token_csi_ps(cc,argv[i]), 0, 0);
}
}
resetTokenizer();
/* clang-format on */
} else {
// VT52 Mode
if (lec(1, 0, ESC)) {
return;
}
if (les(1, 0, CHR)) {
processToken(token_chr(), s[0], 0);
/* clang-format off */
// <ESC> ']' ...
if (osc ) { continue; }
if (lec(3,2,'?')) { continue; }
if (lec(3,2,'=')) { continue; }
if (lec(3,2,'>')) { continue; }
if (lec(3,2,'!')) { continue; }
if (lec(3,2,SP )) { continue; }
if (lec(4,3,SP )) { continue; }
if (lun( )) { processToken(token_chr(), applyCharset(cc), 0); resetTokenizer(); continue; }
if (dcs ) { continue; /* TODO We don't xterm DCS, so we just eat it */ }
if (lec(2,0,ESC)) { processToken(token_esc(s[1]), 0, 0); resetTokenizer(); continue; }
if (les(3,1,SCS)) { processToken(token_esc_cs(s[1],s[2]), 0, 0); resetTokenizer(); continue; }
if (lec(3,1,'#')) { processToken(token_esc_de(s[2]), 0, 0); resetTokenizer(); continue; }
if (eps( CPN)) { processToken(token_csi_pn(cc), argv[0],argv[1]); resetTokenizer(); continue; }
// resize = \e[8;<row>;<col>t
if (eps(CPS)) {
processToken(token_csi_ps(cc, argv[0]), argv[1], argv[2]);
resetTokenizer();
return;
}
if (lec(2, 1, 'Y')) {
return;
continue;
}
if (lec(3, 1, 'Y')) {
return;
if (epe( )) { processToken(token_csi_pe(cc), 0, 0); resetTokenizer(); continue; }
if (esp ( )) { processToken(token_csi_sp(cc), 0, 0); resetTokenizer(); continue; }
if (epsp( )) { processToken(token_csi_psp(cc, argv[0]), 0, 0); resetTokenizer(); continue; }
if (ees(DIG)) { addDigit(cc-'0'); continue; }
if (eec(';')) { addArgument(); continue; }
if (ees(INT)) { continue; }
if (p >= 3 && cc == 'y' && s[p - 2] == '*') { processChecksumRequest(argc, argv); resetTokenizer(); continue; }
for (int i = 0; i <= argc; i++) {
if (epp()) {
processToken(token_csi_pr(cc,argv[i]), 0, 0);
} else if (eeq()) {
processToken(token_csi_pq(cc), 0, 0); // spec. case for ESC[=0c or ESC[=c
} else if (egt()) {
processToken(token_csi_pg(cc), 0, 0); // spec. case for ESC[>0c or ESC[>c
} else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2)
{
// ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
i += 2;
processToken(token_csi_ps(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]);
i += 2;
} else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5) {
// ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
i += 2;
processToken(token_csi_ps(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
} else if (p < 2 || (charClass[s[p-2]] & (INT)) != (INT)) {
processToken(token_csi_ps(cc,argv[i]), 0, 0);
}
}
if (p < 4) {
processToken(token_vt52(s[1]), 0, 0);
resetTokenizer();
/* clang-format on */
} else {
// VT52 Mode
if (lec(1, 0, ESC)) {
continue;
}
if (les(1, 0, CHR)) {
processToken(token_chr(), s[0], 0);
resetTokenizer();
continue;
}
if (lec(2, 1, 'Y')) {
continue;
}
if (lec(3, 1, 'Y')) {
continue;
}
if (p < 4) {
processToken(token_vt52(s[1]), 0, 0);
resetTokenizer();
continue;
}
processToken(token_vt52(s[1]), s[2], s[3]);
resetTokenizer();
return;
continue;
}
processToken(token_vt52(s[1]), s[2], s[3]);
resetTokenizer();
return;
}
}
......
......@@ -86,7 +86,7 @@ protected:
// reimplemented from Emulation
void setMode(int mode) override;
void resetMode(int mode) override;
void receiveChar(uint cc) override;
void receiveChars(const QVector<uint> &chars) override;
private Q_SLOTS:
// Causes sessionAttributeChanged() to be emitted for each (int,QString)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment