diff --git a/Makefile b/Makefile index 5444450..06614dd 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,14 @@ -kilo: kilo.c - $(CC) kilo.c -o kilo -Wall -Wextra -pedantic -std=c99 +kilo: fn.c terminal.c + $(CC) fn.c terminal.c -o fn \ + -Wall \ + -Wextra \ + -Wbad-function-cast \ + -Wcast-align \ + -Wcast-qual \ + -Wmissing-declarations \ + -Wnested-externs \ + -Wpointer-arith \ + -Wwrite-strings \ + -Wno-discarded-qualifiers \ + -pedantic \ + -std=c99 diff --git a/fn b/fn new file mode 100755 index 0000000..3982dfe Binary files /dev/null and b/fn differ diff --git a/kilo.c b/fn.c similarity index 80% rename from kilo.c rename to fn.c index 7736da2..526728a 100644 --- a/kilo.c +++ b/fn.c @@ -17,84 +17,9 @@ #include #include -/*** defines ***/ +#include "fn.h" +#include "terminal.h" -#define KILO_VERSION "0.0.1" -#define KILO_TAB_STOP 8 -#define KILO_QUIT_TIMES 3 - -#define CTRL_KEY(k) ((k) & 0x1f) - -enum editorKey { - BACKSPACE = 127, - ARROW_LEFT = 1000, - ARROW_RIGHT, - ARROW_UP, - ARROW_DOWN, - DEL_KEY, - HOME_KEY, - END_KEY, - PAGE_UP, - PAGE_DOWN -}; - -enum editorHighlight { - HL_NORMAL = 0, - HL_COMMENT, - HL_MLCOMMENT, - HL_KEYWORD1, - HL_KEYWORD2, - HL_STRING, - HL_NUMBER, - HL_MATCH -}; - -#define HL_HIGHLIGHT_NUMBERS (1<<0) -#define HL_HIGHLIGHT_STRINGS (1<<1) - - -/*** data ***/ - -struct editorSyntax { - char *filetype; - char **filematch; - char **keywords; - char *singleline_comment_start; - char *multiline_comment_start; - char *multiline_comment_end; - int flags; -}; - -typedef struct erow { - int idx; - int size; - int rsize; - char *chars; - char *render; - unsigned char *hl; - int hl_open_comment; -} erow; - -struct editorConfig { - int cx, cy; - int rx; // The x position in the rendered line (for tabs) - int rowoff; - int coloff; - int screenrows; - int screencols; - int numrows; - erow *row; - int dirty; - char *filename; - char statusmsg[80]; - time_t statusmsg_time; - struct editorSyntax *syntax; - struct termios orig_termios; -}; - -struct editorConfig E; - -/*** filetypes ***/ char *C_HL_extensions[] = { ".c", ".h", ".cpp", NULL }; char *C_HL_keywords[] = { @@ -117,128 +42,6 @@ struct editorSyntax HLDB[] = { #define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0])) -/*** prototypes ***/ - -void editorSetStatusMessage(const char *fmt, ...); -void editorRefreshScreen(); -char *editorPrompt(char *prompt, void (*callback)(char *, int)); - -/*** terminal ***/ - -void die(const char *s) { - write(STDOUT_FILENO, "\x1b[2J", 4); - write(STDOUT_FILENO, "\x1b[H", 3); - perror(s); - exit(1); -} - -void disableRawMode() { - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) - die("tcsetattr"); -} - -void enableRawMode() { - if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) - die("tcgetattr"); - atexit(disableRawMode); - - struct termios raw = E.orig_termios; - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_oflag &= ~(OPOST); - raw.c_cflag |= (CS8); - raw.c_lflag &= ~(ECHO | ICANON | ISIG); - raw.c_cc[VMIN] = 0; - raw.c_cc[VTIME] = 1; - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) - die("tcsetattr"); -} - -int editorReadKey() { - int nread; - char c; - while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { - if (nread == -1 && errno != EAGAIN) die("read"); - } - - // Process escape sequences - if (c == '\x1b') { - char seq[3]; - - if (read(STDIN_FILENO, &seq[0], 1) != 1) return '\x1b'; - if (read(STDIN_FILENO, &seq[1], 1) != 1) return '\x1b'; - - if (seq[0] == '[') { - if (seq[1] >= '0' && seq[1] <= '9') { - if (read(STDIN_FILENO, &seq[2], 1) != 1) return '\x1b'; - if (seq[2] == '~') { - switch (seq[1]) { - case '1': return HOME_KEY; - case '3': return DEL_KEY; - case '4': return END_KEY; - case '5': return PAGE_UP; - case '6': return PAGE_DOWN; - case '7': return HOME_KEY; - case '8': return END_KEY; - } - } - } else { - switch (seq[1]) { - case 'A': return ARROW_UP; - case 'B': return ARROW_DOWN; - case 'C': return ARROW_RIGHT; - case 'D': return ARROW_LEFT; - } - } - } else if (seq[0] == '0') { - switch (seq[1]) { - case 'H': return HOME_KEY; - case 'F': return END_KEY; - } - } - - return '\x1b'; - } else { - return c; - } -} - -int getCursorPosition(int *rows, int *cols) { - char buf[32]; - unsigned int i = 0; - - if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) // CPR (custor position report) - return -1; - - while (i < sizeof(buf) - 1) { - if (read(STDIN_FILENO, &buf[i], 1) != 1) break; - if (buf[i] == 'R') break; - i++; - } - buf[i] = '\0'; - - if (buf[0] != '\x1b' || buf[1] != '[') return -1; - if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) return -1; - - return 0; -} - -int getWindowSize(int *rows, int *cols) { - struct winsize ws; - - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { - // Move cursor to the lower right as a fallback if TIOCGWINSZ does - // not work. We count the columns and rows then by hand. - if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) - return -1; - return getCursorPosition(rows, cols); - return -1; - } else { - *cols = ws.ws_col; - *rows = ws.ws_row; - return 0; - } -} /*** syntax highlighting ***/ @@ -413,7 +216,7 @@ int editorRowCxToRx(erow *row, int cx) { int j; for (j=0; jchars[j] == '\t') { - rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP); + rx += (FN_TAB_STOP - 1) - (rx % FN_TAB_STOP); } rx++; } @@ -425,7 +228,7 @@ int editorRowRxToCx(erow *row, int rx) { int cx; for (cx=0; cx < row->size; cx++) { if (row->chars[cx] == '\t') - cur_rx += (KILO_TAB_STOP - 1) - (cur_rx % KILO_TAB_STOP); + cur_rx += (FN_TAB_STOP - 1) - (cur_rx % FN_TAB_STOP); cur_rx++; if (cur_rx > rx) return cx; @@ -441,13 +244,13 @@ void editorUpdateRow(erow *row) { } free(row->render); - row->render = malloc(row->size + tabs*(KILO_TAB_STOP - 1) + 1); + row->render = malloc(row->size + tabs*(FN_TAB_STOP - 1) + 1); int idx = 0; for (j=0; jsize; j++) { if (row->chars[j] == '\t') { row->render[idx++] = ' '; - while (idx % KILO_TAB_STOP != 0) row->render[idx++] = ' '; + while (idx % FN_TAB_STOP != 0) row->render[idx++] = ' '; } else { row->render[idx++] = row->chars[j]; } @@ -764,7 +567,7 @@ void editorDrawRows(struct abuf *ab) { if (E.numrows == 0 && y == E.screenrows / 3) { char welcome[80]; int welcomelen = snprintf(welcome, sizeof(welcome), - "Kilo editor -- version %s", KILO_VERSION); + "FuNote v%s", FN_VERSION); if (welcomelen > E.screencols) welcomelen = E.screencols; int padding = (E.screencols - welcomelen) / 2; if (padding) { @@ -823,9 +626,9 @@ void editorDrawRows(struct abuf *ab) { void editorDrawStatusBar(struct abuf *ab) { abAppend(ab, "\x1b[7m", 4); char status[80], rstatus[80]; - int len = snprintf(status, sizeof(status), "%.20s - %d lines %s", - E.filename ? E.filename : "[No Name]", E.numrows, - E.dirty ? "(modified)" : ""); + int len = snprintf(status, sizeof(status), "%.20s%s", + E.filename ? E.filename : "[No Name]", + E.dirty ? "*" : ""); int rlen = snprintf(rstatus, sizeof(rstatus), "%s | %d/%d", E.syntax ? E.syntax->filetype : "no ft", E.cy + 1, E.numrows); if (len > E.screencols) len = E.screencols; @@ -963,7 +766,7 @@ void editorMoveCursor(int key) { void editorProcessKeypress() { - static int quit_times = KILO_QUIT_TIMES; + static int quit_times = FN_QUIT_TIMES; int c = editorReadKey(); // Blocking! @@ -1039,7 +842,7 @@ void editorProcessKeypress() { break; } - quit_times = KILO_QUIT_TIMES; + quit_times = FN_QUIT_TIMES; } /*** init ***/ diff --git a/fn.h b/fn.h new file mode 100644 index 0000000..32786b2 --- /dev/null +++ b/fn.h @@ -0,0 +1,88 @@ +#ifndef _FN_H +#define _FN_H + +#define FN_VERSION "0.2" +#define FN_TAB_STOP 4 +#define FN_QUIT_TIMES 2 + +#define CTRL_KEY(k) ((k) & 0x1f) + +enum editorKey { + BACKSPACE = 127, + ARROW_LEFT = 1000, + ARROW_RIGHT, + ARROW_UP, + ARROW_DOWN, + DEL_KEY, + HOME_KEY, + END_KEY, + PAGE_UP, + PAGE_DOWN +}; + +enum editorHighlight { + HL_NORMAL = 0, + HL_COMMENT, + HL_MLCOMMENT, + HL_KEYWORD1, + HL_KEYWORD2, + HL_STRING, + HL_NUMBER, + HL_MATCH +}; + +#define HL_HIGHLIGHT_NUMBERS (1<<0) +#define HL_HIGHLIGHT_STRINGS (1<<1) + + +/*** data ***/ + +struct editorSyntax { + char *filetype; + char **filematch; + char **keywords; + char *singleline_comment_start; + char *multiline_comment_start; + char *multiline_comment_end; + int flags; +}; + +typedef struct erow { + int idx; + int size; + int rsize; + char *chars; + char *render; + unsigned char *hl; + int hl_open_comment; +} erow; + +struct editorConfig { + int cx, cy; + int rx; // The x position in the rendered line (for tabs) + int rowoff; + int coloff; + int screenrows; + int screencols; + int numrows; + erow *row; + int dirty; + char *filename; + char statusmsg[80]; + time_t statusmsg_time; + struct editorSyntax *syntax; + struct termios orig_termios; +}; + +struct editorConfig E; + +/*** filetypes ***/ + + +/*** prototypes ***/ + +void editorSetStatusMessage(const char *fmt, ...); +void editorRefreshScreen(); +char *editorPrompt(char *prompt, void (*callback)(char *, int)); + +#endif diff --git a/terminal.c b/terminal.c new file mode 100644 index 0000000..318bacf --- /dev/null +++ b/terminal.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "fn.h" +#include "terminal.h" + +void die(const char *s) { + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, "\x1b[H", 3); + perror(s); + exit(1); +} + +void disableRawMode() { + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) + die("tcsetattr"); +} + +void enableRawMode() { + if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) + die("tcgetattr"); + atexit(disableRawMode); + + struct termios raw = E.orig_termios; + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag &= ~(OPOST); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | ISIG); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) + die("tcsetattr"); +} + +int editorReadKey() { + int nread; + char c; + while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { + if (nread == -1 && errno != EAGAIN) die("read"); + } + + // Process escape sequences + if (c == '\x1b') { + char seq[3]; + + if (read(STDIN_FILENO, &seq[0], 1) != 1) return '\x1b'; + if (read(STDIN_FILENO, &seq[1], 1) != 1) return '\x1b'; + + if (seq[0] == '[') { + if (seq[1] >= '0' && seq[1] <= '9') { + if (read(STDIN_FILENO, &seq[2], 1) != 1) return '\x1b'; + if (seq[2] == '~') { + switch (seq[1]) { + case '1': return HOME_KEY; + case '3': return DEL_KEY; + case '4': return END_KEY; + case '5': return PAGE_UP; + case '6': return PAGE_DOWN; + case '7': return HOME_KEY; + case '8': return END_KEY; + } + } + } else { + switch (seq[1]) { + case 'A': return ARROW_UP; + case 'B': return ARROW_DOWN; + case 'C': return ARROW_RIGHT; + case 'D': return ARROW_LEFT; + } + } + } else if (seq[0] == '0') { + switch (seq[1]) { + case 'H': return HOME_KEY; + case 'F': return END_KEY; + } + } + + return '\x1b'; + } else { + return c; + } +} + +int getCursorPosition(int *rows, int *cols) { + char buf[32]; + unsigned int i = 0; + + if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) // CPR (custor position report) + return -1; + + while (i < sizeof(buf) - 1) { + if (read(STDIN_FILENO, &buf[i], 1) != 1) break; + if (buf[i] == 'R') break; + i++; + } + buf[i] = '\0'; + + if (buf[0] != '\x1b' || buf[1] != '[') return -1; + if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) return -1; + + return 0; +} + +int getWindowSize(int *rows, int *cols) { + struct winsize ws; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + // Move cursor to the lower right as a fallback if TIOCGWINSZ does + // not work. We count the columns and rows then by hand. + if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) + return -1; + return getCursorPosition(rows, cols); + return -1; + } else { + *cols = ws.ws_col; + *rows = ws.ws_row; + return 0; + } +} diff --git a/terminal.h b/terminal.h new file mode 100644 index 0000000..05a5cb0 --- /dev/null +++ b/terminal.h @@ -0,0 +1,13 @@ +#ifndef _TERMINAL_H +#define _TERMINAL_H + +void die(const char *s); + +void disableRawMode(); +void enableRawMode(); + +int editorReadKey(); +int getCursorPosition(int *rows, int *cols); +int getWindowSize(int *rows, int *cols); + +#endif