Skip to content

Instantly share code, notes, and snippets.

@tyru
Last active January 9, 2018 16:32
Show Gist options
  • Select an option

  • Save tyru/1f71fdd2a15fcb4a9dc40f5796394a29 to your computer and use it in GitHub Desktop.

Select an option

Save tyru/1f71fdd2a15fcb4a9dc40f5796394a29 to your computer and use it in GitHub Desktop.
Struggling with ANSI escape code: https://en.wikipedia.org/wiki/ANSI_escape_code
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <termios.h>
#include <unistd.h>
#define ESC "\x1b"
#define CSI "\x1b\x5b"
#define CSILEN 2
void out(const char* str) {
printf("%s", str);
fflush(stdout);
}
void outc(const char c) {
printf("%c", c);
fflush(stdout);
}
void outf(const char* fmt, ...) {
va_list arg;
va_start(arg, fmt);
vprintf(fmt, arg);
va_end(arg);
fflush(stdout);
}
void escup(int n) {
outf(CSI "%dA", n);
}
void escdown(int n) {
outf(CSI "%dB", n);
}
void escright(int n) {
outf(CSI "%dC", n);
}
void escleft(int n) {
outf(CSI "%dD", n);
}
void escsave() {
out(ESC "7");
}
void escrestore() {
out(ESC "8");
}
size_t read_until(char *p, size_t size, int in_fd, char end) {
size_t i = 0;
char buf[1] = {0};
while (i + 1 < size) {
switch (read(in_fd, buf, 1)) {
case -1: // TODO: handle error
case 0:
goto end;
}
p[i] = buf[0];
i++;
if (buf[0] == end) {
break;
}
}
end:
p[i] = '\0';
return i + 1;
}
void sleep_msec(long msec) {
struct timespec ts;
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000 * 1000;
nanosleep(&ts, NULL);
}
void get_cursor(int* x, int* y) {
*x = *y = 0;
outf(CSI "6n");
char buf[32] = {0};
read_until(buf, sizeof(buf), STDIN_FILENO, 'R');
char *p = buf;
p += CSILEN;
while (*p != ';') {
if (!isdigit(*p)) {
goto error;
}
*x = *x * 10 + (*p - '0');
p++;
}
p++;
while (*p != 'R') {
if (!isdigit(*p)) {
goto error;
}
*y = *y * 10 + (*p - '0');
p++;
}
return;
error:
*x = *y = -1;
}
void demo_bars() {
const int line = 3;
for (int width = 1; width <= 80; width++) {
escsave();
for (int i = 0; i < line; i++) {
if (width > 1) {
escright(width - 1);
}
out("*\n");
}
escrestore();
sleep_msec(30);
}
escdown(line);
}
void demo_get_cursor() {
// https://stackoverflow.com/a/8101262/6321251
struct termios ttystate, ttysave;
tcgetattr(STDIN_FILENO, &ttystate);
ttysave = ttystate;
ttystate.c_lflag &= ~(ICANON | ECHO);
ttystate.c_cc[VMIN] = 1;
ttystate.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
out("あえいうえおあお");
int x, y;
get_cursor(&x, &y);
tcsetattr(STDIN_FILENO, TCSANOW, &ttysave);
// y should be 17
outf("(%d, %d)\n", x, y);
}
int main(int argc, char const* argv[])
{
// demo_bars();
demo_get_cursor();
return 0;
}
@tyru

tyru commented Jan 9, 2018

Copy link
Copy Markdown
Author

@tyru

tyru commented Jan 9, 2018

Copy link
Copy Markdown
Author

read(2) blocks even when non-canonical mode (min=1) on Vim's :terminal. it seems bug maybe vim-jp/issues#1140

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment