8 Commits

Author SHA1 Message Date
36013e42e4 version bump
Some checks are pending
Release / Bump Homebrew formula (push) Waiting to run
2025-11-22 12:13:56 -08:00
dd667c1ef5 revert back to older version with some previous fixes
the ai was getting wild
2025-11-22 12:13:03 -08:00
c9977b0fc0 checkpoint
Some checks are pending
Release / Bump Homebrew formula (push) Waiting to run
2025-11-22 12:00:50 -08:00
dd2c888766 update man page
Some checks are pending
Release / Bump Homebrew formula (push) Waiting to run
2025-11-22 01:48:31 -08:00
2967998893 Update README
Some checks are pending
Release / Bump Homebrew formula (push) Waiting to run
2025-11-22 01:45:59 -08:00
a400cdf5ad update README.
Some checks are pending
Release / Bump Homebrew formula (push) Waiting to run
2025-11-22 01:44:41 -08:00
c8a43fb328 typo in release 2025-11-22 01:41:14 -08:00
3ea7c31cba update workflow 2025-11-22 01:39:45 -08:00
5 changed files with 53 additions and 135 deletions

View File

@@ -10,29 +10,6 @@ permissions:
contents: write contents: write
jobs: jobs:
goreleaser:
name: GoReleaser
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache: true
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GH_CPAT }}
homebrew: homebrew:
name: Bump Homebrew formula name: Bump Homebrew formula
# Skip this job in case of git pushes to prerelease tags # Skip this job in case of git pushes to prerelease tags
@@ -49,7 +26,7 @@ jobs:
- uses: mislav/bump-homebrew-formula-action@v3 - uses: mislav/bump-homebrew-formula-action@v3
with: with:
formula-name: ke formula-name: ke
formula-path: Formula/kw.rb formula-path: Formula/ke.rb
homebrew-tap: kisom/homebrew-tap homebrew-tap: kisom/homebrew-tap
base-branch: master base-branch: master
commit-message: | commit-message: |

View File

@@ -2,10 +2,11 @@ cmake_minimum_required(VERSION 3.15)
project(ke C) # Specify C language explicitly project(ke C) # Specify C language explicitly
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
set(KE_VERSION "1.0.3") set(KE_VERSION "1.0.8")
set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wshadow -Werror -std=c99 -g") 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} -D_DEFAULT_SOURCE -D_XOPEN_SOURCE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
# Add executable # Add executable
@@ -18,4 +19,4 @@ target_compile_definitions(ke PRIVATE KE_VERSION="ke version ${KE_VERSION}")
set_target_properties(ke PROPERTIES set_target_properties(ke PROPERTIES
FOLDER bin FOLDER bin
RUNTIME_OUTPUT_DIRECTORY bin RUNTIME_OUTPUT_DIRECTORY bin
) )

View File

@@ -6,4 +6,9 @@ used fairly often.
See the man page for more info. See the man page for more info.
It should be available via homebrew, even:
brew tap kisom/homebrew-tap
brew install ke
Released under an ISC license. Released under an ISC license.

2
ke.1
View File

@@ -24,8 +24,6 @@ saving a file can be done with either C-k s or C-k C-s.
.Bl -tag -width xxxxxxxxxxxx -offset indent .Bl -tag -width xxxxxxxxxxxx -offset indent
.It C-k BACKSPACE .It C-k BACKSPACE
Delete from the cursor to the beginning of the line. Delete from the cursor to the beginning of the line.
.It C-k C-d
Delete the current row.
.It C-k d .It C-k d
Delete from the cursor to the end of the line. Delete from the cursor to the end of the line.
.It C-k e .It C-k e

151
main.c
View File

@@ -14,7 +14,6 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -25,6 +24,10 @@
#include <unistd.h> #include <unistd.h>
#ifndef KE_VERSION
#define KE_VERSION "ke dev build"
#endif
#define ESCSEQ "\x1b[" #define ESCSEQ "\x1b["
#define CTRL_KEY(key) ((key)&0x1f) #define CTRL_KEY(key) ((key)&0x1f)
#define TAB_STOP 8 #define TAB_STOP 8
@@ -44,33 +47,35 @@
#define TAB_STOP 8 #define TAB_STOP 8
#define INITIAL_BUFSIZE 64 #define INITIAL_CAPACITY 64
int int
next_power_of_2(int n) next_power_of_2(int n)
{ {
if (n < 2) {
n = 2;
}
n--; n--;
n |= n >> 1; n |= n >> 1;
n |= n >> 2; n |= n >> 2;
n |= n >> 4; n |= n >> 4;
n |= n >> 8; n |= n >> 8;
n |= n >> 16; n |= n >> 16;
return n+1;
return n + 1;
} }
/*
* cap_growth is a generalized strategy to growing buffers.
*/
int int
cap_growth(int cap, int sz) cap_growth(int cap, int sz)
{ {
if (cap == 0) { if (cap == 0) {
return INITIAL_BUFSIZE; cap = INITIAL_CAPACITY;
} }
while (sz < cap) { while (cap <= sz) {
cap = next_power_of_2(cap); cap = next_power_of_2(cap + 1);
} }
return cap; return cap;
@@ -107,8 +112,8 @@ struct erow {
char nibble_to_hex(char c); char nibble_to_hex(char c);
int erow_render_to_cursor(struct erow *row, int cx); int erow_render_to_cursor(struct erow *row, int cx);
int erow_cursor_to_render(struct erow *row, int rx); int erow_cursor_to_render(struct erow *row, int rx);
int erow_init(struct erow *row, int len);
void erow_update(struct erow *row); void erow_update(struct erow *row);
int erow_init(struct erow *row, int len);
void erow_insert(int at, char *s, int len); void erow_insert(int at, char *s, int len);
void erow_free(struct erow *row); void erow_free(struct erow *row);
void editor_set_status(const char *fmt, ...); void editor_set_status(const char *fmt, ...);
@@ -137,7 +142,6 @@ void move_cursor(int16_t c);
void newline(void); void newline(void);
void process_kcommand(int16_t c); void process_kcommand(int16_t c);
void process_normal(int16_t c); void process_normal(int16_t c);
void navonly_escape(int16_t c);
void process_escape(int16_t c); void process_escape(int16_t c);
int process_keypress(void); int process_keypress(void);
void enable_termraw(void); void enable_termraw(void);
@@ -216,7 +220,7 @@ init_editor(void)
editor.rows = 0; editor.rows = 0;
if (get_winsz(&editor.rows, &editor.cols) == -1) { if (get_winsz(&editor.rows, &editor.cols) == -1) {
// die("can't get window size - is this an interactive terminal?"); die("can't get window size");
} }
editor.rows--; /* status bar */ editor.rows--; /* status bar */
editor.rows--; /* message line */ editor.rows--; /* message line */
@@ -237,8 +241,7 @@ init_editor(void)
/* /*
* reset_editor presumes that editor has been initialized. That is, * reset_editor presumes that editor has been initialized.
* before reset_editor is called, init_editor should be called.
*/ */
void void
reset_editor(void) reset_editor(void)
@@ -260,37 +263,24 @@ reset_editor(void)
void void
ab_append(struct abuf *buf, const char *s, int len) ab_append(struct abuf *buf, const char *s, int len)
{ {
const int delta = (len < 0) ? 0 : len; char *nc = buf->b;
char *nc = buf->b; int sz = buf->len + len;
int sz;
assert((delta >= 0 && buf->len < INT_MAX - delta)); if (sz >= buf->cap) {
sz = buf->len + delta; while (sz > buf->cap) {
if (buf->cap == 0) {
if (sz > buf->cap) { buf->cap = 1;
if (buf->cap == 0) { } else {
buf->cap = 64; buf->cap *= 2;
}
while (sz < buf->cap) {
if (buf->cap > INT_MAX/2) {
buf->cap = INT_MAX;
break;
} }
buf->cap *= 2;
} }
assert(sz <= buf->cap);
nc = realloc(nc, buf->cap); nc = realloc(nc, buf->cap);
assert(nc != NULL); assert(nc != NULL);
} }
if (delta > 0) { memcpy(&nc[buf->len], s, len);
memcpy(&nc[buf->len], s, (size_t)delta); buf->b = nc;
buf->b = nc; buf->len += len; /* DANGER: overflow */
buf->len += delta;
}
} }
@@ -461,14 +451,14 @@ erow_free(struct erow *row)
void void
die(const char *s) die(const char *s)
{ {
/*
* NOTE(kyle): this is a duplication of the code in display.c
* but I would like to be able to import these files from there.
*/
write(STDOUT_FILENO, "\x1b[2J", 4); write(STDOUT_FILENO, "\x1b[2J", 4);
write(STDOUT_FILENO, "\x1b[H", 3); write(STDOUT_FILENO, "\x1b[H", 3);
if (errno != 0) { perror(s);
perror(s);
} else {
fprintf(stderr, "%s\n", s);
}
exit(1); exit(1);
} }
@@ -549,9 +539,6 @@ row_append_row(struct erow *row, char *s, int len)
void void
row_insert_ch(struct erow *row, int at, int16_t c) row_insert_ch(struct erow *row, int at, int16_t c)
{ {
int ncap = 0;
char *nline = NULL;
/* /*
* row_insert_ch just concerns itself with how to update a row. * row_insert_ch just concerns itself with how to update a row.
*/ */
@@ -560,19 +547,6 @@ row_insert_ch(struct erow *row, int at, int16_t c)
} }
assert(c > 0); assert(c > 0);
if (row->size == row->cap) {
ncap = cap_growth(row->cap, row->size+1);
nline = realloc(row->line, ncap);
assert(nline != NULL);
if (nline == NULL) {
return;
}
row->cap = ncap;
row->line = nline;
}
row->line = realloc(row->line, row->size+2); row->line = realloc(row->line, row->size+2);
assert(row->line != NULL); assert(row->line != NULL);
memmove(&row->line[at+1], &row->line[at], row->size - at + 1); memmove(&row->line[at+1], &row->line[at], row->size - at + 1);
@@ -653,7 +627,7 @@ open_file(const char *filename)
editor.filename = strdup(filename); editor.filename = strdup(filename);
assert(editor.filename != NULL); assert(editor.filename != NULL);
editor.dirty = 0; editor.dirty = 0;
if ((fp = fopen(filename, "r")) == NULL) { if ((fp = fopen(filename, "r")) == NULL) {
if (errno == ENOENT) { if (errno == ENOENT) {
@@ -697,14 +671,9 @@ rows_to_buffer(int *buflen)
} }
if (len == 0) { if (len == 0) {
if (buflen != NULL) {
*buflen = 0;
}
return NULL; return NULL;
} }
assert(buflen != NULL);
*buflen = len; *buflen = len;
buf = malloc(len); buf = malloc(len);
assert(buf != NULL); assert(buf != NULL);
@@ -762,7 +731,7 @@ save_file(void)
status = 0; status = 0;
save_exit: save_exit:
if (fd != -1) close(fd); if (fd) close(fd);
if (buf) { if (buf) {
free(buf); free(buf);
buf = NULL; buf = NULL;
@@ -1008,11 +977,7 @@ editor_openfile(void)
return; return;
} }
/* open_file() will handle freeing the previous file/buffer state
* via reset_editor() and will strdup() the filename internally. */
open_file(filename); open_file(filename);
free(filename);
} }
@@ -1230,25 +1195,7 @@ process_normal(int16_t c)
void void
process_escape(int16_t c) process_escape(int16_t c)
{ {
struct erow *row = NULL; struct erow *row = &editor.row[editor.cury];
/* if there are no rows, there's nothing to do */
if (editor.nrows <= 0) {
return;
}
if (editor.cury <0) {
editor.cury = 0;
} else if (editor.cury >= editor.nrows) {
editor.cury = editor.nrows - 1;
}
row = &editor.row[editor.cury];
if (editor.curx < 0) {
editor.curx = 0;
} else if (editor.curx > row->size) {
editor.curx = row->size;
}
editor_set_status("hi"); editor_set_status("hi");
@@ -1262,12 +1209,7 @@ process_escape(int16_t c)
editor.curx = 0; editor.curx = 0;
break; break;
case BACKSPACE: case BACKSPACE:
row = &editor.row[editor.cury]; /* cury may have changed */ if (isalnum(row->line[editor.curx])) {
if (editor.curx == 0 || editor.curx < row->size) {
break;
}
if ((unsigned char)isalnum(row->line[editor.curx])) {
editor_set_status("is alnum"); editor_set_status("is alnum");
while (editor.curx > 0 && isalnum(row->line[editor.curx])) { while (editor.curx > 0 && isalnum(row->line[editor.curx])) {
process_normal(BACKSPACE); process_normal(BACKSPACE);
@@ -1396,8 +1338,7 @@ draw_rows(struct abuf *ab)
{ {
assert(editor.cols >= 0); assert(editor.cols >= 0);
int cols = editor.cols > 0 ? editor.cols : 1; char buf[editor.cols];
char buf[cols];
int buflen, filerow, padding; int buflen, filerow, padding;
int y; int y;
@@ -1420,6 +1361,7 @@ draw_rows(struct abuf *ab)
ab_append(ab, "|", 1); ab_append(ab, "|", 1);
} }
} else { } else {
erow_update(&editor.row[filerow]);
buflen = editor.row[filerow].rsize - editor.coloffs; buflen = editor.row[filerow].rsize - editor.coloffs;
if (buflen < 0) { if (buflen < 0) {
buflen = 0; buflen = 0;
@@ -1428,7 +1370,6 @@ draw_rows(struct abuf *ab)
if (buflen > editor.cols) { if (buflen > editor.cols) {
buflen = editor.cols; buflen = editor.cols;
} }
ab_append(ab, editor.row[filerow].render+editor.coloffs, ab_append(ab, editor.row[filerow].render+editor.coloffs,
buflen); buflen);
} }
@@ -1571,10 +1512,10 @@ editor_set_status(const char *fmt, ...)
void void
loop(void) loop(void)
{ {
display_refresh(); int up = 1; /* update on the first runthrough */
while (1) { while (1) {
int update = 0; if (up) display_refresh();
/* /*
* ke should only refresh the display if it has received keyboard * ke should only refresh the display if it has received keyboard
@@ -1582,12 +1523,8 @@ loop(void)
* handling pastes without massive screen flicker. * handling pastes without massive screen flicker.
* *
*/ */
while (process_keypress()) { if ((up = process_keypress()) != 0) {
update = 1; while (process_keypress()) ;
}
if (update) {
display_refresh();
} }
} }
} }