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