14 Commits

Author SHA1 Message Date
d1978a3b98 Code cleanups and editor fixups.
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
2025-11-24 10:54:48 -08:00
5ee8234ab7 Update the manpage.
Print the core dump k-command correctly.
2025-11-24 10:23:39 -08:00
f82d1f8831 move nix to nixos config 2025-11-24 10:22:48 -08:00
2019ec10ce local testing updates 2025-11-23 19:15:19 -08:00
0110f82705 bump version
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
2025-11-23 14:26:17 -08:00
a62a8e50fa find_prev_word and delete_prev_word work. 2025-11-23 14:24:49 -08:00
33e19e7d76 add Makefile for basic build 2025-11-23 11:48:46 -08:00
fd01e3593f delete next word complete, delete prev in progress. 2025-11-23 11:48:35 -08:00
47bbc5339c forward/backward word. 2025-11-23 00:19:25 -08:00
2962a6c92e start word nav 2025-11-22 23:31:49 -08:00
7fa887273b move nix to nixos config 2025-11-22 23:31:49 -08:00
fb02f37512 make ASan a compile time option 2025-11-22 23:27:34 -08:00
1722dbee0b Fix check for render realloc. 2025-11-22 12:50:22 -08:00
14199afeb5 bump version
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
2025-11-22 12:36:41 -08:00
7 changed files with 206 additions and 19 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
*.log
build
ke
*.txt

View File

@@ -2,15 +2,29 @@ cmake_minimum_required(VERSION 3.15)
project(ke C) # Specify C language explicitly
set(CMAKE_C_STANDARD 99)
set(KE_VERSION "1.0.8")
set(KE_VERSION "1.0.12")
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")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
# Optionally enable AddressSanitizer (ASan)
option(ENABLE_ASAN "Enable AddressSanitizer for builds" OFF)
if (ENABLE_ASAN)
message(STATUS "ASan enabled")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
# Ensure the sanitizer is linked too (especially important on some platforms)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
endif()
include(GNUInstallDirs)
# Add executable
add_executable(ke main.c)
# Define KE_VERSION for use in C code (e.g., #define KE_VERSION)
target_compile_definitions(ke PRIVATE KE_VERSION="ke version ${KE_VERSION}")
install(TARGETS ke RUNTIME DESTINATION bin)
install(FILES ke.1 TYPE MAN)
install(TARGETS ke RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES ke.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)

21
Makefile Normal file
View File

@@ -0,0 +1,21 @@
TARGET := ke
KE_VERSION := devel
CFLAGS := -Wall -Wextra -pedantic -Wshadow -Werror -std=c99 -g
CFLAGS += -D_DEFAULT_SOURCE -D_XOPEN_SOURCE
CFLAGS += -fsanitize=address -fno-omit-frame-pointer
LDFLAGS := -fsanitize=address
all: $(TARGET) test.txt
$(TARGET): main.c
$(CC) $(CFLAGS) -o $(TARGET) $(LDFLAGS) main.c
clean:
rm -f $(TARGET)
.PHONY: test.txt
test.txt:
cp test.txt.bak $@

View File

@@ -11,4 +11,8 @@ It should be available via homebrew, even:
brew tap kisom/homebrew-tap
brew install ke
Released under an ISC license.
To get verbose ASAN messages:
export LSAN_OPTIONS=verbosity=1:log_threads=1
Released under an ISC license.

4
ke.1
View File

@@ -26,6 +26,8 @@ saving a file can be done with either C-k s or C-k C-s.
Delete from the cursor to the beginning of the line.
.It C-k d
Delete from the cursor to the end of the line.
.It C-k C-d
Delete the entire link.
.It C-k e
Edit a new file. Also C-k C-e.
.It C-k f
@@ -40,7 +42,7 @@ exit the editor. Also C-k C-q.
save the file, prompting for a filename if needed. Also C-k C-s.
.It C-k x
save the file and exit. Also C-k C-x.
.It C-k \
.It C-k \[char92]
Dump core.
.El
.Sh FIND

155
main.c
View File

@@ -122,6 +122,11 @@ void editor_set_status(const char *fmt, ...);
void die(const char *s);
int get_winsz(int *rows, int *cols);
void goto_line(void);
int cursor_at_eol(void);
void find_next_word(void);
void delete_next_word(void);
void find_prev_word(void);
void delete_prev_word(void);
void delete_row(int at);
void row_append_row(struct erow *row, char *s, int len);
void row_insert_ch(struct erow *row, int at, int16_t c);
@@ -364,7 +369,7 @@ erow_update(struct erow *row)
}
}
if (row->rsize) {
if (row->rsize || row->render != NULL) {
free(row->render);
row->rsize = 0;
}
@@ -463,6 +468,7 @@ die(const char *s)
}
/*
* get_winsz uses the TIOCGWINSZ to get the window size.
*
@@ -508,6 +514,121 @@ goto_line(void)
}
int
cursor_at_eol(void)
{
assert(editor.curx >= 0);
assert(editor.cury >= 0);
assert(editor.cury <= editor.nrows);
assert(editor.curx <= editor.row[editor.cury].size);
return editor.curx == editor.row[editor.cury].size;
}
void
find_next_word(void)
{
while (cursor_at_eol()) {
move_cursor(ARROW_RIGHT);
}
if (isalnum(editor.row[editor.cury].line[editor.curx])) {
while (!isspace(editor.row[editor.cury].line[editor.curx]) && !cursor_at_eol()) {
move_cursor(ARROW_RIGHT);
}
return;
}
if (isspace(editor.row[editor.cury].line[editor.curx])) {
while (isspace(editor.row[editor.cury].line[editor.curx])) {
move_cursor(ARROW_RIGHT);
}
find_next_word();
}
}
void
delete_next_word(void)
{
while (cursor_at_eol()) {
move_cursor(ARROW_RIGHT);
deletech();
}
if (isalnum(editor.row[editor.cury].line[editor.curx])) {
while (!isspace(editor.row[editor.cury].line[editor.curx]) && !cursor_at_eol()) {
move_cursor(ARROW_RIGHT);
deletech();
}
return;
}
if (isspace(editor.row[editor.cury].line[editor.curx])) {
while (isspace(editor.row[editor.cury].line[editor.curx])) {
move_cursor(ARROW_RIGHT);
deletech();
}
delete_next_word();
}
}
void
find_prev_word(void)
{
if (editor.cury == 0 && editor.curx == 0) {
return;
}
move_cursor(ARROW_LEFT);
while (cursor_at_eol() || isspace(editor.row[editor.cury].line[editor.curx])) {
if (editor.cury == 0 && editor.curx == 0) {
return;
}
move_cursor(ARROW_LEFT);
}
while (editor.curx > 0 && !isspace(editor.row[editor.cury].line[editor.curx - 1])) {
move_cursor(ARROW_LEFT);
}
}
void
delete_prev_word(void)
{
if (editor.cury == 0 && editor.curx == 0) {
return;
}
deletech();
while (editor.cury > 0 || editor.curx > 0) {
if (editor.curx == 0) {
deletech();
} else {
if (!isspace(editor.row[editor.cury].line[editor.curx - 1])) {
break;
}
deletech();
}
}
while (editor.curx > 0) {
if (isspace(editor.row[editor.cury].line[editor.curx - 1])) {
break;
}
deletech();
}
}
void
delete_row(int at)
{
@@ -588,6 +709,9 @@ insertch(int16_t c)
}
/*
* deletech
*/
void
deletech(void)
{
@@ -985,7 +1109,7 @@ void
move_cursor(int16_t c)
{
struct erow *row;
int reps;
int reps;
row = (editor.cury >= editor.nrows) ? NULL : &editor.row[editor.cury];
@@ -1109,9 +1233,15 @@ process_kcommand(int16_t c)
delete_row(editor.cury);
break;
case 'd':
if (editor.curx == 0 && cursor_at_eol()) {
delete_row(editor.cury);
return;
}
while ((editor.row[editor.cury].size - editor.curx) > 0) {
process_normal(DEL_KEY);
}
break;
case 'g':
case CTRL_KEY('g'):
@@ -1195,8 +1325,6 @@ process_normal(int16_t c)
void
process_escape(int16_t c)
{
struct erow *row = &editor.row[editor.cury];
editor_set_status("hi");
switch (c) {
@@ -1208,16 +1336,17 @@ process_escape(int16_t c)
editor.cury = 0;
editor.curx = 0;
break;
case 'b':
find_prev_word();
break;
case 'd':
delete_next_word();
break;
case 'f':
find_next_word();
break;
case BACKSPACE:
if (isalnum(row->line[editor.curx])) {
editor_set_status("is alnum");
while (editor.curx > 0 && isalnum(row->line[editor.curx])) {
process_normal(BACKSPACE);
}
} else {
editor_set_status("not alnum");
process_normal(BACKSPACE);
}
delete_prev_word();
break;
default:
editor_set_status("unknown ESC key: %04x", c);

15
test.txt.bak Normal file
View File

@@ -0,0 +1,15 @@
hello
world it is me
but I am not me