2 Commits

Author SHA1 Message Date
78e4f84f7b fix bug into goto_line
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
2025-11-28 03:12:08 -08:00
734eb6e67d ke version 2.0
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
- with multiple buffers
- some handy tab completion
- lots of cleanups
2025-11-28 02:52:24 -08:00
8 changed files with 87 additions and 46 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15)
project(ke C) # Specify C language explicitly
set(CMAKE_C_STANDARD 99)
set(KE_VERSION "1.5.6")
set(KE_VERSION "2.0.1")
set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wshadow -Werror -std=c99 -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEFAULT_SOURCE -D_XOPEN_SOURCE")

33
abuf.c
View File

@@ -6,6 +6,15 @@
#include "core.h"
static void
abuf_grow(abuf *buf, size_t delta)
{
if (buf->cap - buf->size < delta) {
ab_resize(buf, buf->cap + delta);
}
}
void
ab_init(abuf *buf)
{
@@ -38,6 +47,7 @@ ab_resize(abuf *buf, size_t cap)
void
ab_appendch(abuf *buf, char c)
{
abuf_grow(buf, 1);
ab_append(buf, &c, 1);
}
@@ -45,20 +55,10 @@ ab_appendch(abuf *buf, char c)
void
ab_append(abuf *buf, const char *s, size_t len)
{
char *nc = buf->b;
size_t sz = buf->size + len;
char *nc = NULL;
if (sz >= buf->cap) {
while (sz > buf->cap) {
if (buf->cap == 0) {
buf->cap = 1;
} else {
buf->cap *= 2;
}
}
nc = realloc(nc, buf->cap);
assert(nc != NULL);
}
abuf_grow(buf, len);
nc = buf->b;
memcpy(&nc[buf->size], s, len);
buf->b = nc;
@@ -69,6 +69,8 @@ ab_append(abuf *buf, const char *s, size_t len)
void
ab_prependch(abuf *buf, const char c)
{
abuf_grow(buf, 1);
ab_prepend(buf, &c, 1);
}
@@ -76,7 +78,10 @@ ab_prependch(abuf *buf, const char c)
void
ab_prepend(abuf *buf, const char *s, const size_t len)
{
char *nc = realloc(buf->b, buf->size + len);
char *nc = NULL;
abuf_grow(buf, len);
nc = buf->b;
assert(nc != NULL);
memmove(nc + len, nc, buf->size);

View File

@@ -71,6 +71,7 @@ buffer_collect_prefix_matches(const char *prefix, int *out_idx, const int max_ou
size_t plen = (prefix ? strlen(prefix) : 0);
for (int i = 0; i < editor.bufcount; i++) {
matched = 0;
b = editor.buffers[i];
const char *cand1 = b->filename;
@@ -267,21 +268,35 @@ buffers_init(void)
editor.buffers = NULL;
editor.bufcount = 0;
editor.curbuf = -1;
editor.bufcap = 0;
idx = buffer_add_empty();
buffer_switch(idx);
}
static void
buffer_list_resize(void)
{
buffer **newlist = NULL;
if (editor.bufcount == (int)editor.bufcap) {
editor.bufcap = cap_growth((int)editor.bufcap, editor.bufcount + 1);
newlist = realloc(editor.buffers, sizeof(buffer *) * editor.bufcap);
assert(newlist != NULL);
editor.buffers = newlist;
}
}
int
buffer_add_empty(void)
{
buffer *buf = NULL;
buffer **newlist = realloc(editor.buffers, sizeof(buffer *) * (editor.bufcount + 1));
int idx = 0;
assert(newlist != NULL);
editor.buffers = newlist;
buffer_list_resize();
buf = calloc(1, sizeof(buffer));
assert(buf != NULL);
@@ -418,6 +433,7 @@ buffer_close_current(void)
int target = 0;
int nb = 0;
/* sanity check */
if (editor.curbuf < 0 || editor.curbuf >= editor.bufcount) {
editor_set_status("No buffer to close.");
return;

View File

@@ -43,7 +43,6 @@ 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);

View File

@@ -92,6 +92,7 @@ init_editor(void)
/* initialize buffer system on first init */
if (editor.buffers == NULL && editor.bufcount == 0) {
editor.bufcap = 0;
buffers_init();
}
}

View File

@@ -32,9 +32,10 @@ struct editor {
time_t msgtm;
/* Multi-buffer support */
struct buffer **buffers; /* array of buffers */
struct buffer **buffers; /* array of buffers */
int bufcount; /* number of buffers */
int curbuf; /* current buffer index */
int curbuf; /* current buffer index */
size_t bufcap; /* current buffer capacity */
};

13
ke.1
View File

@@ -32,8 +32,11 @@ Toggle the mark.
If the mark is set, unindent the region.
.It C-k =
If the mark is set, indent the region.
.It C-k b
Switch to a buffer.
.It C-k c
Clear (flush) the kill ring.
Close the current buffer. If no other buffers are open, an empty
buffer will be opened. To exit, use C-k q.
.It C-k d
Delete from the cursor to the end of the line.
.It C-k C-d
@@ -41,7 +44,7 @@ Delete the entire line.
.It C-k e
Edit a new file. Also C-k C-e.
.It C-k f
Incremental find.
Flush the kill ring.
.It C-k g
Go to a specific line.
.It C-k j
@@ -50,6 +53,8 @@ Jump to the mark.
List the number of lines of code in a saved file.
.It C-k m
Run make(1).
.It C-k p
Switch to the next buffer.
.It C-k q
Exit the editor. If the file has unsaved changes,
a warning will be printed; a second C-k q will exit.
@@ -60,9 +65,9 @@ Reload the current buffer from disk.
.It C-k s
Save the file, prompting for a filename if needed. Also C-k C-s.
.It C-k u
Undo changes.
Undo changes (not implemented; marking this k-command as taken).
.It C-k U
Redo changes.
Redo changes (not implemented; marking this k-command as taken).
.It C-k x
save the file and exit. Also C-k C-x.
.It C-k y

56
main.c
View File

@@ -842,23 +842,37 @@ delete_region(void)
void
jump_to_position(int col, int row)
{
/* clamp position */
if (row < 0) {
row = 0;
} else if (row > editor.nrows) {
row = editor.nrows - 1;
}
/* Handle empty buffer safely */
if (ENROWS <= 0) {
ECURX = 0;
ECURY = 0;
/* Keep legacy globals in sync with per-buffer fields for rendering */
editor.curx = ECURX;
editor.cury = ECURY;
display_refresh();
return;
}
if (col < 0) {
col = 0;
} else if (row >= 0 && row < ENROWS && col > (int) EROW[row].size) {
col = (int) EROW[row].size;
}
/* clamp position using per-buffer dimensions */
if (row < 0) {
row = 0;
} else if (row >= ENROWS) {
row = ENROWS - 1;
}
ECURX = col;
ECURY = row;
if (col < 0) {
col = 0;
} else if (col > (int) EROW[row].size) {
col = (int) EROW[row].size;
}
display_refresh();
ECURX = col;
ECURY = row;
/* Keep legacy globals in sync with per-buffer fields for rendering */
editor.curx = ECURX;
editor.cury = ECURY;
display_refresh();
}
@@ -872,13 +886,13 @@ goto_line(void)
return;
}
lineno = atoi(query);
if (lineno < 1 || lineno >= ENROWS) {
editor_set_status("Line number must be between 1 and %d.",
ENROWS);
free(query);
return;
}
lineno = atoi(query);
if (lineno < 1 || lineno > ENROWS) {
editor_set_status("Line number must be between 1 and %d.",
ENROWS);
free(query);
return;
}
jump_to_position(0, lineno - 1);
free(query);