diff --git a/bt.c b/bt.c index 998b0f7..5fad1a2 100644 --- a/bt.c +++ b/bt.c @@ -16,6 +16,7 @@ const int SCREEN_WIDTH = 900; const int SCREEN_HEIGHT = 700; +const int SCROLLBACK_DEFAULT_SIZE = 4096; const SDL_Color WHITE = {255, 255, 255, 255}; const SDL_Color BLACK = {0, 0, 0, 255}; const SDL_Color RED = {255, 0, 0, 255}; @@ -26,20 +27,26 @@ const SDL_Color MAGENTA = {255, 0, 255, 255}; const SDL_Color SKYBLUE = {0, 255, 255, 255}; const SDL_Color RAYWHITE = {200, 200, 200, 255}; -typedef struct scrollback { +typedef struct { float height; float ypos; int capacity; int length; char *buf; -} scrollback; +} Scrollback; -typedef struct file_descriptors { +typedef struct { int master; int child; -} file_descriptors; +} FileDescriptors; -void spawn(file_descriptors *fds) { +typedef struct { + Scrollback* sb; + TTF_Font* font; + SDL_Renderer* renderer; +} Context; + +void spawn(FileDescriptors *fds) { openpty(&fds->master, &fds->child, NULL, NULL, NULL); pid_t p = fork(); if (p == 0) { @@ -57,7 +64,7 @@ void spawn(file_descriptors *fds) { } } -int read_pty(file_descriptors *fds, scrollback *sb) { +int read_pty(FileDescriptors *fds, Scrollback *sb) { ssize_t nread; char readbuf[256]; switch (nread = read(fds->master, readbuf, sizeof(readbuf))) { @@ -84,9 +91,115 @@ int read_pty(file_descriptors *fds, scrollback *sb) { } } +void render_scrollback(Context* ctx) { + SDL_RenderClear(ctx->renderer); + + SDL_Color current_color = WHITE; + int col_max = 80; + char row_buf[col_max]; + int nrow = 0; + int ncol = 0; + int row_height = 18; + float row_posx = 0; + Scrollback sb = *ctx->sb; + for (int c = 0; c <= sb.length; c++) { + // for (int c = 0; c <= -1; c++) { + if (sb.buf[c] == '\r') { + continue; + } else if (sb.buf[c] == '\n' || sb.buf[c] == '\0' || ncol >= col_max) { + row_buf[ncol] = '\0'; + // TODO: Render new line or something? + // Vector2 pos = { row_posx, nrow * row_height + sb.ypos }; + // DrawTextEx(*fontDefault, row_buf, pos, fontsize, 0, current_color); + SDL_Surface* surface = + TTF_RenderText_Blended(ctx->font, row_buf, WHITE); + + // now you can convert it into a texture + SDL_Texture* texture = SDL_CreateTextureFromSurface(ctx->renderer, surface); + + SDL_Rect rect; + rect.x = 0; + rect.y = nrow * 15; + rect.w = surface->w; + rect.h = surface->h; + + + SDL_RenderCopy(ctx->renderer, texture, NULL, &rect); + + SDL_DestroyTexture(texture); + SDL_FreeSurface(surface); + + nrow++; + ncol = 0; + row_posx = 0; + // Control sequence + } else if (sb.buf[c] == '\x1b') { + int c2 = c + 1; + // Control Sequence Introducer + int csi_args[16]; + char csi_code; + int nargs = 0; + if (sb.buf[c2] == '[') { + char *esc_buf = sb.buf + c2 + 1; + while (true) { + char *substr; + long num = strtol(esc_buf, &substr, 10); + if (esc_buf != substr) { + csi_args[nargs++] = num; + esc_buf = substr; + if (substr[0] == ';') { + esc_buf++; + } + continue; + } + csi_code = substr[0]; + SDL_Color new_color = WHITE; + switch (csi_code) { + case 'm': + for (int i = 0; i < nargs; i++) { + if (csi_args[i] == 31) { + new_color = RED; + } else if (csi_args[i] == 32) { + new_color = GREEN; + } else if (csi_args[i] == 33) { + new_color = YELLOW; + } else if (csi_args[i] == 34) { + new_color = BLUE; + } else if (csi_args[i] == 35) { + new_color = MAGENTA; + } else if (csi_args[i] == 36) { + new_color = SKYBLUE; + } else if (csi_args[i] == 0) { + new_color = RAYWHITE; + } + } + row_buf[ncol] = '\0'; + // TODO: This looks like the actual place where we + // draw the text at a line + // Vector2 pos = { row_posx, nrow * row_height + sb.ypos }; + // DrawTextEx(*fontDefault, row_buf, pos, fontsize, 0, current_color); + current_color = new_color; + ncol = 0; + c += (substr) - (sb.buf + c); + // TODO: Get the text height + // int width = MeasureTextEx(*fontDefault, row_buf, fontsize, 1).x; + // row_posx += width + 0.85; + break; + } + break; + } + } + } else { + row_buf[ncol++] = sb.buf[c]; + } + } + + SDL_RenderPresent(ctx->renderer); +} + int main(void) { - scrollback sb = { 0 }; - file_descriptors fds = { 0 }; + Scrollback sb = { 0 }; + FileDescriptors fds = { 0 }; spawn(&fds); @@ -94,20 +207,21 @@ int main(void) { printf("error initializing SDL: %s\n", SDL_GetError()); return 1; } - - SDL_Window* window = SDL_CreateWindow( "bt", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, - SCREEN_HEIGHT, - SDL_WINDOW_SHOWN ); + int start_x = 20; + int start_y = 20; + SDL_Window* window = SDL_CreateWindow("bt", + start_x, + start_y, + SCREEN_WIDTH, + SCREEN_HEIGHT, + SDL_WINDOW_SHOWN); if (window == NULL) { printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() ); return 1; } SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); - SDL_SetRenderDrawColor(renderer, 130, 163, 255, 1); + // SDL_SetRenderDrawColor(renderer, 130, 163, 255, 1); TTF_Init(); TTF_Font* font = TTF_OpenFont( "./fira.ttf", 16); @@ -120,7 +234,7 @@ int main(void) { // TODO: It would be nice to figure out how to do this in SDL // SetTargetFPS(60); - sb.capacity = 2048; + sb.capacity = SCROLLBACK_DEFAULT_SIZE; sb.buf = malloc(sb.capacity); sb.buf[0] = '\0'; sb.length = 0; @@ -136,6 +250,11 @@ int main(void) { sb.ypos = 0; + Context ctx = { + .sb = &sb, + .font = font, + .renderer = renderer + }; bool new_read = false; bool new_char = false; SDL_Event e; @@ -203,108 +322,13 @@ int main(void) { } - // Drawing int nread = read_pty(&fds, &sb); if (nread > 0) { sb.length += nread; new_read = true; } - SDL_RenderClear(renderer); - SDL_Surface* surfaceMessage = - TTF_RenderText_Blended(font, "put your text here", WHITE); - // now you can convert it into a texture - SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surfaceMessage); - SDL_Rect rect; - rect.x = 0; - rect.y = 0; - rect.w = surfaceMessage->w; - rect.h = surfaceMessage->h; - - SDL_RenderCopy(renderer, texture, NULL, &rect); - - SDL_Color current_color = WHITE; - int col_max = 200; - char row_buf[col_max]; - int nrow = 0; - int ncol = 0; - int row_height = 18; - float row_posx = 0; - // for (int c = 0; c <= sb.length; c++) { - for (int c = 0; c <= -1; c++) { - if (sb.buf[c] == '\r') { - continue; - } else if (sb.buf[c] == '\n' || sb.buf[c] == '\0' || ncol >= col_max) { - row_buf[ncol] = '\0'; - // TODO: Render new line or something? - // Vector2 pos = { row_posx, nrow * row_height + sb.ypos }; - // DrawTextEx(*fontDefault, row_buf, pos, fontsize, 0, current_color); - nrow++; - ncol = 0; - row_posx = 0; - } else if (sb.buf[c] == '\x1b') { - int c2 = c + 1; - // Control Sequence Introducer - int csi_args[16]; - char csi_code; - int nargs = 0; - if (sb.buf[c2] == '[') { - char *esc_buf = sb.buf + c2 + 1; - while (true) { - char *substr; - long num = strtol(esc_buf, &substr, 10); - if (esc_buf != substr) { - csi_args[nargs++] = num; - esc_buf = substr; - if (substr[0] == ';') { - esc_buf++; - } - continue; - } - csi_code = substr[0]; - SDL_Color new_color = WHITE; - switch (csi_code) { - case 'm': - for (int i = 0; i < nargs; i++) { - if (csi_args[i] == 31) { - new_color = RED; - } else if (csi_args[i] == 32) { - new_color = GREEN; - } else if (csi_args[i] == 33) { - new_color = YELLOW; - } else if (csi_args[i] == 34) { - new_color = BLUE; - } else if (csi_args[i] == 35) { - new_color = MAGENTA; - } else if (csi_args[i] == 36) { - new_color = SKYBLUE; - } else if (csi_args[i] == 0) { - new_color = RAYWHITE; - } - } - row_buf[ncol] = '\0'; - // TODO: This looks like the actual place where we - // draw the text at a line - // Vector2 pos = { row_posx, nrow * row_height + sb.ypos }; - // DrawTextEx(*fontDefault, row_buf, pos, fontsize, 0, current_color); - current_color = new_color; - ncol = 0; - c += (substr) - (sb.buf + c); - // TODO: Get the text height - // int width = MeasureTextEx(*fontDefault, row_buf, fontsize, 1).x; - // row_posx += width + 0.85; - break; - } - break; - } - } - } else { - row_buf[ncol++] = sb.buf[c]; - } - } - SDL_RenderPresent(renderer); - SDL_DestroyTexture(texture); - SDL_FreeSurface(surfaceMessage); + render_scrollback(&ctx); } free(sb.buf); diff --git a/project.todo b/bt.todo similarity index 54% rename from project.todo rename to bt.todo index e6070a0..12c5d8a 100644 --- a/project.todo +++ b/bt.todo @@ -1,8 +1,7 @@ #-*- mode: org -*- -#+TODO: BLOCKED TODO INPROGRESS | DONE BACKLOG +#+TODO: TODO | DONE #+STARTUP: overview - * DONE Render with Raylib * DONE Load custom Mono font * DONE Render input from user @@ -12,17 +11,12 @@ * DONE Auto-scrolling * DONE Render scrollback by rows * DONE Handle color escape sequences -* TODO Backspace and Return aren't repeating [[https://github.com/raysan5/raylib/issues/2041][Issue Here]] -* TODO Switch to SDL2 +* DONE Switch to SDL2 +* TODO Clean up the rendering of the scrollback buffer +* TODO Get Backspace and Return to repeat properly [[https://github.com/raysan5/raylib/issues/2041][Why we switched to SDL]] +* TODO Render the scrollback line by line * TODO Only draw scrollback that is visible -* TODO Improve the scrolling to match first and last lines * TODO Handle unicode characters * TODO Handle canonical and raw commands * TODO Mouse copy/paste -* TODO Manually control when raylib updates/draws -* TODO Create basic vertical splits - -* COMMENT Local variables -;; Local Variables: -;; eval: (olivetti-mode t) -;; End: +* TODO Create basic vertical splits?