summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2022-04-26 02:56:53 +0200
committerJohnny Richard <johnny@johnnyrichard.com>2022-04-26 02:56:53 +0200
commit0f3b356ebfe533d8135cf05f02fe1ff53cfe49b0 (patch)
treef8710b8322ec5f65fc29f66379b2fcc363035c11
parent2f249f6be2e49e57fd59ecd50f73e6a734c6bbb4 (diff)
Add cursor movement
-rw-r--r--.gitignore1
-rw-r--r--Makefile4
-rw-r--r--string_builder.c42
-rw-r--r--string_builder.h31
-rw-r--r--ted.c88
5 files changed, 153 insertions, 13 deletions
diff --git a/.gitignore b/.gitignore
index 8490248..a8cd213 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
+*.o
ted
tags
diff --git a/Makefile b/Makefile
index 3968073..1f4421f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,2 +1,2 @@
-ted: ted.c
- $(CC) ted.c -o ted -Wall -Wextra -pedantic -std=c11
+ted: ted.c string_builder.o
+ $(CC) ted.c string_builder.o -o ted -ggdb -Wall -Wextra -pedantic -std=c11
diff --git a/string_builder.c b/string_builder.c
new file mode 100644
index 0000000..fa26e44
--- /dev/null
+++ b/string_builder.c
@@ -0,0 +1,42 @@
+/*
+ * Terminal Text Editor
+ * Copyright (C) 2022 Johnny Richard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include "string_builder.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+void
+string_builder_append(string_builder_t *sb, const char *s, int len)
+{
+ char *snew = realloc(sb->data, sb->len + len);
+
+ if (snew == NULL) {
+ return;
+ }
+
+ memcpy(&snew[sb->len], s, len);
+ sb->data = snew;
+ sb->len += len;
+}
+
+void
+string_builder_destroy(string_builder_t *sb)
+{
+ free(sb->data);
+}
+
diff --git a/string_builder.h b/string_builder.h
new file mode 100644
index 0000000..49cdf3a
--- /dev/null
+++ b/string_builder.h
@@ -0,0 +1,31 @@
+/*
+ * Terminal Text Editor
+ * Copyright (C) 2022 Johnny Richard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef STRING_BUILDER_H
+#define STRING_BUILDER_H
+
+typedef struct string_builder {
+ char *data;
+ int len;
+} string_builder_t;
+
+#define STRING_BUILDER_INIT { NULL, 0 }
+
+void string_builder_append(string_builder_t *sb, const char *s, int len);
+void string_builder_destroy(string_builder_t *sb);
+
+#endif /* STRING_BUILDER_H */
diff --git a/ted.c b/ted.c
index a01ac7e..e27ea94 100644
--- a/ted.c
+++ b/ted.c
@@ -21,13 +21,18 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
+#include "string_builder.h"
+
#define CTRL_KEY(k) ((k) & 0x1F)
+#define TED_VERSION "0.0.1"
typedef struct editor_config {
+ int cx, cy;
int screen_rows;
int screen_cols;
struct termios orig_termios;
@@ -40,8 +45,9 @@ void editor_init(editor_config_t *ec);
char editor_read_key();
int get_cursor_position(int *rows, int *cols);
int get_window_size(int *rows, int *cols);
-void editor_process_key();
-void editor_draw_rows(editor_config_t *ec);
+void editor_move_cursor(editor_config_t *ec, char key);
+void editor_process_key(editor_config_t *ec);
+void editor_draw_rows(editor_config_t *ec, string_builder_t *sb);
void editor_clear_screen();
void editor_refresh_screen(editor_config_t *ec);
void disable_raw_mode();
@@ -57,7 +63,7 @@ main()
while (true) {
editor_refresh_screen(&E);
- editor_process_key();
+ editor_process_key(&E);
}
return EXIT_SUCCESS;
@@ -66,7 +72,9 @@ main()
void
editor_init(editor_config_t *ec)
{
- if (get_window_size(&ec->screen_rows, &ec->screen_rows) == -1) {
+ ec->cx = 0;
+ ec->cy = 0;
+ if (get_window_size(&ec->screen_rows, &ec->screen_cols) == -1) {
die("get_window_size");
}
}
@@ -133,7 +141,26 @@ get_window_size(int *rows, int *cols)
}
void
-editor_process_key()
+editor_move_cursor(editor_config_t *ec, char key)
+{
+ switch (key) {
+ case 'h':
+ ec->cx--;
+ break;
+ case 'l':
+ ec->cx++;
+ break;
+ case 'k':
+ ec->cy--;
+ break;
+ case 'j':
+ ec->cy++;
+ break;
+ }
+}
+
+void
+editor_process_key(editor_config_t *ec)
{
char c = editor_read_key();
@@ -142,6 +169,12 @@ editor_process_key()
editor_clear_screen();
exit(EXIT_SUCCESS);
break;
+ case 'h':
+ case 'j':
+ case 'k':
+ case 'l':
+ editor_move_cursor(ec, c);
+ break;
}
}
@@ -153,13 +186,34 @@ editor_clear_screen()
}
void
-editor_draw_rows(editor_config_t *ec)
+editor_draw_rows(editor_config_t *ec, string_builder_t *sb)
{
for (int y = 0; y < ec->screen_rows; ++y) {
- write(STDOUT_FILENO, "~", 1);
+ if (y == ec->screen_rows / 3) {
+ char welcome[80];
+ int welcomelen = snprintf(welcome, sizeof(welcome), "Ted editor --- version %s", TED_VERSION);
+ if (welcomelen > ec->screen_cols) {
+ welcomelen = ec->screen_cols;
+ }
+
+ int padding = (ec->screen_cols - welcomelen) / 2;
+ if (padding) {
+ string_builder_append(sb, "~", 1);
+ padding--;
+ }
+ while (padding--) {
+ string_builder_append(sb, " ", 1);
+ }
+
+ string_builder_append(sb, welcome, welcomelen);
+ } else {
+ string_builder_append(sb, "~", 1);
+ }
+
+ string_builder_append(sb, "\x1b[K", 3);
if (y < ec->screen_rows - 1) {
- write(STDOUT_FILENO, "\r\n", 2);
+ string_builder_append(sb, "\r\n", 2);
}
}
}
@@ -167,9 +221,21 @@ editor_draw_rows(editor_config_t *ec)
void
editor_refresh_screen(editor_config_t *ec)
{
- editor_clear_screen();
- editor_draw_rows(ec);
- write(STDOUT_FILENO, "\x1b[H", 3);
+ string_builder_t sb = STRING_BUILDER_INIT;
+
+ string_builder_append(&sb, "\x1b[?25l", 6);
+ string_builder_append(&sb, "\x1b[H", 3);
+
+ editor_draw_rows(ec, &sb);
+
+ char buf[32];
+ snprintf(buf, sizeof(buf), "\x1b[%d;%dH", ec->cy + 1, ec->cx + 1);
+ string_builder_append(&sb, buf, strlen(buf));
+
+ string_builder_append(&sb, "\x1b[?25h", 6);
+
+ write(STDOUT_FILENO, sb.data, sb.len);
+ string_builder_destroy(&sb);
}
void