Checkpoint file split.

This commit is contained in:
2025-11-28 02:27:19 -08:00
parent 4db6077738
commit a0d760c7d2
11 changed files with 960 additions and 775 deletions

View File

@@ -21,12 +21,13 @@ include(GNUInstallDirs)
# Add executable
add_executable(ke
main.c
abuf.c
term.c
buffer.c
editor.c
core.c
core.h
main.c
)
target_compile_definitions(ke PRIVATE KE_VERSION="ke version ${KE_VERSION}")
install(TARGETS ke RUNTIME DESTINATION bin)

View File

@@ -11,7 +11,8 @@ LDFLAGS := -fsanitize=address
all: $(TARGET) test.txt
SRCS := main.c abuf.c term.c buffer.c
SRCS := main.c abuf.c term.c buffer.c editor.c core.c
HDRS := abuf.h term.h buffer.h editor.h core.h
$(TARGET): $(SRCS)
$(CC) $(CFLAGS) -o $(TARGET) $(SRCS) $(LDFLAGS)
@@ -33,3 +34,7 @@ test.txt:
gdb:
@test -f $(TARGET).pid || (echo "error: $(TARGET).pid not found" >&2; exit 1)
@gdb -p $$(cat $(TARGET).pid | tr -d ' \t\n\r') ./$(TARGET)
.PHONY: cloc
cloc:
cloc $(SRCS) $(HDRS)

22
abuf.c
View File

@@ -3,10 +3,11 @@
#include <string.h>
#include "abuf.h"
#include "core.h"
void
abuf_init(abuf *buf)
ab_init(abuf *buf)
{
assert(buf != NULL);
@@ -15,6 +16,25 @@ abuf_init(abuf *buf)
}
void
ab_init_cap(abuf *buf, const size_t cap)
{
buf->b = calloc(cap, 1);
buf->size = 0;
buf->cap = cap;
}
void
ab_resize(abuf *buf, size_t cap)
{
cap = cap_growth(buf->cap, cap);
buf->b = realloc(buf->b, cap);
assert(buf->b != NULL);
buf->cap = cap;
}
void
ab_appendch(abuf *buf, char c)
{

3
abuf.h
View File

@@ -13,10 +13,13 @@ typedef struct abuf {
size_t cap;
} abuf;
#define ABUF_INIT {NULL, 0, 0}
void ab_init(abuf *buf);
void ab_init_cap(abuf *buf, size_t cap);
void ab_resize(abuf *buf, size_t cap);
void ab_appendch(abuf *buf, char c);
void ab_append(abuf *buf, const char *s, size_t len);
void ab_prependch(abuf *buf, const char c);

View File

@@ -1,4 +1,4 @@
/* buffer.c - buffer management implementation */
/* buffer.c - multiple file buffers */
#include <assert.h>
#include <stdint.h>
@@ -8,13 +8,15 @@
#include "abuf.h"
#include "buffer.h"
#include "core.h"
#include "editor.h"
#define NO_NAME "[No Name]"
/* externs from other modules */
char *editor_prompt(char *, void (*cb)(char *, int16_t));
char *editor_prompt(const char *, void (*cb)(char *, int16_t));
static const char *
@@ -28,6 +30,7 @@ buf_basename(const char *path)
return (slash != NULL) ? (slash + 1) : path;
}
static int
buffer_find_exact_by_name(const char *name)
{
@@ -158,11 +161,10 @@ buffer_switch_prompt_cb(char *buf, const int16_t key)
size_t need = 0;
size_t used = 0;
if (key != 9) { /* TODO(kyle): extract TAB_KEY */
return; /* TAB key */
if (key != TAB_KEY) {
return;
}
n = buffer_collect_prefix_matches(buf, idxs, 64);
if (n <= 0) {
editor_set_status("No matches");
@@ -204,7 +206,7 @@ buffer_switch_prompt_cb(char *buf, const int16_t key)
static void
buffer_bind_to_editor(buffer *b)
buffer_bind_to_editor(const buffer *b)
{
if (b == NULL) {
return;
@@ -225,7 +227,8 @@ buffer_bind_to_editor(buffer *b)
}
static void buffer_extract_from_editor(buffer *b)
static void
buffer_extract_from_editor(buffer *b)
{
if (b == NULL) {
return;
@@ -317,6 +320,43 @@ buffer_save_current(void)
}
buffer *
buffer_current(void)
{
if (editor.curbuf < 0 || editor.curbuf >= editor.bufcount) {
return NULL;
}
return editor.buffers[editor.curbuf];
}
int
buffer_is_unnamed_and_empty(const buffer *b)
{
if (b == NULL) {
return 0;
}
if (b->filename != NULL) {
return 0;
}
if (b->dirty) {
return 0;
}
if (b->nrows != 0) {
return 0;
}
if (b->row != NULL) {
return 0;
}
return 1;
}
void
buffer_switch(const int idx)
{
@@ -355,7 +395,9 @@ buffer_next(void)
buffer_switch(idx);
}
void buffer_prev(void)
void
buffer_prev(void)
{
int idx = 0;
@@ -433,6 +475,11 @@ buffer_switch_by_name(void)
int idx = 0;
int n = 0;
if (editor.bufcount <= 1) {
editor_set_status("No other buffers.");
return;
}
name = editor_prompt("Switch buffer (name, TAB to complete): %s", buffer_switch_prompt_cb);
if (name == NULL) {
return;

View File

@@ -16,6 +16,23 @@ typedef struct buffer {
int mark_curx, mark_cury;
} buffer;
/* Access current buffer and convenient aliases for file-specific fields */
buffer *buffer_current(void);
#define CURBUF (buffer_current())
#define EROW (CURBUF->row)
#define ENROWS (CURBUF->nrows)
#define ECURX (CURBUF->curx)
#define ECURY (CURBUF->cury)
#define ERX (CURBUF->rx)
#define EROWOFFS (CURBUF->rowoffs)
#define ECOLOFFS (CURBUF->coloffs)
#define EFILENAME (CURBUF->filename)
#define EDIRTY (CURBUF->dirty)
#define EMARK_SET (CURBUF->mark_set)
#define EMARK_CURX (CURBUF->mark_curx)
#define EMARK_CURY (CURBUF->mark_cury)
void buffers_init(void);
int buffer_add_empty(void);
@@ -26,6 +43,8 @@ void buffer_prev(void);
void buffer_switch_by_name(void);
void buffer_close_current(void);
const char *buffer_name(buffer *b);
/* Helpers */
int buffer_is_unnamed_and_empty(const buffer *b);
#endif

64
core.c
View File

@@ -35,6 +35,70 @@ strnstr(const char *s, const char *find, size_t slen)
#endif
char
nibble_to_hex(char c)
{
c &= 0xf;
if (c < 10) {
return (char)('0' + c);
}
return (char)('A' + (c - 10));
}
void
swap_int(int *first, int *second)
{
*first ^= *second;
*second ^= *first;
*first ^= *second;
}
int
next_power_of_2(int n)
{
if (n < 2) {
n = 2;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
int
cap_growth(int cap, int sz)
{
if (cap == 0) {
cap = INITIAL_CAPACITY;
}
while (cap <= sz) {
cap = next_power_of_2(cap + 1);
}
return cap;
}
size_t
kstrnlen(const char *buf, const size_t max)
{
if (buf == NULL) {
return 0;
}
return strnlen(buf, max);
}
void
kwrite(const int fd, const char* buf, const int len)
{

11
core.h
View File

@@ -1,9 +1,11 @@
#ifndef KE_CORE_H
#define KE_CORE_H
#include <stddef.h>
#define calloc1(sz) calloc(1, sz)
#include <stddef.h>
#define INITIAL_CAPACITY 8
typedef enum key_press {
@@ -21,12 +23,17 @@ typedef enum key_press {
PG_DN = 1008,
} key_press;
#ifndef strnstr
char *strnstr(const char *s, const char *find, size_t slen);
#define INCLUDE_STRNSTR
#endif
char nibble_to_hex(char c);
void swap_int(int *first, int *second);
int next_power_of_2(int n);
int cap_growth(int cap, int sz);
size_t kstrnlen(const char *buf, size_t max);
void kwrite(int fd, const char *buf, int len);
void die(const char *s);

124
editor.c Normal file
View File

@@ -0,0 +1,124 @@
/* editor.c - editor-wide state and functions */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "abuf.h"
#include "buffer.h"
#include "core.h"
#include "editor.h"
#include "term.h"
/*
* Global editor instance
*/
struct editor editor = {
.cols = 0,
.rows = 0,
.curx = 0,
.cury = 0,
.rx = 0,
.mode = 0,
.nrows = 0,
.rowoffs = 0,
.coloffs = 0,
.row = NULL,
.killring = NULL,
.kill = 0,
.no_kill = 0,
.filename = NULL,
.dirty = 0,
.dirtyex = 0,
.mark_set = 0,
.mark_curx = 0,
.mark_cury = 0,
.uarg = 0,
.ucount = 0,
.msgtm = 0,
.buffers = NULL,
.bufcount = 0,
.curbuf = -1,
};
void
editor_set_status(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(editor.msg, sizeof(editor.msg), fmt, ap);
va_end(ap);
editor.msgtm = time(NULL);
}
void
init_editor(void)
{
editor.cols = 0;
editor.rows = 0;
if (get_winsz(&editor.rows, &editor.cols) == -1) {
die("can't get window size");
}
editor.rows--; /* status bar */
editor.rows--; /* message line */
editor.curx = editor.cury = 0;
editor.rx = 0;
editor.nrows = 0;
editor.rowoffs = editor.coloffs = 0;
editor.row = NULL;
/* don't clear out the kill ring:
* killing / yanking across files is helpful, and killring
* is initialized to NULL at program start.
*/
editor.kill = 0;
editor.no_kill = 0;
editor.msg[0] = '\0';
editor.msgtm = 0;
editor.dirty = 0;
editor.mark_set = 0;
editor.mark_cury = editor.mark_curx = 0;
/* initialize buffer system on first init */
if (editor.buffers == NULL && editor.bufcount == 0) {
buffers_init();
}
}
void
reset_editor(void)
{
/* Clear current working set. Notably, does not reset terminal
* or buffers list. */
for (int i = 0; i < editor.nrows; i++) {
ab_free(&editor.row[i]);
}
free(editor.row);
editor.row = NULL;
editor.nrows = 0;
editor.rowoffs = editor.coloffs = 0;
editor.curx = editor.cury = 0;
editor.rx = 0;
if (editor.filename != NULL) {
free(editor.filename);
editor.filename = NULL;
}
editor.dirty = 0;
editor.mark_set = 0;
editor.mark_cury = editor.mark_curx = 0;
}

47
editor.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef EDITOR_H
#define EDITOR_H
#include <termios.h>
#include <time.h>
#include "abuf.h"
#include "buffer.h"
/* TODO(kyle): remove the "per-buffer" fields completely from the editor. */
struct editor {
int rows, cols;
int curx, cury; /* per-buffer */
int rx; /* per-buffer */
int mode;
int nrows; /* per-buffer */
int rowoffs, coloffs; /* per-buffer */
abuf *row; /* per-buffer */
abuf *killring;
int kill; /* KILL CHAIN (\m/) */
int no_kill; /* don't kill in delete_row */
char *filename; /* per-buffer */
int dirty; /* per-buffer */
int dirtyex;
char msg[80];
int mark_set; /* per-buffer */
int mark_curx, mark_cury; /* per-buffer */
int uarg, ucount; /* C-u support */
time_t msgtm;
/* Multi-buffer support */
struct buffer **buffers; /* array of buffers */
int bufcount; /* number of buffers */
int curbuf; /* current buffer index */
};
extern struct editor editor;
void editor_set_status(const char *fmt, ...);
void init_editor(void);
void reset_editor(void);
#endif /* EDITOR_H */

882
main.c

File diff suppressed because it is too large Load Diff