ANSI Escape Code Handling
Better handling of ANSI Escape Code Handling
This commit is contained in:
parent
a044864f92
commit
264f53a342
237
cowterm.c
237
cowterm.c
@ -365,33 +365,14 @@ static void draw_terminal(Display *display, Window window) {
|
||||
if (!terminal_buffer || !color_buffer || !attr_buffer)
|
||||
return;
|
||||
|
||||
if (buffer_pixmap == None)
|
||||
buffer_pixmap = XCreatePixmap(
|
||||
display, DefaultRootWindow(display), term_cols * CHAR_WIDTH,
|
||||
term_rows * CHAR_HEIGHT, DefaultDepth(display, DefaultScreen(display)));
|
||||
XSetForeground(display, gc, current_bg_color);
|
||||
XFillRectangle(display, buffer_pixmap, gc, 0, 0, term_cols * CHAR_WIDTH,
|
||||
term_rows * CHAR_HEIGHT);
|
||||
|
||||
if (needs_refresh) {
|
||||
int start_y = scroll_top ? scroll_top - 1 : 0;
|
||||
int end_y = scroll_bottom ? scroll_bottom : term_rows;
|
||||
|
||||
if (end_y > term_rows) {
|
||||
end_y = term_rows;
|
||||
}
|
||||
|
||||
if (scroll_top == 0 && scroll_bottom == 0) {
|
||||
// Full screen refresh
|
||||
for (int y = 0; y < term_rows; y++) {
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
draw_char(display, buffer_pixmap, x, y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Only refresh scroll region
|
||||
for (int y = start_y; y < end_y; y++) {
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
draw_char(display, buffer_pixmap, x, y);
|
||||
}
|
||||
}
|
||||
// Draw all characters
|
||||
for (int y = 0; y < term_rows; y++) {
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
draw_char(display, buffer_pixmap, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -745,6 +726,19 @@ static unsigned long get_bright_ansi_color(int index) {
|
||||
// P.S. yes I had to google this up
|
||||
static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
Window window) {
|
||||
if (*idx + 1 < max_len) {
|
||||
// Skip CSI sequences that we don't need to process
|
||||
if (buf[*idx] == '\033' && buf[*idx + 1] == '(') {
|
||||
*idx += 2;
|
||||
return;
|
||||
}
|
||||
// Skip other common terminal sequences
|
||||
if (buf[*idx] == '\033' && strchr("=>", buf[*idx + 1])) {
|
||||
*idx += 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char num_buf[32] = {0};
|
||||
int params[32] = {0};
|
||||
size_t num_idx = 0;
|
||||
@ -911,15 +905,76 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
}
|
||||
} break;
|
||||
case 'K': // Clear line
|
||||
for (int i = cursor_x; i < term_cols; i++) {
|
||||
terminal_buffer[cursor_y][i] = ' ';
|
||||
color_buffer[cursor_y][i] = current_color;
|
||||
attr_buffer[cursor_y][i] = current_attr;
|
||||
bg_color_buffer[cursor_y][i] = current_bg_color;
|
||||
switch (params[0]) {
|
||||
case 0: // Clear from cursor to end of line
|
||||
for (int x = cursor_x; x < term_cols; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
break;
|
||||
case 1: // Clear from cursor to beginning of line
|
||||
for (int x = 0; x <= cursor_x; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
break;
|
||||
case 2: // Clear entire line
|
||||
memset(terminal_buffer[cursor_y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
break;
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case 'J': // Clear screen
|
||||
if (params[0] == 2) {
|
||||
switch (params[0]) {
|
||||
case 0: // Clear from cursor to end of screen
|
||||
// Clear current line from cursor
|
||||
for (int x = cursor_x; x < term_cols; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
// Clear all lines below cursor
|
||||
for (int y = cursor_y + 1; y < term_rows; y++) {
|
||||
memset(terminal_buffer[y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
color_buffer[y][x] = current_color;
|
||||
attr_buffer[y][x] = current_attr;
|
||||
bg_color_buffer[y][x] = current_bg_color;
|
||||
}
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case 1: // Clear from cursor to beginning of screen
|
||||
// Clear current line up to cursor
|
||||
for (int x = 0; x <= cursor_x; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
// Clear all lines above cursor
|
||||
for (int y = 0; y < cursor_y; y++) {
|
||||
memset(terminal_buffer[y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
color_buffer[y][x] = current_color;
|
||||
attr_buffer[y][x] = current_attr;
|
||||
bg_color_buffer[y][x] = current_bg_color;
|
||||
}
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case 2: // Clear entire screen
|
||||
case 3: // Clear entire screen and scrollback (treat same as 2)
|
||||
current_color = XWhitePixel(display, DefaultScreen(display));
|
||||
current_bg_color = XBlackPixel(display, DefaultScreen(display));
|
||||
current_attr = 0;
|
||||
@ -932,6 +987,7 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
}
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'r': // Set scrolling region
|
||||
@ -1051,56 +1107,81 @@ static int master_cb(int fd, void *data, Window window) {
|
||||
if (n <= 0)
|
||||
return 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (buf[i] == '\033' && i + 1 < n && buf[i + 1] == '[') {
|
||||
parse_ansi_code(buf, &i, n, window);
|
||||
continue;
|
||||
}
|
||||
switch (buf[i]) {
|
||||
case '\n':
|
||||
cursor_x = 0;
|
||||
if (++cursor_y >= term_rows) {
|
||||
scroll_region_up(1);
|
||||
cursor_y = term_rows - 1;
|
||||
if (buf[i] == '\033') {
|
||||
if (i + 1 < n && buf[i + 1] == '[') {
|
||||
parse_ansi_code(buf, &i, n, window);
|
||||
continue;
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case '\r':
|
||||
cursor_x = 0;
|
||||
break;
|
||||
case '\b':
|
||||
if (cursor_x > 0) {
|
||||
cursor_x--;
|
||||
terminal_buffer[cursor_y][cursor_x] = ' ';
|
||||
color_buffer[cursor_y][cursor_x] = current_color;
|
||||
attr_buffer[cursor_y][cursor_x] = current_attr;
|
||||
bg_color_buffer[cursor_y][cursor_x] = current_bg_color;
|
||||
needs_refresh = 1;
|
||||
} else if (cursor_y > 0) {
|
||||
cursor_y--;
|
||||
cursor_x = term_cols - 1;
|
||||
while (cursor_x > 0 && terminal_buffer[cursor_y][cursor_x - 1] == ' ')
|
||||
cursor_x--;
|
||||
needs_refresh = 1;
|
||||
if (i + 1 < n && (buf[i + 1] == '(' || buf[i + 1] == ')')) {
|
||||
if (i + 2 < n) {
|
||||
i += 2; // Skip ESC, (, and the character set identifier
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (cursor_y >= term_rows || cursor_x >= term_cols)
|
||||
break;
|
||||
if (buf[i] >= 32 && buf[i] <= 126) {
|
||||
terminal_buffer[cursor_y][cursor_x] = buf[i];
|
||||
color_buffer[cursor_y][cursor_x] = current_color;
|
||||
attr_buffer[cursor_y][cursor_x] = current_attr;
|
||||
bg_color_buffer[cursor_y][cursor_x] = current_bg_color;
|
||||
needs_refresh = 1;
|
||||
if (++cursor_x >= term_cols) {
|
||||
cursor_x = 0;
|
||||
if (++cursor_y >= term_rows) {
|
||||
scroll_region_up(1);
|
||||
cursor_y = term_rows - 1;
|
||||
}
|
||||
// Handle other simple escape sequences
|
||||
if (i + 1 < n) {
|
||||
switch (buf[i + 1]) {
|
||||
case '=': // Application keypad
|
||||
case '>': // Normal keypad
|
||||
case '7': // Save cursor position
|
||||
case '8': // Restore cursor position
|
||||
case 'E': // Next line
|
||||
case 'M': // Reverse line feed
|
||||
i++; // Skip the command character
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if ((buf[i] >= 32 && buf[i] <= 126) || buf[i] == '\n' || buf[i] == '\r' ||
|
||||
buf[i] == '\b' || buf[i] == '\t') {
|
||||
switch (buf[i]) {
|
||||
case '\n':
|
||||
cursor_x = 0;
|
||||
if (++cursor_y >= term_rows) {
|
||||
scroll_region_up(1);
|
||||
cursor_y = term_rows - 1;
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case '\r':
|
||||
cursor_x = 0;
|
||||
break;
|
||||
case '\b':
|
||||
if (cursor_x > 0) {
|
||||
cursor_x--;
|
||||
terminal_buffer[cursor_y][cursor_x] = ' ';
|
||||
color_buffer[cursor_y][cursor_x] = current_color;
|
||||
attr_buffer[cursor_y][cursor_x] = current_attr;
|
||||
bg_color_buffer[cursor_y][cursor_x] = current_bg_color;
|
||||
needs_refresh = 1;
|
||||
} else if (cursor_y > 0) {
|
||||
cursor_y--;
|
||||
cursor_x = term_cols - 1;
|
||||
while (cursor_x > 0 && terminal_buffer[cursor_y][cursor_x - 1] == ' ')
|
||||
cursor_x--;
|
||||
needs_refresh = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (cursor_y >= term_rows || cursor_x >= term_cols)
|
||||
break;
|
||||
if ((buf[i] >= 32 && buf[i] <= 126) || buf[i] == '\t') {
|
||||
terminal_buffer[cursor_y][cursor_x] = buf[i];
|
||||
color_buffer[cursor_y][cursor_x] = current_color;
|
||||
attr_buffer[cursor_y][cursor_x] = current_attr;
|
||||
bg_color_buffer[cursor_y][cursor_x] = current_bg_color;
|
||||
needs_refresh = 1;
|
||||
if (++cursor_x >= term_cols) {
|
||||
cursor_x = 0;
|
||||
if (++cursor_y >= term_rows) {
|
||||
scroll_region_up(1);
|
||||
cursor_y = term_rows - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor_visible = 1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user