Status bar / editing / saving file

This commit is contained in:
Arthur Barraux
2024-10-08 14:57:59 +02:00
parent 297eef4ce2
commit 1c22c3beca
15 changed files with 334 additions and 27 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ build: main.c src/*
$(CC) main.c -o $(BELUGA_OUTPUT)/beluga src/* $(CC) main.c -o $(BELUGA_OUTPUT)/beluga src/*
doxygen doxygen
DEBUG_FLAGS=-Wall -Wextra -pedantic -Werror -fsanitize=address,undefined -g DEBUG_FLAGS=-Wall -Wextra -pedantic -Werror -fsanitize=address -g
debug: main.c src/* debug: main.c src/*
if [ ! -d $(BELUGA_OUTPUT) ]; then mkdir $(BELUGA_OUTPUT); fi if [ ! -d $(BELUGA_OUTPUT) ]; then mkdir $(BELUGA_OUTPUT); fi
+30 -11
View File
@@ -2,10 +2,19 @@
#define DATA_H_ #define DATA_H_
#include <termios.h> #include <termios.h>
#include <time.h>
/**
* \struct erow
* \brief Store one editor row
* \param
* */
typedef struct erow { typedef struct erow {
int size; int size; /**< Size of the line */
char *chars; int rsize; /**< Size of the render line */
char *chars; /**< Characters of the line */
char *render; /**< The actual line we will print */
} erow; } erow;
/** /**
@@ -13,18 +22,28 @@ typedef struct erow {
* \brief Containing our editor state. * \brief Containing our editor state.
*/ */
struct editorConfig { struct editorConfig {
int cursor_x, cursor_y; int cursor_x, cursor_y; /**< Cursor position */
int row_offset; int rx; /**< Position in the render*/
int screenrows; int row_offset; /**< Position scroll of lines */
int screencols; int col_offset; /**< Position scroll of colomns*/
int numrows; int screenrows; /**< Terminal height*/
erow *row; int screencols; /**< Terminal width*/
struct termios orig_termios; int numrows; /**< Number of rows contained */
erow *row; /**< Store all the rows printed */
char *filename;
char status_msg[80];
time_t status_msg_time;
struct termios orig_termios; /**< Terminal communication interface */
}; };
/**
* \struct abuf
* \brief Contains text to add before writing to screen.
* */
struct abuf { struct abuf {
char *b; char *b; /**< Text that will be printed */
int len; int len; /**< Length of the text */
}; };
#endif #endif
+2
View File
@@ -9,6 +9,7 @@
#define ERASE_END_LINE "\x1b[K" #define ERASE_END_LINE "\x1b[K"
enum editorKey { enum editorKey {
BACKSPACE = 127,
CURSOR_LEFT = 1000, CURSOR_LEFT = 1000,
CURSOR_RIGHT, CURSOR_RIGHT,
CURSOR_UP, CURSOR_UP,
@@ -23,5 +24,6 @@ enum editorKey {
#define ABUF_INIT {NULL, 0} #define ABUF_INIT {NULL, 0}
#define BELUGA_VERSION "0.1" #define BELUGA_VERSION "0.1"
#define TAB_LENGTH 8
#endif // DEFINE_H_ #endif // DEFINE_H_
+7
View File
@@ -0,0 +1,7 @@
#ifndef EDITOR_OP_H_
#define EDITOR_OP_H_
#include "data.h"
void editorInsertChar(struct editorConfig *E, int c);
#endif // EDITOR_OP_H_
+4
View File
@@ -8,6 +8,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
char *editorRowsToString(struct editorConfig *E, int *buffer_len);
void editorOpen(struct editorConfig *E, char *filename); void editorOpen(struct editorConfig *E, char *filename);
void editorSave(struct editorConfig *E);
#endif // FILE_IO_H_ #endif // FILE_IO_H_
+9
View File
@@ -4,6 +4,7 @@
#include "append_buffer.h" #include "append_buffer.h"
#include "data.h" #include "data.h"
#include "define.h" #include "define.h"
#include "row_op.h"
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@@ -16,4 +17,12 @@ void editorDrawRows(struct editorConfig *E, struct abuf *ab);
void editorRefreshScreen(struct editorConfig *E); void editorRefreshScreen(struct editorConfig *E);
void editorScroll(struct editorConfig *E);
void editorDrawStatusBar(struct editorConfig *E, struct abuf *ab);
void editorDrawMessageBar(struct editorConfig *E, struct abuf *ab);
void editorSetStatusMessage(struct editorConfig *E, const char *fmt, ...);
#endif // OUTPUT_H_ #endif // OUTPUT_H_
+7
View File
@@ -2,10 +2,17 @@
#define ROW_OP_H_ #define ROW_OP_H_
#include "data.h" #include "data.h"
#include "define.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
int editorRowCxToRx(erow *row, int cursor_x);
void editorUpdateRow(erow *row);
void editorAppendRow(struct editorConfig *E, char *s, size_t len); void editorAppendRow(struct editorConfig *E, char *s, size_t len);
void editorRowInsertChar(erow *row, int at, int c);
#endif // ROW_OP_H_ #endif // ROW_OP_H_
+2
View File
@@ -26,6 +26,8 @@ int main(int argc, char *argv[]) {
editorOpen(&E, argv[1]); editorOpen(&E, argv[1]);
} }
editorSetStatusMessage(&E, "HELP: Ctrl-Q = quit");
while (1) { while (1) {
editorRefreshScreen(&E); editorRefreshScreen(&E);
editorProcessKeypress(&E); editorProcessKeypress(&E);
+10
View File
@@ -0,0 +1,10 @@
#include "../include/editor_op.h"
#include "../include/row_op.h"
void editorInsertChar(struct editorConfig *E, int c) {
if (E->cursor_y == E->numrows) {
editorAppendRow(E, "", 0);
}
editorRowInsertChar(&E->row[E->cursor_y], E->cursor_x, c);
E->cursor_x++;
}
+49 -1
View File
@@ -1,7 +1,40 @@
#include "../include/file_io.h" #include "../include/file_io.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
char *editorRowsToString(struct editorConfig *E, int *buffer_len) {
int tot_len = 0;
int j;
char *buf;
char *p;
for (j = 0; j < E->numrows; ++j) {
tot_len += E->row[j].size + 1;
}
*buffer_len = tot_len;
buf = malloc(tot_len);
p = buf;
for (j = 0; j < E->numrows; ++j) {
memcpy(p, E->row[j].chars, E->row[j].size);
p += E->row[j].size;
*p = '\n';
p++;
}
return buf;
}
void editorOpen(struct editorConfig *E, char *filename) { void editorOpen(struct editorConfig *E, char *filename) {
FILE *fp = fopen(filename, "r"); FILE *fp;
free(E->filename);
E->filename = strdup(filename);
fp = fopen(filename, "r");
if (!fp) if (!fp)
die("fopen"); die("fopen");
@@ -19,3 +52,18 @@ void editorOpen(struct editorConfig *E, char *filename) {
free(line); free(line);
fclose(fp); fclose(fp);
} }
void editorSave(struct editorConfig *E) {
int len;
char *buf;
int fd;
if (E->filename == NULL) {
return;
}
buf = editorRowsToString(E, &len);
fd = open(E->filename, O_RDWR | O_CREAT, 0644);
ftruncate(fd, len);
write(fd, buf, len);
close(fd);
free(buf);
}
+6
View File
@@ -3,10 +3,16 @@
void initEditor(struct editorConfig *E) { void initEditor(struct editorConfig *E) {
E->cursor_x = 0; E->cursor_x = 0;
E->cursor_y = 0; E->cursor_y = 0;
E->rx = 0;
E->row_offset = 0; E->row_offset = 0;
E->col_offset = 0;
E->numrows = 0; E->numrows = 0;
E->row = NULL; E->row = NULL;
E->filename = NULL;
E->status_msg[0] = '\0';
E->status_msg_time = 0;
if (getWindowSize(&E->screenrows, &E->screencols) == -1) { if (getWindowSize(&E->screenrows, &E->screencols) == -1) {
die("getWindowSize"); die("getWindowSize");
} }
E->screenrows -= 2;
} }
+53 -6
View File
@@ -1,14 +1,22 @@
#include "../include/input.h" #include "../include/input.h"
#include "../include/editor_op.h"
#include "../include/file_io.h"
#include <stdint.h>
void editorMoveCursor(struct editorConfig *E, int key) { void editorMoveCursor(struct editorConfig *E, int key) {
erow *row = (E->cursor_y >= E->numrows) ? NULL : &E->row[E->cursor_y];
int row_len;
switch (key) { switch (key) {
case CURSOR_RIGHT: case CURSOR_RIGHT:
if (E->cursor_x != 0) { if (row && E->cursor_x < row->size) {
--E->cursor_x; ++E->cursor_x;
} else if (row && E->cursor_x == row->size) {
E->cursor_y++;
E->cursor_x = 0;
} }
break; break;
case CURSOR_DOWN: case CURSOR_DOWN:
if (E->cursor_y != E->screenrows - 1) { if (E->cursor_y < E->numrows) {
++E->cursor_y; ++E->cursor_y;
} }
break; break;
@@ -18,11 +26,20 @@ void editorMoveCursor(struct editorConfig *E, int key) {
} }
break; break;
case CURSOR_LEFT: case CURSOR_LEFT:
if (E->cursor_x != E->screencols - 1) { if (E->cursor_x != 0) {
++E->cursor_x; --E->cursor_x;
} else if (E->cursor_y > 0) {
--E->cursor_y;
E->cursor_x = E->row[E->cursor_y].size;
} }
break; break;
} }
row = (E->cursor_y >= E->numrows) ? NULL : &E->row[E->cursor_y];
row_len = row ? row->size : 0;
if (E->cursor_x > row_len) {
E->cursor_x = row_len;
}
} }
void editorProcessKeypress(struct editorConfig *E) { void editorProcessKeypress(struct editorConfig *E) {
@@ -30,6 +47,9 @@ void editorProcessKeypress(struct editorConfig *E) {
int times; int times;
switch (c) { switch (c) {
case '\r':
/* TODO */
break;
case CTRL_KEY('q'): case CTRL_KEY('q'):
write(STDOUT_FILENO, "\x1b[2J", 4); write(STDOUT_FILENO, "\x1b[2J", 4);
write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3);
@@ -37,16 +57,36 @@ void editorProcessKeypress(struct editorConfig *E) {
exit(0); exit(0);
break; break;
case CTRL_KEY('s'):
editorSave(E);
break;
case BEG_LINE: case BEG_LINE:
E->cursor_x = 0; E->cursor_x = 0;
break; break;
case END_LINE: case END_LINE:
E->cursor_x = E->screencols - 1; if (E->cursor_y < E->numrows) {
E->cursor_x = E->row[E->cursor_y].size;
}
break;
case BACKSPACE:
case CTRL_KEY('h'):
// case DEL_KEY:
/* TODO */
break; break;
case PAGE_UP: case PAGE_UP:
case PAGE_DOWN: { case PAGE_DOWN: {
if (c == PAGE_UP) {
E->cursor_y = E->row_offset;
} else if (c == PAGE_DOWN) {
E->cursor_y = E->row_offset + E->screenrows - 1;
if (E->cursor_y > E->numrows) {
E->cursor_y = E->numrows;
}
}
times = E->screenrows; times = E->screenrows;
while (--times) { while (--times) {
editorMoveCursor(E, c == PAGE_UP ? CURSOR_UP : CURSOR_DOWN); editorMoveCursor(E, c == PAGE_UP ? CURSOR_UP : CURSOR_DOWN);
@@ -59,5 +99,12 @@ void editorProcessKeypress(struct editorConfig *E) {
case CURSOR_RIGHT: case CURSOR_RIGHT:
editorMoveCursor(E, c); editorMoveCursor(E, c);
break; break;
case CTRL_KEY('l'):
case '\x1b':
break;
default:
editorInsertChar(E, c);
break;
} }
} }
+80 -6
View File
@@ -1,4 +1,8 @@
#include "../include/output.h" #include "../include/output.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
void editorDrawRows(struct editorConfig *E, struct abuf *ab) { void editorDrawRows(struct editorConfig *E, struct abuf *ab) {
int y; int y;
@@ -30,18 +34,77 @@ void editorDrawRows(struct editorConfig *E, struct abuf *ab) {
abAppend(ab, "~", 1); abAppend(ab, "~", 1);
} }
} else { } else {
len = E->row[file_row].size > E->screencols ? E->screencols len = E->row[file_row].rsize - E->col_offset;
: E->row[y].size; if (len < 0)
abAppend(ab, E->row[file_row].chars, len); len = 0;
if (len > E->screencols)
len = E->screencols;
abAppend(ab, &E->row[file_row].render[E->col_offset], len);
} }
abAppend(ab, ERASE_END_LINE, 3); abAppend(ab, ERASE_END_LINE, 3);
if (y < E->screenrows - 1) { abAppend(ab, "\r\n", 2);
abAppend(ab, "\r\n", 2); }
}
void editorScroll(struct editorConfig *E) {
E->rx = E->cursor_x;
if (E->cursor_y < E->numrows) {
E->rx = editorRowCxToRx(&E->row[E->cursor_y], E->cursor_x);
}
if (E->cursor_y < E->row_offset) {
E->row_offset = E->cursor_y;
}
if (E->cursor_y >= E->row_offset + E->screenrows) {
E->row_offset = E->cursor_y - E->screenrows + 1;
}
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;
}
}
void editorDrawStatusBar(struct editorConfig *E, struct abuf *ab) {
int len, render_len;
char status[80], render_status[80];
abAppend(ab, "\x1b[7m", 4); // inverting colors
len = snprintf(status, sizeof(status), "%.20s - %d lines",
E->filename ? E->filename : "[No Name]", E->numrows);
render_len = snprintf(render_status, sizeof(render_status), "%d/%d",
E->cursor_y + 1, E->numrows);
if (len > E->screencols) {
len = E->screencols;
}
abAppend(ab, status, len);
while (len < E->screencols) {
if (E->screencols - len == render_len) {
abAppend(ab, render_status, render_len);
break;
} else {
abAppend(ab, " ", 1);
++len;
} }
} }
abAppend(ab, "\x1b[m", 3); // normal text mode
abAppend(ab, "\r\n", 2);
}
void editorDrawMessageBar(struct editorConfig *E, struct abuf *ab) {
int msg_len = strlen(E->status_msg);
abAppend(ab, ERASE_END_LINE, 3);
if (msg_len > E->screencols) {
msg_len = E->screencols;
}
if (msg_len && time(NULL) - E->status_msg_time < 5) {
abAppend(ab, E->status_msg, msg_len);
}
} }
void editorRefreshScreen(struct editorConfig *E) { void editorRefreshScreen(struct editorConfig *E) {
editorScroll(E);
struct abuf ab = ABUF_INIT; struct abuf ab = ABUF_INIT;
char buf[32]; char buf[32];
@@ -49,8 +112,11 @@ void editorRefreshScreen(struct editorConfig *E) {
abAppend(&ab, CURSOR_TOP_LEFT, 3); abAppend(&ab, CURSOR_TOP_LEFT, 3);
editorDrawRows(E, &ab); editorDrawRows(E, &ab);
editorDrawStatusBar(E, &ab);
editorDrawMessageBar(E, &ab);
snprintf(buf, sizeof(buf), "\x1b[%d;%dH", E->cursor_y + 1, E->cursor_x + 1); 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)); abAppend(&ab, buf, strlen(buf));
abAppend(&ab, SHOW_CURSOR, 6); abAppend(&ab, SHOW_CURSOR, 6);
@@ -58,3 +124,11 @@ void editorRefreshScreen(struct editorConfig *E) {
write(STDOUT_FILENO, ab.b, ab.len); write(STDOUT_FILENO, ab.b, ab.len);
abFree(&ab); abFree(&ab);
} }
void editorSetStatusMessage(struct editorConfig *E, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vsnprintf(E->status_msg, sizeof(E->status_msg), fmt, ap);
va_end(ap);
E->status_msg_time = time(NULL);
}
+72
View File
@@ -1,4 +1,56 @@
#include "../include/row_op.h" #include "../include/row_op.h"
#include <stdlib.h>
#include <string.h>
int editorRowCxToRx(erow *row, int cursor_x) {
int render_x = 0;
int i;
for (i = 0; i < cursor_x; ++i) {
if (row->chars[i] == '\t') {
render_x += (TAB_LENGTH - 1) - (render_x % TAB_LENGTH);
}
render_x++;
}
return render_x;
}
/**
* \fn editorUpdateRow(erow *row)
* \brief Copy content of \p row in \p row->render.
* */
void editorUpdateRow(erow *row) {
int i, i_render;
int tabs = 0;
// counting number of tabs
for (i = 0; i < row->size; ++i) {
tabs +=
(row->chars[i] == '\t'); /**< increment tabs of 1 if chars[i] is one. */
}
free(row->render);
row->render = malloc(row->size + tabs * (TAB_LENGTH - 1) +
1); /**< Tabs needs TAB_LENGTH chars so TAB_LENGTH - 1
more than the first already counted. */
// end of counting
i_render = 0;
for (i = 0; i < row->size; ++i) {
if (row->chars[i] == '\t') {
row->render[i_render++] = ' ';
while (i_render % TAB_LENGTH) {
row->render[i_render++] =
' '; /**< Addind the right amount of spaces for tabs */
}
} else {
row->render[i_render++] = row->chars[i];
}
}
row->render[i_render] = '\0'; // Don't forget the end of string character.
row->rsize = i_render;
}
void editorAppendRow(struct editorConfig *E, char *s, size_t len) { void editorAppendRow(struct editorConfig *E, char *s, size_t len) {
int at; int at;
@@ -9,5 +61,25 @@ void editorAppendRow(struct editorConfig *E, char *s, size_t len) {
E->row[at].chars = malloc(len + 1); E->row[at].chars = malloc(len + 1);
memcpy(E->row[at].chars, s, len); memcpy(E->row[at].chars, s, len);
E->row[at].chars[len] = '\0'; E->row[at].chars[len] = '\0';
E->row[at].rsize = 0;
E->row[at].render = NULL;
editorUpdateRow(&E->row[at]);
++E->numrows; ++E->numrows;
} }
/**
* \fn editorRowInsertChar(erow *row, int at, int c)
* \param at Index of where we want to insert the char */
void editorRowInsertChar(erow *row, int at, int c) {
if (at < 0 || at > row->size) {
at = row->size;
}
row->chars = realloc(row->chars, row->size + 2);
memmove(&row->chars[at + 1], &row->chars[at], row->size - at + 1);
++row->size;
row->chars[at] = c;
editorUpdateRow(row);
}
+2 -2
View File
@@ -77,9 +77,9 @@ int editorReadKey() {
case 'B': case 'B':
return CURSOR_DOWN; return CURSOR_DOWN;
case 'C': case 'C':
return CURSOR_LEFT;
case 'D':
return CURSOR_RIGHT; return CURSOR_RIGHT;
case 'D':
return CURSOR_LEFT;
case 'H': case 'H':
return BEG_LINE; return BEG_LINE;
case 'F': case 'F':