initial work
This commit is contained in:
parent
a8b58d3499
commit
d7dfb7a751
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
build
|
||||||
|
*.o
|
||||||
|
.git
|
17
src/Makefile
Normal file
17
src/Makefile
Normal 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
25
src/draw.c
Normal 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
8
src/draw.h
Normal 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
27
src/main.c
Normal 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
143
src/term.c
Normal 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
87
src/term.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user