commit 852e8a136763c309ef72779ed71c1fa80d5f6e4d
Author: calliope <me@calliope.sh>
Date: Wed, 17 Sep 2025 01:23:43 -0500
hello hello
Diffstat:
| A | .gitignore | | | 4 | ++++ |
| A | README | | | 19 | +++++++++++++++++++ |
| A | hun.c | | | 245 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 268 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,4 @@
+hun
+*sw*
+*core*
+*.o
diff --git a/README b/README
@@ -0,0 +1,19 @@
+Honey Text Editor for your terminal! It's not finished.
+
+this is just my attempt to follow along with https://viewsourcecode.org/snaptoken/kilo/ but I might make some added customizations.
+
+relevant docs: https://vt100.net/docs/vt100-ug/
+
+Features:
+- Edits text?
+- vi-similar controls (modified for workman layout)
+- NOT unicode (maybe someday)
+- 💋
+
+Dependencies:
+- Terminal emulator that supports vt-100 escape sequences
+- C compiler
+
+To build:
+
+cc -std=c89 -o hun hun.c
diff --git a/hun.c b/hun.c
@@ -0,0 +1,245 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+#define CTRL_KEY(k) ((k) & 0x1f)
+
+#define NUN_VERSION "1"
+
+typedef struct
+{
+ int cx, cy;
+ struct termios termios_original;
+ int screenrows;
+ int screencols;
+} EditorConfig;
+
+EditorConfig ed_state;
+
+void die(const char *s)
+{
+ write(STDOUT_FILENO, "\x1b[2J", 4);
+ write(STDOUT_FILENO, "\x1b[H", 3);
+
+ perror(s);
+ exit(1);
+}
+
+void raw_mode_disable(void)
+{
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &ed_state.termios_original) == -1)
+ die("tcsetattr in raw_mode_disable");
+}
+
+void raw_mode_enable(void)
+{
+ struct termios raw;
+ if (tcgetattr(STDIN_FILENO, &ed_state.termios_original) == -1) die("tcgetattr");
+ atexit(raw_mode_disable);
+
+ raw = ed_state.termios_original;
+ raw.c_iflag &= ~(ICRNL | IXON | BRKINT | INPCK | ISTRIP);
+ raw.c_oflag &= ~(OPOST);
+ raw.c_cflag |= ~(CS8);
+ raw.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
+ raw.c_cc[VMIN] = 0;
+ raw.c_cc[VTIME] = 1;
+
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) die("tcsetattr");
+}
+
+char editor_read_key(void)
+{
+ int nread;
+ char ch;
+
+ while ((nread = read(STDIN_FILENO, &ch, 1)) != 1)
+ {
+ if (nread == -1 && errno != EAGAIN) die("read");
+ }
+ return ch;
+}
+
+int get_cursor_position(int *rows, int *cols)
+{
+ char buf[32];
+ unsigned int i = 0;
+
+ if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) 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 get_window_size(int *rows, int *cols)
+{
+ struct winsize ws;
+
+ if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0)
+ {
+ if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) return -1;
+ return get_cursor_position(rows, cols);
+ }
+ else
+ {
+ *cols = ws.ws_col;
+ *rows = ws.ws_row;
+ return 0;
+ }
+}
+
+/*** append buffer ***/
+
+typedef struct {
+ char *b;
+ size_t len;
+} AppendBuf;
+
+#define ABUF_INIT {NULL, 0}
+
+void abuf_append(AppendBuf *ab, const char *s, int len)
+{
+ char *new = realloc(ab->b, ab->len + len);
+
+ if (new == NULL) return;
+ memcpy(&new[ab->len], s, len);
+ ab->b = new;
+ ab->len += len;
+}
+
+void abuf_free(AppendBuf *ab)
+{
+ free(ab->b);
+}
+
+/*** output ***/
+
+void editor_draw_rows(AppendBuf *ab)
+{
+ int y;
+ for (y = 0; y < ed_state.screenrows; y++)
+ {
+ if (y == ed_state.screenrows / 3)
+ {
+ char welcome[80];
+ int welcomelen;
+ int padding;
+ welcomelen = snprintf(welcome, sizeof(welcome), "Honey Text Editor -- Version %s", NUN_VERSION);
+ if (welcomelen > ed_state.screencols)
+ welcomelen = ed_state.screencols;
+ padding = (ed_state.screencols - welcomelen) / 2;
+ if (padding)
+ {
+ abuf_append(ab, "~", 1);
+ padding--;
+ }
+ while (padding--) abuf_append(ab, " ", 1);
+ abuf_append(ab, welcome, welcomelen);
+ }
+ else
+ {
+ abuf_append(ab, "~", 1);
+ }
+
+ abuf_append(ab, "\x1b[K", 3);
+ if (y < ed_state.screenrows - 1)
+ abuf_append(ab, "\r\n", 2);
+ }
+}
+
+void editor_refresh_screen(void)
+{
+ char buf[32];
+ AppendBuf ab = ABUF_INIT;
+
+ abuf_append(&ab, "\x1b[?25l", 6);
+ abuf_append(&ab, "\x1b[H", 3);
+
+ editor_draw_rows(&ab);
+
+ snprintf(buf, sizeof(buf), "\x1b[%d;%dH", ed_state.cy + 1, ed_state.cx + 1);
+ abuf_append(&ab, buf, strlen(buf));
+
+ abuf_append(&ab, "\x1b[?25h", 6);
+
+ write(STDOUT_FILENO, ab.b, ab.len);
+ abuf_free(&ab);
+}
+
+/*** input ***/
+
+void editor_move_cursor(char key)
+{
+ switch (key)
+ {
+ case 'n':
+ ed_state.cy++;
+ break;
+ case 'e':
+ ed_state.cy--;
+ break;
+ case 'y':
+ ed_state.cx--;
+ break;
+ case 'o':
+ ed_state.cx++;
+ break;
+ }
+}
+
+void editor_process_keypress(void)
+{
+ char ch = editor_read_key();
+
+ switch(ch)
+ {
+ case CTRL_KEY('q'):
+ write(STDOUT_FILENO, "\x1b[2J", 4);
+ write(STDOUT_FILENO, "\x1b[H", 3);
+ exit(0);
+ break;
+
+ case 'n':
+ case 'e':
+ case 'y':
+ case 'o':
+ editor_move_cursor(ch);
+ break;
+ }
+}
+
+/*** init ***/
+
+void editor_init(void)
+{
+ ed_state.cx = 0;
+ ed_state.cy = 0;
+ if (get_window_size(&ed_state.screenrows, &ed_state.screencols) == -1) die("get_window_size");
+}
+
+int main(void)
+{
+ raw_mode_enable();
+ editor_init();
+ while (1)
+ {
+ editor_refresh_screen();
+ editor_process_keypress();
+ }
+ return 0;
+}