Adding splitting screen and buffer switching
This commit is contained in:
+178
-61
@@ -7,6 +7,11 @@
|
||||
|
||||
#include "../include/output.h"
|
||||
#include "../include/append_buffer.h"
|
||||
#include "../include/buffer.h"
|
||||
#include "../include/data.h"
|
||||
#include "../include/define.h"
|
||||
#include "../include/row_op.h"
|
||||
#include "../include/split_screen.h"
|
||||
#include "../include/syntax_highlighter.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -16,60 +21,128 @@
|
||||
extern struct editorConfig E;
|
||||
|
||||
/**
|
||||
* @brief Renders all visible rows to the screen buffer
|
||||
* @details Draws file content with syntax highlighting, handles line wrapping,
|
||||
* and displays tilde characters (~) for empty lines. Shows welcome message
|
||||
* when no file is open.
|
||||
* @param ab Pointer to append buffer structure for accumulating output
|
||||
* @note Respects E.row_offset and E.col_offset for scrolling
|
||||
* @note Clears to end of each line after content
|
||||
* @see editorRefreshScreen()
|
||||
* @brief Renders a single pane with its buffer content
|
||||
*/
|
||||
void editorDrawRows(struct abuf *ab) {
|
||||
int y;
|
||||
char welcome[80];
|
||||
int welcome_len;
|
||||
int padding;
|
||||
int len;
|
||||
int file_row;
|
||||
for (y = 0; y < E.screenrows; ++y) {
|
||||
file_row = y + E.row_offset;
|
||||
static void editorDrawPane(struct abuf *ab, EditorPane *pane) {
|
||||
if (pane == NULL || pane->buffer_id < 0)
|
||||
return;
|
||||
|
||||
struct buffer_t *buf = bufferFindById(pane->buffer_id);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
// Draw content for this pane
|
||||
for (int y = 0; y < pane->height; y++) {
|
||||
int file_row = y + pane->row_offset;
|
||||
|
||||
// Position cursor at start of pane row
|
||||
char pos_buf[32];
|
||||
int pos_len = snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH",
|
||||
pane->start_row + y + 1, pane->start_col + 1);
|
||||
abAppend(ab, pos_buf, pos_len);
|
||||
|
||||
// Apply background color (6 bytes for RGB format)
|
||||
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
|
||||
if (file_row >= E.numrows) {
|
||||
if (E.numrows == 0 && y == E.screenrows / 3) {
|
||||
welcome_len =
|
||||
snprintf(welcome, sizeof(welcome),
|
||||
"Beluga text editor -- version %s", BELUGA_VERSION);
|
||||
if (welcome_len > E.screencols) {
|
||||
welcome_len = E.screencols;
|
||||
}
|
||||
padding = (E.screencols - welcome_len) / 2;
|
||||
|
||||
int chars_printed = 0;
|
||||
|
||||
if (file_row >= buf->numrows) {
|
||||
// Empty line - show tilde
|
||||
if (buf->numrows == 0 && y == pane->height / 3) {
|
||||
char welcome[80];
|
||||
int welcome_len =
|
||||
snprintf(welcome, sizeof(welcome), "Buffer %d", pane->buffer_id);
|
||||
if (welcome_len > pane->width)
|
||||
welcome_len = pane->width;
|
||||
|
||||
int padding = (pane->width - welcome_len) / 2;
|
||||
if (padding) {
|
||||
abAppend(ab, "~", 1);
|
||||
--padding;
|
||||
chars_printed++;
|
||||
padding--;
|
||||
}
|
||||
while (padding--) {
|
||||
while (padding-- && chars_printed < pane->width) {
|
||||
abAppend(ab, " ", 1);
|
||||
chars_printed++;
|
||||
}
|
||||
abAppend(ab, welcome, welcome_len);
|
||||
chars_printed += welcome_len;
|
||||
} else {
|
||||
abAppend(ab, "~", 1);
|
||||
chars_printed++;
|
||||
}
|
||||
} else {
|
||||
len = E.row[file_row].rsize - E.col_offset;
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
if (len > E.screencols)
|
||||
len = E.screencols;
|
||||
char *highlighted = highlight_line(&E.row[file_row].render[E.col_offset],
|
||||
&E.row[file_row].rsize);
|
||||
abAppend(ab, highlighted, E.row[file_row].rsize);
|
||||
// Render line with syntax highlighting, constrain to pane width
|
||||
int start_offset = pane->col_offset;
|
||||
int visible_len = buf->row[file_row].rsize - start_offset;
|
||||
if (visible_len < 0)
|
||||
visible_len = 0;
|
||||
if (visible_len > pane->width)
|
||||
visible_len = pane->width;
|
||||
|
||||
free(highlighted);
|
||||
if (buf->filename[strlen(buf->filename) - 1] == 'c') {
|
||||
int byte_len_to_print;
|
||||
|
||||
char *highlighted = highlight_line(
|
||||
&buf->row[file_row].render[start_offset], &byte_len_to_print);
|
||||
|
||||
// Print only up to pane width
|
||||
|
||||
abAppend(ab, highlighted, byte_len_to_print);
|
||||
free(highlighted);
|
||||
} else {
|
||||
abAppend(ab, &buf->row[file_row].render[start_offset], buf->row[file_row].rsize);
|
||||
}
|
||||
|
||||
chars_printed = visible_len;
|
||||
}
|
||||
|
||||
// Fill remaining space with background color to pane width
|
||||
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
|
||||
abAppend(ab, ERASE_END_LINE, 3);
|
||||
abAppend(ab, "\r\n", 2);
|
||||
while (chars_printed < pane->width) {
|
||||
abAppend(ab, " ", 1);
|
||||
chars_printed++;
|
||||
}
|
||||
|
||||
// Restore background color at end of line
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renders all panes based on current split configuration
|
||||
*/
|
||||
static void editorDrawAllPanes(struct abuf *ab) {
|
||||
ScreenLayout *layout = splitScreenGetLayout();
|
||||
|
||||
if (layout->num_panes == 1) {
|
||||
// Single pane fullscreen
|
||||
editorDrawPane(ab, &layout->panes[0]);
|
||||
} else if (layout->num_panes == 2) {
|
||||
// Draw both panes
|
||||
for (int i = 0; i < 2; i++) {
|
||||
editorDrawPane(ab, &layout->panes[i]);
|
||||
|
||||
// Draw pane border/divider if not the last pane
|
||||
if (layout->mode == SPLIT_VERTICAL && i == 0) {
|
||||
// Draw vertical divider
|
||||
int divider_col = layout->panes[0].width;
|
||||
for (int y = 0; y < layout->panes[0].height; y++) {
|
||||
char pos_buf[32];
|
||||
snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", y + 1, divider_col);
|
||||
abAppend(ab, pos_buf, strlen(pos_buf));
|
||||
abAppend(ab, "\x1b[1m|\x1b[0m", 9); // Bold pipe divider
|
||||
}
|
||||
} else if (layout->mode == SPLIT_HORIZONTAL && i == 0) {
|
||||
// Draw horizontal divider
|
||||
int divider_row = layout->panes[0].height;
|
||||
char pos_buf[32];
|
||||
snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", divider_row + 1, 1);
|
||||
abAppend(ab, pos_buf, strlen(pos_buf));
|
||||
for (int x = 0; x < E.screencols; x++) {
|
||||
abAppend(ab, "\x1b[1m-\x1b[0m", 9); // Bold dash divider
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,22 +154,33 @@ void editorDrawRows(struct abuf *ab) {
|
||||
* @see editorRowCxToRx()
|
||||
*/
|
||||
void editorScroll() {
|
||||
E.rx = E.cursor_x;
|
||||
if (E.cursor_y < E.numrows) {
|
||||
E.rx = editorRowCxToRx(&E.row[E.cursor_y], E.cursor_x);
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buf = bufferFindById(active->buffer_id);
|
||||
active->rx = active->cursor_x;
|
||||
|
||||
fprintf(stderr, "%d %d / %d %d\n", active->cursor_x, active->col_offset,
|
||||
active->cursor_y, active->row_offset);
|
||||
|
||||
if (active->cursor_x < 0) {
|
||||
active->cursor_x = 0;
|
||||
active->col_offset = active->col_offset == 0 ? 0 : --active->col_offset;
|
||||
}
|
||||
|
||||
if (E.cursor_y < E.row_offset) {
|
||||
E.row_offset = E.cursor_y;
|
||||
if (active->cursor_y < 0) {
|
||||
active->cursor_y = 0;
|
||||
active->row_offset = active->row_offset == 0 ? 0 : --active->row_offset;
|
||||
}
|
||||
if (E.cursor_y >= E.row_offset + E.screenrows) {
|
||||
E.row_offset = E.cursor_y - E.screenrows + 1;
|
||||
|
||||
if (active->cursor_x == active->width) {
|
||||
|
||||
active->cursor_x--;
|
||||
active->col_offset++;
|
||||
}
|
||||
if (E.rx < E.col_offset) {
|
||||
E.col_offset = E.rx;
|
||||
}
|
||||
if (E.rx >= E.col_offset + E.screencols) {
|
||||
E.col_offset = E.rx - E.screencols + 1;
|
||||
|
||||
if (active->cursor_y == active->height) {
|
||||
|
||||
active->cursor_y--;
|
||||
active->row_offset++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,16 +195,39 @@ void editorScroll() {
|
||||
void editorDrawStatusBar(struct abuf *ab) {
|
||||
int len, render_len;
|
||||
char status[80], render_status[80];
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buf = bufferFindById(active->buffer_id);
|
||||
|
||||
abAppend(ab, "\x1b[7m", 4); // inverting colors
|
||||
len = snprintf(status, sizeof(status), "%.20s - %d lines%s",
|
||||
E.filename ? E.filename : "[No Name]", E.numrows,
|
||||
E.dirty ? "*" : "");
|
||||
|
||||
const char *mode_str = "";
|
||||
ScreenLayout *layout = splitScreenGetLayout();
|
||||
if (layout->mode == SPLIT_VERTICAL)
|
||||
mode_str = " [V-SPLIT]";
|
||||
else if (layout->mode == SPLIT_HORIZONTAL)
|
||||
mode_str = " [H-SPLIT]";
|
||||
|
||||
// Build buffer status showing all buffers with dirty indicators
|
||||
char buf_status[200] = "";
|
||||
int offset = 0;
|
||||
for (int i = 0; i < E.number_of_buffer; i++) {
|
||||
struct buffer_t *b = &E.buffers[i];
|
||||
char marker = (b->buffer_id == active->buffer_id) ? '>' : ' ';
|
||||
char dirty_marker = b->dirty ? '*' : ' ';
|
||||
offset += snprintf(&buf_status[offset], sizeof(buf_status) - offset,
|
||||
"%c%d:%s%c ", marker, b->buffer_id,
|
||||
b->filename ? b->filename : "[No Name]", dirty_marker);
|
||||
}
|
||||
|
||||
len = snprintf(status, sizeof(status), "%s%s", buf_status, mode_str);
|
||||
|
||||
render_len = snprintf(render_status, sizeof(render_status), "%d/%d",
|
||||
E.cursor_y + 1, E.numrows);
|
||||
active->cursor_y + 1, buf->numrows);
|
||||
|
||||
if (len > E.screencols) {
|
||||
len = E.screencols;
|
||||
}
|
||||
|
||||
abAppend(ab, status, len);
|
||||
while (len < E.screencols) {
|
||||
if (E.screencols - len == render_len) {
|
||||
@@ -131,6 +238,7 @@ void editorDrawStatusBar(struct abuf *ab) {
|
||||
++len;
|
||||
}
|
||||
}
|
||||
|
||||
abAppend(ab, "\x1b[m", 3); // normal text mode
|
||||
abAppend(ab, "\r\n", 2);
|
||||
}
|
||||
@@ -163,23 +271,32 @@ void editorDrawMessageBar(struct abuf *ab) {
|
||||
* @see editorDrawStatusBar()
|
||||
* @see editorDrawMessageBar()
|
||||
*/
|
||||
|
||||
void editorRefreshScreen() {
|
||||
editorScroll();
|
||||
struct abuf ab = ABUF_INIT;
|
||||
char buf[32];
|
||||
|
||||
|
||||
abAppend(&ab, HIDE_CURSOR, 6);
|
||||
abAppend(&ab, CURSOR_TOP_LEFT, 3);
|
||||
abAppend(&ab, E.theme.BACKGROUND_COLOR,
|
||||
strlen(E.theme.BACKGROUND_COLOR)); // RGB background is 12 bytes
|
||||
|
||||
// Draw all panes
|
||||
editorScroll();
|
||||
editorDrawAllPanes(&ab);
|
||||
|
||||
editorDrawRows(&ab);
|
||||
// Draw status bar and message bar
|
||||
editorDrawStatusBar(&ab);
|
||||
editorDrawMessageBar(&ab);
|
||||
|
||||
snprintf(buf, sizeof(buf), "\x1b[%d;%dH", (E.cursor_y - E.row_offset) + 1,
|
||||
(E.rx - E.col_offset) + 1);
|
||||
abAppend(&ab, buf, strlen(buf));
|
||||
// Position cursor in active pane
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
if (active != NULL) {
|
||||
snprintf(buf, sizeof(buf), "\x1b[%d;%dH",
|
||||
active->cursor_y + active->start_row + 1,
|
||||
active->cursor_x + active->start_col + 1);
|
||||
abAppend(&ab, buf, strlen(buf));
|
||||
}
|
||||
|
||||
abAppend(&ab, SHOW_CURSOR, 6);
|
||||
write(STDOUT_FILENO, ab.b, ab.len);
|
||||
|
||||
Reference in New Issue
Block a user