While studying the ANSI control sequences I came across unclear behaviour.
I tried to make "matrix" effect in terminal, which changes one random digit per loop iteration in a row of n 0/1 digits:
#include <iostream>
#include <chrono>
#include <thread>
const int n = 5; // row length
const int pause = 50; // milliseconds
int main() {
using namespace std;
using this_thread::sleep_for;
using chrono::milliseconds;
for (int i = 0; i < n; i++) {
cout << rand() % 2;
}
int offset;
while (true) {
offset = rand() % n + 1; // random digit in row 1..n
cout << "\x1b[" << offset << "D";
cout.flush();
sleep_for(milliseconds(pause));
cout << rand() % 2;
cout.flush();
// cout << "\x1b[" << 1 << "D";
// cout.flush();
sleep_for(milliseconds(pause));
cout << "\x1b[" << offset - 1 << "C";
cout.flush();
sleep_for(milliseconds(pause));
}
}
As far as I understand CSI offset D moves cursor back offset times if it's possible in current row, then I cout
random digit, that moves cursor 1 time forward, then I use CSI offset - 1 C to move it forward offset - 1 times, that should return cursor to n + 1 row position, so n digits go before cursor, but sometimes it goes further than n + 1, so, after several iterations it ends up at the end of the row. I would like to know why it happens.
However, when I use cout << "\x1b[" << 1 << "D";
and then cout << "\x1b[" << offset << "C";
instead of cout << "\x1b[" << offset - 1 << "C";
it works fine.
I'm also aware of using CSI n G, which also works fine, but I want to understand what's going on with CSI n C/D . Maybe it's my maths fault, but not using cout << "\x1b[" << 1 << "D";
seems to be equivalent of using cout << "\x1b[" << offset - 1 << "C";
so it's really confusing to me.
It seems that \x1b[0C
moves cursor to the right, at least on my terminal, (dunno if that is specified/required behavior).
$ printf "a\x1b[0Cb\n"
a b
$ printf "a\x1b[1Cb\n"
a b
Check if offset - 1
is not zero.
if (offset - 1) {
cout << "\x1b[" << offset - 1 << "C";
}