Attempt to fix scrolling in vim

Atleast now it can "emulate" scrolling
This commit is contained in:
Rekketstone 2025-01-16 13:55:08 -07:00
parent 8bed0e9d52
commit 1ad881ba60

299
cowterm.c
View File

@ -1,3 +1,4 @@
#include <X11/X.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/keysym.h> #include <X11/keysym.h>
@ -40,6 +41,8 @@ static Pixmap buffer_pixmap = None;
static int master_fd = -1; static int master_fd = -1;
static int needs_refresh = 0; static int needs_refresh = 0;
static int window_focused = 0; static int window_focused = 0;
static int scroll_top = 0; // 0 means entire terminal
static int scroll_bottom = 0; // 0 means entire terminal
// Cursor stuff // Cursor stuff
static int cursor_visible = 1; static int cursor_visible = 1;
@ -435,6 +438,233 @@ static void scroll_up(void) {
needs_refresh = 1; needs_refresh = 1;
} }
static void scroll_region_up(int amount) {
char **temp_buffer = NULL;
unsigned long **temp_color_buffer = NULL;
int **temp_attr_buffer = NULL;
unsigned long **temp_bg_color_buffer = NULL;
temp_buffer = malloc(term_rows * sizeof(char *));
temp_color_buffer = malloc(term_rows * sizeof(unsigned long *));
temp_attr_buffer = malloc(term_rows * sizeof(int *));
temp_bg_color_buffer = malloc(term_rows * sizeof(unsigned long *));
if (!temp_buffer || !temp_color_buffer || !temp_attr_buffer ||
!temp_bg_color_buffer) {
fprintf(stderr, "Failed to allocate memory for temp buffers\n");
return;
}
for (int i = 0; i < term_rows; i++) {
temp_buffer[i] = malloc(term_cols * sizeof(char));
temp_color_buffer[i] = malloc(term_cols * sizeof(unsigned long));
temp_attr_buffer[i] = malloc(term_cols * sizeof(int));
temp_bg_color_buffer[i] = malloc(term_cols * sizeof(unsigned long));
if (!temp_buffer[i] || !temp_color_buffer[i] || !temp_attr_buffer[i] ||
!temp_bg_color_buffer[i]) {
fprintf(stderr, "Failed to allocate memory for temp buffer row\n");
free(temp_buffer);
free(temp_color_buffer);
free(temp_attr_buffer);
free(temp_bg_color_buffer);
return;
}
}
if (scroll_top == 0 && scroll_bottom == 0) {
for (int i = 0; i < term_rows; i++) {
memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char));
memcpy(temp_color_buffer[i], color_buffer[i],
term_cols * sizeof(unsigned long));
memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int));
memcpy(temp_bg_color_buffer[i], bg_color_buffer[i],
term_cols * sizeof(unsigned long));
}
for (int j = 0; j < amount; j++) {
// Move all lines up one position
for (int y = 0; y < term_rows - 1; y++) {
memcpy(terminal_buffer[y], temp_buffer[y + 1], term_cols);
memcpy(color_buffer[y], temp_color_buffer[y + 1],
term_cols * sizeof(unsigned long));
memcpy(attr_buffer[y], temp_attr_buffer[y + 1],
term_cols * sizeof(int));
memcpy(bg_color_buffer[y], temp_bg_color_buffer[y + 1],
term_cols * sizeof(unsigned long));
}
// Clear the bottom line
memset(terminal_buffer[term_rows - 1], ' ', term_cols);
for (int x = 0; x < term_cols; x++) {
color_buffer[term_rows - 1][x] = current_color;
attr_buffer[term_rows - 1][x] = current_attr;
bg_color_buffer[term_rows - 1][x] = current_bg_color;
}
}
} else {
for (int i = 0; i < term_rows; i++) {
memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char));
memcpy(temp_color_buffer[i], color_buffer[i],
term_cols * sizeof(unsigned long));
memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int));
memcpy(temp_bg_color_buffer[i], bg_color_buffer[i],
term_cols * sizeof(unsigned long));
}
for (int j = 0; j < amount; j++) {
int start = (scroll_top - 1);
int end = (scroll_bottom - 1);
if (start < 0)
start = 0;
if (end < 0)
end = 0;
if (end >= term_rows)
end = term_rows - 1;
// Move all lines up one position
for (int y = start; y < end; y++) {
memcpy(terminal_buffer[y], temp_buffer[y + 1], term_cols);
memcpy(color_buffer[y], temp_color_buffer[y + 1],
term_cols * sizeof(unsigned long));
memcpy(attr_buffer[y], temp_attr_buffer[y + 1],
term_cols * sizeof(int));
memcpy(bg_color_buffer[y], temp_bg_color_buffer[y + 1],
term_cols * sizeof(unsigned long));
}
// Clear the bottom line
memset(terminal_buffer[end], ' ', term_cols);
for (int x = 0; x < term_cols; x++) {
color_buffer[end][x] = current_color;
attr_buffer[end][x] = current_attr;
bg_color_buffer[end][x] = current_bg_color;
}
}
}
for (int i = 0; i < term_rows; i++) {
free(temp_buffer[i]);
free(temp_color_buffer[i]);
free(temp_attr_buffer[i]);
free(temp_bg_color_buffer[i]);
}
free(temp_buffer);
free(temp_color_buffer);
free(temp_attr_buffer);
free(temp_bg_color_buffer);
needs_refresh = 1;
}
static void scroll_region_down(int amount) {
char **temp_buffer = NULL;
unsigned long **temp_color_buffer = NULL;
int **temp_attr_buffer = NULL;
unsigned long **temp_bg_color_buffer = NULL;
temp_buffer = malloc(term_rows * sizeof(char *));
temp_color_buffer = malloc(term_rows * sizeof(unsigned long *));
temp_attr_buffer = malloc(term_rows * sizeof(int *));
temp_bg_color_buffer = malloc(term_rows * sizeof(unsigned long *));
if (!temp_buffer || !temp_color_buffer || !temp_attr_buffer ||
!temp_bg_color_buffer) {
fprintf(stderr, "Failed to allocate memory for temp buffers\n");
return;
}
for (int i = 0; i < term_rows; i++) {
temp_buffer[i] = malloc(term_cols * sizeof(char));
temp_color_buffer[i] = malloc(term_cols * sizeof(unsigned long));
temp_attr_buffer[i] = malloc(term_cols * sizeof(int));
temp_bg_color_buffer[i] = malloc(term_cols * sizeof(unsigned long));
if (!temp_buffer[i] || !temp_color_buffer[i] || !temp_attr_buffer[i] ||
!temp_bg_color_buffer[i]) {
fprintf(stderr, "Failed to allocate memory for temp buffer row\n");
free(temp_buffer);
free(temp_color_buffer);
free(temp_attr_buffer);
free(temp_bg_color_buffer);
return;
}
}
if (scroll_top == 0 && scroll_bottom == 0) {
for (int i = 0; i < term_rows; i++) {
memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char));
memcpy(temp_color_buffer[i], color_buffer[i],
term_cols * sizeof(unsigned long));
memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int));
memcpy(temp_bg_color_buffer[i], bg_color_buffer[i],
term_cols * sizeof(unsigned long));
}
for (int j = 0; j < amount; j++) {
// Move all lines down one position
for (int y = term_rows - 1; y > 0; y--) {
memcpy(terminal_buffer[y], temp_buffer[y - 1], term_cols);
memcpy(color_buffer[y], temp_color_buffer[y - 1],
term_cols * sizeof(unsigned long));
memcpy(attr_buffer[y], temp_attr_buffer[y - 1],
term_cols * sizeof(int));
memcpy(bg_color_buffer[y], temp_bg_color_buffer[y - 1],
term_cols * sizeof(unsigned long));
}
// Clear the top line
memset(terminal_buffer[0], ' ', term_cols);
for (int x = 0; x < term_cols; x++) {
color_buffer[0][x] = current_color;
attr_buffer[0][x] = current_attr;
bg_color_buffer[0][x] = current_bg_color;
}
}
} else {
for (int i = 0; i < term_rows; i++) {
memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char));
memcpy(temp_color_buffer[i], color_buffer[i],
term_cols * sizeof(unsigned long));
memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int));
memcpy(temp_bg_color_buffer[i], bg_color_buffer[i],
term_cols * sizeof(unsigned long));
}
for (int j = 0; j < amount; j++) {
int start = (scroll_top - 1);
int end = (scroll_bottom - 1);
if (start < 0)
start = 0;
if (end < 0)
end = 0;
if (end >= term_rows)
end = term_rows - 1;
// Move all lines down one position
for (int y = end; y > start; y--) {
memcpy(terminal_buffer[y], temp_buffer[y - 1], term_cols);
memcpy(color_buffer[y], temp_color_buffer[y - 1],
term_cols * sizeof(unsigned long));
memcpy(attr_buffer[y], temp_attr_buffer[y - 1],
term_cols * sizeof(int));
memcpy(bg_color_buffer[y], temp_bg_color_buffer[y - 1],
term_cols * sizeof(unsigned long));
}
// Clear the top line
memset(terminal_buffer[start], ' ', term_cols);
for (int x = 0; x < term_cols; x++) {
color_buffer[start][x] = current_color;
attr_buffer[start][x] = current_attr;
bg_color_buffer[start][x] = current_bg_color;
}
}
}
for (int i = 0; i < term_rows; i++) {
free(temp_buffer[i]);
free(temp_color_buffer[i]);
free(temp_attr_buffer[i]);
free(temp_bg_color_buffer[i]);
}
free(temp_buffer);
free(temp_color_buffer);
free(temp_attr_buffer);
free(temp_bg_color_buffer);
needs_refresh = 1;
}
// Alternative buffer visual: // Alternative buffer visual:
// //
// Normal buffer: Alternate buffer: // Normal buffer: Alternate buffer:
@ -453,7 +683,8 @@ static void scroll_up(void) {
// saved_terminal = backup of normal buffer // saved_terminal = backup of normal buffer
// saved_colors/attrs = backup of attributes // saved_colors/attrs = backup of attributes
// using_alternate = tracks which buffer is active // using_alternate = tracks which buffer is active
static void handle_alternate_buffer(const char *buf, int *idx, int max_len) { static void handle_alternate_buffer(const char *buf, int *idx, int max_len,
Window window) {
char num_buf[32] = {0}; char num_buf[32] = {0};
size_t num_idx = 0; size_t num_idx = 0;
@ -488,6 +719,8 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len) {
bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long));
} }
using_alternate = 1; using_alternate = 1;
needs_refresh = 1;
draw_terminal(display, window);
} }
} else if (using_alternate) { } else if (using_alternate) {
for (int i = 0; i < term_rows; i++) { for (int i = 0; i < term_rows; i++) {
@ -506,6 +739,8 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len) {
bg_color_buffer = saved_colors; bg_color_buffer = saved_colors;
saved_terminal = NULL; saved_terminal = NULL;
using_alternate = 0; using_alternate = 0;
needs_refresh = 1;
draw_terminal(display, window);
} }
break; break;
case 1048: // Save/restore cursor case 1048: // Save/restore cursor
@ -537,6 +772,8 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len) {
bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long));
} }
using_alternate = 1; using_alternate = 1;
needs_refresh = 1;
draw_terminal(display, window);
} }
} else if (using_alternate) { } else if (using_alternate) {
for (int i = 0; i < term_rows; i++) { for (int i = 0; i < term_rows; i++) {
@ -557,6 +794,8 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len) {
cursor_x = saved_cursor_x; cursor_x = saved_cursor_x;
cursor_y = saved_cursor_y; cursor_y = saved_cursor_y;
using_alternate = 0; using_alternate = 0;
needs_refresh = 1;
draw_terminal(display, window);
} }
break; break;
} }
@ -583,7 +822,7 @@ static unsigned long get_bright_ansi_color(int index) {
// 34 = Blue 35 = Magenta 36 = Cyan 37 = White // 34 = Blue 35 = Magenta 36 = Cyan 37 = White
// 0 sets everything back to plain white // 0 sets everything back to plain white
// P.S. yes I had to google this up // P.S. yes I had to google this up
static void parse_ansi_code(const char *buf, int *idx, int max_len) { static void parse_ansi_code(const char *buf, int *idx, int max_len, Window window) {
char num_buf[32] = {0}; char num_buf[32] = {0};
int params[32] = {0}; int params[32] = {0};
size_t num_idx = 0; size_t num_idx = 0;
@ -592,7 +831,7 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len) {
// Handle '?' prefix for private sequences // Handle '?' prefix for private sequences
if (buf[*idx] == '?') { if (buf[*idx] == '?') {
handle_alternate_buffer(buf, idx, max_len); handle_alternate_buffer(buf, idx, max_len, window);
return; return;
} }
@ -678,6 +917,54 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len) {
needs_refresh = 1; needs_refresh = 1;
} }
break; break;
case 'r': // Set scrolling region
if (param_idx == 0) {
scroll_top = 0; // Entire terminal
scroll_bottom = 0;
} else if (param_idx == 1) {
scroll_top = (params[0] <= 0)
? 1
: (params[0] > term_rows ? term_rows : params[0]);
scroll_bottom = 0;
} else if (param_idx >= 2) {
scroll_top = (params[0] <= 0)
? 1
: (params[0] > term_rows ? term_rows : params[0]);
scroll_bottom = (params[1] <= 0)
? term_rows
: (params[1] > term_rows ? term_rows : params[1]);
// if top is bigger than bottom, swap values
if (scroll_top > scroll_bottom) {
int tmp = scroll_top;
scroll_top = scroll_bottom;
scroll_bottom = tmp;
break;
case 'S': // Scroll up
scroll_region_up(params[0] == 0 ? 1 : params[0]);
needs_refresh = 1;
break;
case 'T': // Scroll down
scroll_region_down(params[0] == 0 ? 1 : params[0]);
needs_refresh = 1;
break;
case 'E': // Cursor next line
cursor_x = 0;
cursor_y += params[0] ? params[0] : 1;
if (cursor_y >= term_rows) {
cursor_y = term_rows - 1;
}
break;
case 'F': // Cursor line before
cursor_x = 0;
cursor_y -= params[0] ? params[0] : 1;
if (cursor_y < 0) {
cursor_y = 0;
}
break;
}
}
break;
case 'm': // Handling of text case 'm': // Handling of text
for (int i = 0; i < param_idx; i++) { for (int i = 0; i < param_idx; i++) {
if (params[i] == 0) { // Reset Everything if (params[i] == 0) { // Reset Everything
@ -722,7 +1009,7 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len) {
} }
} }
static int master_cb(int fd, void *data) { static int master_cb(int fd, void *data, Window window) {
if (!terminal_buffer || !color_buffer || !attr_buffer || !bg_color_buffer) if (!terminal_buffer || !color_buffer || !attr_buffer || !bg_color_buffer)
return 0; return 0;
char buf[4096]; char buf[4096];
@ -740,7 +1027,7 @@ static int master_cb(int fd, void *data) {
if (bytes_read > 0) { if (bytes_read > 0) {
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
if (buf[i] == '\033' && i + 1 < bytes_read && buf[i + 1] == '[') { if (buf[i] == '\033' && i + 1 < bytes_read && buf[i + 1] == '[') {
parse_ansi_code(buf, &i, bytes_read); parse_ansi_code(buf, &i, bytes_read, window);
continue; continue;
} }
if (buf[i] == '\n') { if (buf[i] == '\n') {
@ -1043,7 +1330,7 @@ int main(void) {
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(master, &fds); FD_SET(master, &fds);
if (select(master + 1, &fds, NULL, NULL, &tv) > 0) { if (select(master + 1, &fds, NULL, NULL, &tv) > 0) {
master_cb(master, &ctx); master_cb(master, &ctx, window);
} }
check_refresh(display, window); check_refresh(display, window);