From d7dfb7a751ea193384e0cf7cdc1db0ffea14f6a6 Mon Sep 17 00:00:00 2001 From: SuperNovaa41 Date: Tue, 14 Jan 2025 21:33:23 -0500 Subject: [PATCH] initial work --- .gitignore | 3 ++ src/Makefile | 17 ++++++ src/draw.c | 25 +++++++++ src/draw.h | 8 +++ src/main.c | 27 ++++++++++ src/term.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/term.h | 87 +++++++++++++++++++++++++++++++ 7 files changed, 310 insertions(+) create mode 100644 .gitignore create mode 100644 src/Makefile create mode 100644 src/draw.c create mode 100644 src/draw.h create mode 100644 src/main.c create mode 100644 src/term.c create mode 100644 src/term.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d65c35 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +*.o +.git diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..12aeae7 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,17 @@ +TARGET=editor +CC=gcc + +OBJ = main.o draw.o term.o + +$(TARGET): $(OBJ) + mkdir -p ../build + $(CC) -o $(TARGET) $(OBJ) -g + mv $(TARGET) ../build/ + +main.o: term.h draw.h +term.o: term.h draw.h +draw.o: term.h draw.h + +.PHONY: clean +clean: + rm -rf ../build $(OBJ) diff --git a/src/draw.c b/src/draw.c new file mode 100644 index 0000000..01f8aaf --- /dev/null +++ b/src/draw.c @@ -0,0 +1,25 @@ +#include + +#include "draw.h" +#include "term.h" + +/** BEGIN extern section **/ + +extern editor_t editor; +extern screen_buffer_t screen_buffer; + +/** END extern section **/ + +void refresh_screen(void) +{ + draw_editor_rows(); + + write(STDOUT_FILENO, screen_buffer.text, screen_buffer.len); +} + +void draw_editor_rows(void) +{ + size_t i; + for (i = 0; i < editor.rows - 1; i++) + screen_buffer_append(&screen_buffer, "~\r\n", 3); +} diff --git a/src/draw.h b/src/draw.h new file mode 100644 index 0000000..365066c --- /dev/null +++ b/src/draw.h @@ -0,0 +1,8 @@ +#ifndef DRAW_H +#define DRAW_H + +void refresh_screen(void); + +void draw_editor_rows(void); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a2dadd9 --- /dev/null +++ b/src/main.c @@ -0,0 +1,27 @@ +#include + +#include "draw.h" +#include "term.h" + +editor_t editor; +screen_buffer_t screen_buffer; + +int main(void) +{ + char c; + + setup_terminal(); + + refresh_screen(); // want to draw first since we're going to be waiting on the read + + while (1) { + read(STDIN_FILENO, &c, 1); + if (c == '\004') + break; + refresh_screen(); + } + + kill_application(); + + return EXIT_SUCCESS; +} diff --git a/src/term.c b/src/term.c new file mode 100644 index 0000000..ae41ad9 --- /dev/null +++ b/src/term.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include + + +#include "term.h" + +/** BEGIN extern section **/ + +extern editor_t editor; +extern screen_buffer_t screen_buffer; + +/** END extern section **/ + +void reset_input_mode(void) +{ + int err; + /** + * STDIN_FILENO - the file descriptor for STDIN, provuded by unistd + * TCSANOW - means to enact the change NOW, provided by termios + */ + err = tcsetattr(STDIN_FILENO, TCSANOW, &(editor.term_settings)); + if (-1 == err) { + fprintf(stderr, "tcsetattr failed.\n"); + exit(EXIT_FAILURE); + } +} + +void save_input_mode(void) +{ + int err; + + err = tcgetattr(STDIN_FILENO, &(editor.term_settings)); + if (-1 == err) { + fprintf(stderr, "tcgetattr failed.\n"); + exit(EXIT_FAILURE); + } + atexit(kill_application); +} + +void set_input_mode(void) +{ + struct termios tattr; + int err; + + // make sure we're actually in a terminal + if (!isatty(STDIN_FILENO)) { + fprintf(stderr, "Not a terminal.\n"); + exit(EXIT_FAILURE); + } + + // need to save the terminal settings so that + // we can restore them on kill + save_input_mode(); + + err = tcgetattr(STDIN_FILENO, &tattr); + if (-1 == err) { + fprintf(stderr, "tcgetattr failed.\n"); + exit(EXIT_FAILURE); + } + tattr.c_lflag &= ~(ICANON|ECHO); // clears icanon and echo flags + + /** + * This is the minimum number of bytes in the input + * queue in order for read to return. + * We need this as one because it will be constantly looking for one char input. + * + * Zero would be consistently reading null, + * any higher would bel ooking for a specific amount + * of characters each time it tries to read. + */ + tattr.c_cc[VMIN] = 1; + + /** + * This is specifying how long we want to wait for input + * before returning. + * We want this to be set to zero so that + * we are constantly reading. + */ + tattr.c_cc[VTIME] = 0; + + /** + * TCSAFLUSH waits for all of the output in the buffer + * to be outputted before we discard all of the settings + * and reset the terminal mode + */ + err = tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr); + if (-1 == err) { + fprintf(stderr, "tcsetattr failed.\n"); + exit(EXIT_FAILURE); + } +} + +void setup_terminal(void) +{ + struct winsize win; + int err; + + set_input_mode(); + + err = ioctl(STDOUT_FILENO, TIOCGWINSZ, &win); + if (-1 == err) { + fprintf(stderr, "ioctl w/ TIOCGWINSZ failed to fetch screen size.\n"); + exit(EXIT_FAILURE); + } + + editor.cols = win.ws_col; + editor.rows = win.ws_row; +} + +void kill_application(void) +{ + /** + * TODO: implement more things that need to be cleaned up when + * killing the application + */ + reset_input_mode(); + + screen_buffer_free(&screen_buffer); +} + + +int screen_buffer_append(screen_buffer_t *buf, const char *in, size_t len) +{ + // Need to realloc to allow for the input to fit into the buffer + char* new = realloc(buf->text, buf->len + len); + + if (NULL == new) return -1; + + memcpy(&new[buf->len], in, len); + buf->text = new; + buf->len += len; + + return 0; +} + +void screen_buffer_free(screen_buffer_t *buf) +{ + free(buf->text); +} diff --git a/src/term.h b/src/term.h new file mode 100644 index 0000000..311fa76 --- /dev/null +++ b/src/term.h @@ -0,0 +1,87 @@ +#include +#include + +#ifndef TERM_H +#define TERM_H + +typedef struct { + struct termios term_settings; + size_t cols, rows; + int cx, cy; // cursor pos +} editor_t; + +typedef struct { + char* text; + size_t len; +} screen_buffer_t; + +/** + * # reset_input_mode + * + * Resets the term settings back to their original configuration + * + */ +void reset_input_mode(void); + +/** + * # save_input_mode + * + * Saves the current terminal settings, so that they can be restored + * + */ +void save_input_mode(void); + +/** + * # set_input_mode + * + * Sets the current terminal settings to enable non-canonical mode + * so we can fully control the screen to employ the editor + * + */ +void set_input_mode(void); + +/** + * # setup_terminal + * + * Sets the variables and initializes various things to make + * the editor usable + * + */ +void setup_terminal(void); + +/** + * # kill_application + * + * Frees, resets, etc the things we need to do when closing the + * application so everything returns to normal after closing + * + */ +void kill_application(void); + +/** + * # screen_buffer_append + * + * - screen_buffer_t* buf : The screen buffer + * - const char* in : The input text + * - size_t len : Length of the input text + * + * Adds to the screen buffer + * + * ## RETURN VALUE + * + * Returns -1 on failure, 0 on success + * + */ +int screen_buffer_append(screen_buffer_t* buf, const char* in, size_t len); + +/** + * # screen_buffer_free + * + * - screen_buffer_t* buf + * + * Frees the screen buffer + * + */ +void screen_buffer_free(screen_buffer_t* buf); + +#endif