diff --git a/cowterm.c b/cowterm.c index d534d58..fed3046 100644 --- a/cowterm.c +++ b/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;