CE edit command
All checks were successful
Build documentation / build-and-deploy (push) Successful in 2m11s

This commit is contained in:
2026-03-05 16:29:59 +01:00
parent a5f5dbf21f
commit 25b289ccfb
11 changed files with 316 additions and 30 deletions

46
ce/ce.c
View File

@@ -7,6 +7,7 @@
#include "strbuf.h"
#include <arena.h>
#include <kb.h>
#include <liballoc.h>
#include <list.h>
#include <printf.h>
#include <stdbool.h>
@@ -18,9 +19,35 @@
#include <tscreen.h>
#define LINE_INIT_MAX 40
#define LINE_TAIL_BATCH_MAX 1024
#define PROMPT "$ "
void* wmalloc (void* ctx, size_t size) {
(void)ctx;
return malloc (size);
}
void* wrealloc (void* ctx, void* mem, size_t old, size_t new) {
(void)ctx, (void)old;
return realloc (mem, new);
}
void wfree (void* ctx, void* mem) {
(void)ctx;
free (mem);
}
void* warena_malloc (void* ctx, size_t size) {
struct arena* a = ctx;
return arena_malloc (a, size);
}
void* warena_realloc (void* ctx, void* mem, size_t old, size_t new) {
struct arena* a = ctx;
return arena_realloc (a, mem, old, new);
}
void warena_free (void* ctx, void* mem) { (void)ctx, (void)mem; }
struct edit_line {
struct gapbuffer gb;
size_t cursor;
@@ -44,7 +71,7 @@ void app_main (void) {
const char* render = NULL;
while (interp_is_running ()) {
gapbuffer_init (&edit_line.gb, LINE_INIT_MAX);
gapbuffer_init (&warena_malloc, &arena, &edit_line.gb, LINE_INIT_MAX);
edit_line.cursor = 0;
mprintf (PROMPT);
@@ -66,7 +93,8 @@ void app_main (void) {
mprintf (ANSIQ_CUR_LEFT (1));
char* tail = gapbuffer_string_at (&edit_line.gb, edit_line.cursor);
char* tail =
gapbuffer_string_at (&warena_malloc, &arena, &edit_line.gb, edit_line.cursor);
mprintf ("%s" ANSIQ_SCR_CLR2LEND, tail);
int move_back = strlen (tail);
@@ -78,7 +106,8 @@ void app_main (void) {
if (edit_line.cursor < gapbuffer_length (&edit_line.gb)) {
edit_line.gb.gap_end++;
char* tail = gapbuffer_string_at (&edit_line.gb, edit_line.cursor);
char* tail =
gapbuffer_string_at (&warena_malloc, &arena, &edit_line.gb, edit_line.cursor);
mprintf ("%s" ANSIQ_SCR_CLR2LEND, tail);
int move_back = strlen (tail);
@@ -100,13 +129,14 @@ void app_main (void) {
break;
default:
if (isprint (ch)) {
gapbuffer_insert (&edit_line.gb, ch);
gapbuffer_insert (&warena_realloc, &arena, &edit_line.gb, ch);
edit_line.cursor++;
if (edit_line.cursor == gapbuffer_length (&edit_line.gb)) {
mprintf ("%c", ch);
} else {
char* tail = gapbuffer_string_at (&edit_line.gb, edit_line.cursor - 1);
char* tail =
gapbuffer_string_at (&warena_malloc, &arena, &edit_line.gb, edit_line.cursor - 1);
size_t move_back = strlen (tail) - 1;
mprintf ("%s" ANSIQ_DYN_CUR_LEFT, tail, move_back);
}
@@ -117,12 +147,12 @@ void app_main (void) {
mprintf ("\n");
render = gapbuffer_get_string (&edit_line.gb);
render = gapbuffer_get_string (&warena_malloc, &arena, &edit_line.gb);
if (render != NULL)
exec_line (render);
gapbuffer_fini (&edit_line.gb);
gapbuffer_fini (&warena_free, &arena, &edit_line.gb);
arena_reset (&arena);
}

140
ce/edit.c Normal file
View File

@@ -0,0 +1,140 @@
#include "edit.h"
#include "arena_alloc.h"
#include "gapbuffer.h"
#include "mprintf.h"
#include "self.h"
#include "walloc.h"
#include <arena.h>
#include <kb.h>
#include <liballoc.h>
#include <list.h>
#include <printf.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <system.h>
#include <tcursor.h>
#include <tgraphics.h>
#include <tscreen.h>
struct edit_line {
struct list_node_link lines_link;
struct gapbuffer gb;
};
struct cursor {
size_t col;
size_t line;
};
struct editor {
struct list_node_link* lines;
struct edit_line* current_line;
struct cursor cursor;
};
static struct editor editor;
static bool prepare_lines_cb (void* ctx, const char* start, size_t len) {
struct edit_line* line = malloc (sizeof (*line));
if (line == NULL)
return false;
memset (line, 0, sizeof (*line));
gapbuffer_init (&wmalloc, NULL, &line->gb, len);
for (size_t chr = 0; chr < len; chr++)
gapbuffer_insert (&wrealloc, NULL, &line->gb, start[chr]);
list_append (editor.lines, &line->lines_link);
if (editor.current_line == NULL)
editor.current_line = line;
return true;
}
static void prepare_lines (const char* text) { strtokenize (text, '\n', NULL, &prepare_lines_cb); }
void edit_start (const char* text) {
prepare_lines (text);
struct arena temp_arena;
mprintf (ANSIQ_SCR_SAVE ANSIQ_SCR_CLR_ALL ANSIQ_CUR_INVISIBLE);
for (;;) {
const size_t backbuffer_max = 128 * 1024;
char* backbuffer = arena_malloc (&temp_arena, backbuffer_max);
memset (backbuffer, 0, backbuffer_max);
strncat (backbuffer, ANSIQ_CUR_HOME ANSIQ_SCR_CLR_ALL, backbuffer_max);
struct list_node_link *line_link, *tmp_line_link;
list_foreach (editor.lines, line_link, tmp_line_link) {
struct edit_line* line = list_entry (line_link, struct edit_line, lines_link);
strncat (backbuffer, ANSIQ_SCR_CLR_LINE, backbuffer_max);
char* render = gapbuffer_get_string (&warena_malloc, &temp_arena, &line->gb);
strncat (backbuffer, render, backbuffer_max);
strncat (backbuffer, "\n", backbuffer_max);
}
char tmp[128];
snprintf (tmp, sizeof (tmp), ANSIQ_DYN_CUR_SET ANSIQ_CUR_VISIBLE, (int)editor.cursor.line + 1,
(int)editor.cursor.col + 1);
strncat (backbuffer, tmp, backbuffer_max);
mail_send (e_pgid, backbuffer, strlen (backbuffer));
uint8_t ch = 0;
mail_receive (&ch, 1);
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
switch (ch) {
case '\b':
if (editor.cursor.col > 0) {
editor.cursor.col--;
gapbuffer_backspace (&editor.current_line->gb);
}
break;
case KB_DELETE:
if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) {
editor.current_line->gb.gap_end++;
}
break;
case KB_LEFT:
if (editor.cursor.col > 0) {
editor.cursor.col--;
}
break;
case KB_RIGHT:
if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) {
editor.cursor.col++;
}
break;
default:
if (isprint (ch)) {
gapbuffer_insert (&wrealloc, NULL, &editor.current_line->gb, ch);
editor.cursor.col++;
}
break;
}
arena_reset (&temp_arena);
}
mprintf (ANSIQ_CUR_VISIBLE ANSIQ_SCR_RESTORE);
arena_destroy (&temp_arena);
struct list_node_link *line_link, *tmp_line_link;
list_foreach (editor.lines, line_link, tmp_line_link) {
struct edit_line* line = list_entry (line_link, struct edit_line, lines_link);
free (line->gb.buffer);
free (line);
}
}

6
ce/edit.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _EDIT_H
#define _EDIT_H
void edit_start (const char* text);
#endif // _EDIT_H

View File

@@ -1,11 +1,12 @@
#include "gapbuffer.h"
#include "arena_alloc.h"
#include <arena.h>
#include <liballoc.h>
#include <stddef.h>
#include <string.h>
void gapbuffer_init (struct gapbuffer* gb, size_t capacity) {
gb->buffer = arena_malloc (&arena, capacity);
void gapbuffer_init (gb_malloc_func_t mallocfn, void* ctx, struct gapbuffer* gb, size_t capacity) {
gb->buffer = mallocfn (ctx, capacity);
if (gb->buffer == NULL)
return;
@@ -16,13 +17,16 @@ void gapbuffer_init (struct gapbuffer* gb, size_t capacity) {
gb->gap_end = capacity;
}
void gapbuffer_fini (struct gapbuffer* gb) { memset (gb, 0, sizeof (*gb)); }
void gapbuffer_fini (gb_free_func_t freefn, void* ctx, struct gapbuffer* gb) {
freefn (ctx, gb->buffer);
memset (gb, 0, sizeof (*gb));
}
void gapbuffer_grow (struct gapbuffer* gb) {
void gapbuffer_grow (gb_realloc_func_t reallocfn, void* ctx, struct gapbuffer* gb) {
size_t old_size = gb->size;
size_t new_size = gb->size * 2;
char* new = arena_realloc (&arena, gb->buffer, old_size, new_size);
char* new = reallocfn (ctx, gb->buffer, old_size, new_size);
if (new == NULL)
return;
@@ -55,9 +59,9 @@ void gapbuffer_move (struct gapbuffer* gb, size_t pos) {
}
}
void gapbuffer_insert (struct gapbuffer* gb, char c) {
void gapbuffer_insert (gb_realloc_func_t reallocfn, void* ctx, struct gapbuffer* gb, char c) {
if (gb->gap_start == gb->gap_end)
gapbuffer_grow (gb);
gapbuffer_grow (reallocfn, ctx, gb);
gb->buffer[gb->gap_start] = c;
gb->gap_start++;
@@ -68,10 +72,10 @@ void gapbuffer_backspace (struct gapbuffer* gb) {
gb->gap_start--;
}
char* gapbuffer_get_string (struct gapbuffer* gb) {
char* gapbuffer_get_string (gb_malloc_func_t mallocfn, void* ctx, struct gapbuffer* gb) {
size_t size = gb->size - (gb->gap_end - gb->gap_start);
char* str = arena_malloc (&arena, size + 1);
char* str = mallocfn (ctx, size + 1);
if (str == NULL)
return NULL;
@@ -86,7 +90,7 @@ char* gapbuffer_get_string (struct gapbuffer* gb) {
size_t gapbuffer_length (struct gapbuffer* gb) { return gb->size - (gb->gap_end - gb->gap_start); }
char* gapbuffer_string_at (struct gapbuffer* gb, size_t pos) {
char* gapbuffer_string_at (gb_malloc_func_t mallocfn, void* ctx, struct gapbuffer* gb, size_t pos) {
size_t total_size = gapbuffer_length (gb);
if (pos >= total_size)
@@ -94,7 +98,7 @@ char* gapbuffer_string_at (struct gapbuffer* gb, size_t pos) {
size_t tail_size = total_size - pos;
char* res = arena_malloc (&arena, tail_size + 1);
char* res = mallocfn (ctx, tail_size + 1);
if (res == NULL)
return NULL;
@@ -124,3 +128,17 @@ char* gapbuffer_string_at (struct gapbuffer* gb, size_t pos) {
res[written] = '\0';
return res;
}
char gapbuffer_at (struct gapbuffer* gb, size_t index) {
if (index < gb->gap_start)
return gb->buffer[index];
else
return gb->buffer[index + (gb->gap_end - gb->gap_start)];
}
void gapbuffer_delete_at (struct gapbuffer* gb, size_t index) {
gapbuffer_move (gb, index);
if (gb->gap_end < gb->size)
gb->gap_end++;
}

View File

@@ -1,6 +1,7 @@
#ifndef _GAPBUFFER_H
#define _GAPBUFFER_H
#include <arena.h>
#include <stddef.h>
struct gapbuffer {
@@ -10,22 +11,32 @@ struct gapbuffer {
size_t gap_end;
};
void gapbuffer_init (struct gapbuffer* gb, size_t capacity);
typedef void* (*gb_malloc_func_t) (void*, size_t);
void gapbuffer_fini (struct gapbuffer* gb);
typedef void* (*gb_realloc_func_t) (void*, void*, size_t, size_t);
typedef void (*gb_free_func_t) (void*, void*);
void gapbuffer_init (gb_malloc_func_t mallocfn, void* ctx, struct gapbuffer* gb, size_t capacity);
void gapbuffer_fini (gb_free_func_t freefn, void* ctx, struct gapbuffer* gb);
void gapbuffer_move (struct gapbuffer* gb, size_t pos);
void gapbuffer_insert (struct gapbuffer* gb, char c);
void gapbuffer_insert (gb_realloc_func_t reallocfn, void* ctx, struct gapbuffer* gb, char c);
void gapbuffer_backspace (struct gapbuffer* gb);
void gapbuffer_grow (struct gapbuffer* gb);
void gapbuffer_grow (gb_realloc_func_t reallocfn, void* ctx, struct gapbuffer* gb);
char* gapbuffer_get_string (struct gapbuffer* gb);
char* gapbuffer_get_string (gb_malloc_func_t mallocfn, void* ctx, struct gapbuffer* gb);
size_t gapbuffer_length (struct gapbuffer* gb);
char* gapbuffer_string_at (struct gapbuffer* gb, size_t pos);
char* gapbuffer_string_at (gb_malloc_func_t mallocfn, void* ctx, struct gapbuffer* gb, size_t pos);
char gapbuffer_at (struct gapbuffer* gb, size_t index);
void gapbuffer_delete_at (struct gapbuffer* gb, size_t index);
#endif // _GAPBUFFER_H

View File

@@ -1,12 +1,14 @@
#include "interp.h"
#include "arena_alloc.h"
#include "context.h"
#include "edit.h"
#include "parser.h"
#include "self.h"
#include <desc.h>
#include <filereader.h>
#include <filewriter.h>
#include <kb.h>
#include <liballoc.h>
#include <path.h>
#include <process.h>
#include <stddef.h>
@@ -189,6 +191,48 @@ static void ls (struct context* context, const char* path_string) {
volume_close ();
}
static void edit (struct context* context, const char* path_string) {
struct desc desc;
char volume[VOLUME_MAX];
const char* path;
int ret;
if (!path_parse (path_string, volume, &path)) {
cprintf (context, "ERROR bad path '%s'\n", path_string);
return;
}
if ((ret = volume_open (volume)) < 0) {
cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
return;
}
if ((ret = describe (path, &desc)) < 0) {
cprintf (context, "ERROR could not describe '%s': %s\n", path, str_status[-ret]);
volume_close ();
return;
}
char* str = malloc (desc.size + 1);
if (str == NULL) {
volume_close ();
return;
}
memset (str, 0, desc.size);
if ((ret = read_file (path, 0, (uint8_t*)str, desc.size)) < 0) {
free (str);
volume_close ();
return;
}
edit_start (str);
volume_close ();
}
static void quit1 (struct context* context) {
cprintf (context, "Goodbye!\n");
interp_shutdown ();
@@ -203,6 +247,7 @@ static void help (struct context* context) {
cprintf (context, "mkfile <file path>\n");
cprintf (context, "mkdir <directory path>\n");
cprintf (context, "rm <path>\n");
cprintf (context, "edit <path>\n");
cprintf (context, "quit\n");
}
@@ -239,6 +284,8 @@ static void execute_cmd (struct ast_cmd* cmd, struct context* context) {
mkdir (context, cmd->args, cmd->arg_count);
} else if (strcmp (cmd->name, "rm") == 0) {
rm (context, cmd->args, cmd->arg_count);
} else if (strcmp (cmd->name, "edit") == 0) {
edit (context, cmd->args[0]);
} else {
char volume[VOLUME_MAX];
const char* path;

View File

@@ -6,7 +6,8 @@ c += ce.c \
interp.c \
mprintf.c \
self.c \
gapbuffer.c
gapbuffer.c \
edit.c
o += ce.o \
arena_alloc.o \
@@ -16,4 +17,5 @@ o += ce.o \
interp.o \
mprintf.o \
self.o \
gapbuffer.o
gapbuffer.o \
edit.o

16
ce/walloc.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _WALLOC_H
#define _WALLOC_H
void* wmalloc (void* ctx, size_t size);
void* wrealloc (void* ctx, void* mem, size_t old, size_t new);
void wfree (void* ctx, void* mem);
void* warena_malloc (void* ctx, size_t size);
void* warena_realloc (void* ctx, void* mem, size_t old, size_t new);
void warena_free (void* ctx, void* mem);
#endif // _WALLOC_H

View File

@@ -4,7 +4,7 @@
#include <stddef.h>
#include <stdint.h>
#define ARENA_CHUNK_CAPACITY (8 * 1024)
#define ARENA_CHUNK_CAPACITY (1024 * 1024)
struct arena_chunk {
struct arena_chunk* next;

View File

@@ -140,3 +140,17 @@ void* memmove (void* dest, const void* src, unsigned int n) {
}
return dest;
}
char* strncat (char* dest, const char* src, size_t n) {
char* ptr = dest;
while (*ptr != '\0')
ptr++;
while (n > 0 && *src != '\0') {
*ptr++ = *src++;
n--;
}
*ptr = '\0';
return dest;
}

View File

@@ -31,6 +31,8 @@ int strcmp (const char* s1, const char* s2);
/* concatinate strings */
char* strcat (char* dest, const char* src);
char* strncat (char* dest, const char* src, size_t n);
int isalnum (int c);
int isalpha (int c);