initial work

This commit is contained in:
SuperNovaa41 2025-01-14 21:33:23 -05:00
parent a8b58d3499
commit d7dfb7a751
7 changed files with 310 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
build
*.o
.git

17
src/Makefile Normal file
View File

@ -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)

25
src/draw.c Normal file
View File

@ -0,0 +1,25 @@
#include <unistd.h>
#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);
}

8
src/draw.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef DRAW_H
#define DRAW_H
void refresh_screen(void);
void draw_editor_rows(void);
#endif

27
src/main.c Normal file
View File

@ -0,0 +1,27 @@
#include <unistd.h>
#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;
}

143
src/term.c Normal file
View File

@ -0,0 +1,143 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#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);
}

87
src/term.h Normal file
View File

@ -0,0 +1,87 @@
#include <stdlib.h>
#include <termios.h>
#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