tAdd basic support for marks - ledit - Text editor (WIP) | |
git clone git://lumidify.org/ledit.git (fast, but not encrypted) | |
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow) | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 657c25540c4b349068c4c24f82b6b5bb1f94c459 | |
parent 133041cbe8f5b106c95984a743b852fcdac6eda9 | |
Author: lumidify <[email protected]> | |
Date: Thu, 4 Nov 2021 13:22:00 +0100 | |
Add basic support for marks | |
Diffstat: | |
M keys_basic.c | 21 +++++++++++++++++++++ | |
M keys_basic_config.h | 4 ++++ | |
M keys_command.c | 83 +++++++++++++++++++++++++++++… | |
M keys_command.h | 5 ++++- | |
M keys_command_config.h | 8 +++++++- | |
M ledit.c | 2 ++ | |
6 files changed, 121 insertions(+), 2 deletions(-) | |
--- | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -396,6 +396,7 @@ get_key_repeat(void) { | |
return num; | |
} | |
+/* FIXME: allow motion callback! */ | |
static struct action | |
move_to_line(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
t@@ -1382,6 +1383,26 @@ enter_searchedit_backward(ledit_buffer *buffer, char *t… | |
return (struct action){ACTION_GRABKEY, &ledit_command_key_handler}; | |
} | |
+static struct action | |
+mark_line(ledit_buffer *buffer, char *text, int len) { | |
+ (void)buffer; | |
+ (void)text; | |
+ (void)len; | |
+ ledit_command_set_type(CMD_MARKLINE); | |
+ discard_repetition_stack(); | |
+ return (struct action){ACTION_GRABKEY, &ledit_command_key_handler}; | |
+} | |
+ | |
+static struct action | |
+jump_to_mark(ledit_buffer *buffer, char *text, int len) { | |
+ (void)buffer; | |
+ (void)text; | |
+ (void)len; | |
+ ledit_command_set_type(CMD_JUMPTOMARK); | |
+ discard_repetition_stack(); | |
+ return (struct action){ACTION_GRABKEY, &ledit_command_key_handler}; | |
+} | |
+ | |
/* FIXME: support visual mode, i.e. change selection to new place? */ | |
static struct action | |
key_search_next(ledit_buffer *buffer, char *text, int len) { | |
diff --git a/keys_basic_config.h b/keys_basic_config.h | |
t@@ -68,6 +68,8 @@ static struct action paste_normal(ledit_buffer *buffer, char… | |
static struct action paste_normal_backwards(ledit_buffer *buffer, char *text, … | |
static struct action change(ledit_buffer *buffer, char *text, int len); | |
static struct action move_to_eol(ledit_buffer *buffer, char *text, int len); | |
+static struct action mark_line(ledit_buffer *buffer, char *text, int len); | |
+static struct action jump_to_mark(ledit_buffer *buffer, char *text, int len); | |
/* FIXME: maybe sort these and use binary search | |
-> but that would mess with the catch-all keys */ | |
t@@ -129,6 +131,8 @@ static struct key keys_en[] = { | |
{"G", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &move_to_line}, | |
{"p", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal}, | |
{"P", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal_backwards}, | |
+ {"m", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &mark_line}, | |
+ {"'", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &jump_to_mark}, | |
{"", 0, 0, INSERT, KEY_ANY, KEY_ANY, &insert_mode_insert_text} | |
}; | |
diff --git a/keys_command.c b/keys_command.c | |
t@@ -30,6 +30,89 @@ | |
/* this must first be set by caller before jumping to key handler */ | |
static enum ledit_command_type cur_type; | |
+struct mark { | |
+ char *text; | |
+ int line; | |
+ int byte; | |
+}; | |
+ | |
+/* FIXME: this should be part of buffer! */ | |
+struct { | |
+ size_t len, alloc; | |
+ struct mark *marks; | |
+} marklist = {0, 0, NULL}; | |
+ | |
+void | |
+command_key_cleanup(void) { | |
+ for (size_t i = 0; i < marklist.len; i++) { | |
+ free(marklist.marks[i].text); | |
+ } | |
+ free(marklist.marks); | |
+} | |
+ | |
+static void | |
+insert_mark(char *mark, int len, int line, int byte) { | |
+ for (size_t i = 0; i < marklist.len; i++) { | |
+ if (!strncmp(mark, marklist.marks[i].text, len)) { | |
+ marklist.marks[i].line = line; | |
+ marklist.marks[i].byte = byte; | |
+ return; | |
+ } | |
+ } | |
+ if (marklist.len == marklist.alloc) { | |
+ size_t new_alloc = marklist.alloc > 0 ? marklist.alloc * 2 : 4; | |
+ marklist.marks = ledit_realloc( | |
+ marklist.marks, new_alloc * sizeof(struct mark) | |
+ ); | |
+ marklist.alloc = new_alloc; | |
+ } | |
+ struct mark *m = &marklist.marks[marklist.len]; | |
+ m->text = ledit_strndup(mark, len); | |
+ m->line = line; | |
+ m->byte = byte; | |
+ marklist.len++; | |
+} | |
+ | |
+/* FIXME: differentiate between jumping to line and index like nvi */ | |
+static int | |
+mark_line(ledit_buffer *buffer, char *key_text, int len) { | |
+ insert_mark(key_text, len, buffer->cur_line, buffer->cur_index); | |
+ return 0; | |
+} | |
+ | |
+/* FIXME: check that byte is actually in at grapheme boundary */ | |
+/* FIXME: make this work with selections! */ | |
+static int | |
+jump_to_mark(ledit_buffer *buffer, char *key_text, int len) { | |
+ ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
+ for (size_t i = 0; i < marklist.len; i++) { | |
+ if (!strncmp(key_text, marklist.marks[i].text, len)) { | |
+ ledit_line *ll; | |
+ struct mark *m = &marklist.marks[i]; | |
+ if (m->line >= buffer->lines_num) { | |
+ buffer->cur_line = buffer->lines_num - 1; | |
+ ll = ledit_buffer_get_line(buffer, buffer->cur… | |
+ buffer->cur_index = ll->len; | |
+ } else { | |
+ buffer->cur_line = m->line; | |
+ ll = ledit_buffer_get_line(buffer, m->line); | |
+ if (m->byte >= ll->len) | |
+ buffer->cur_index = ll->len; | |
+ else | |
+ buffer->cur_index = m->byte; | |
+ } | |
+ break; | |
+ } | |
+ } | |
+ if (buffer->common->mode == NORMAL) { | |
+ buffer->cur_index = ledit_buffer_get_legal_normal_pos( | |
+ buffer, buffer->cur_line, buffer->cur_index | |
+ ); | |
+ } | |
+ ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c… | |
+ return 0; | |
+} | |
+ | |
void | |
ledit_command_set_type(enum ledit_command_type type) { | |
cur_type = type; | |
diff --git a/keys_command.h b/keys_command.h | |
t@@ -4,12 +4,15 @@ enum ledit_command_type { | |
CMD_EDITSEARCHB, | |
CMD_SEARCH, | |
CMD_SEARCHB, | |
- CMD_SUBSTITUTE | |
+ CMD_SUBSTITUTE, | |
+ CMD_MARKLINE, | |
+ CMD_JUMPTOMARK | |
}; | |
/* these are only here so they can also be used by keys_basic */ | |
void search_next(ledit_buffer *buffer); | |
void search_prev(ledit_buffer *buffer); | |
+void command_key_cleanup(void); | |
void ledit_command_set_type(enum ledit_command_type type); | |
struct action ledit_command_key_handler(ledit_buffer *buffer, XEvent *event, i… | |
diff --git a/keys_command_config.h b/keys_command_config.h | |
t@@ -6,6 +6,8 @@ static int edit_insert_text(ledit_buffer *buffer, char *key_te… | |
static int edit_submit(ledit_buffer *buffer, char *key_text, int len); | |
static int editsearch_submit(ledit_buffer *buffer, char *key_text, int len); | |
static int editsearchb_submit(ledit_buffer *buffer, char *key_text, int len); | |
+static int mark_line(ledit_buffer *buffer, char *key_text, int len); | |
+static int jump_to_mark(ledit_buffer *buffer, char *key_text, int len); | |
struct key { | |
char *text; /* for keys that correspond… | |
t@@ -26,7 +28,11 @@ static struct key keys_en[] = { | |
{NULL, 0, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit}, | |
{"", 0, 0, CMD_EDIT, &edit_insert_text}, | |
{"", 0, 0, CMD_EDITSEARCH, &edit_insert_text}, | |
- {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text} | |
+ {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}, | |
+ /* FIXME: also allow non-text keys for marks? | |
+ OpenBSD nvi seems to allow it, at least sort of. */ | |
+ {"", 0, 0, CMD_MARKLINE, &mark_line}, | |
+ {"", 0, 0, CMD_JUMPTOMARK, &jump_to_mark} | |
}; | |
static struct key keys_de[] = { | |
diff --git a/ledit.c b/ledit.c | |
t@@ -41,6 +41,7 @@ | |
#include "search.h" | |
#include "keys.h" | |
#include "keys_basic.h" | |
+#include "keys_command.h" | |
static void resize_window(int w, int h); | |
static void mainloop(void); | |
t@@ -234,6 +235,7 @@ cleanup(void) { | |
/* FIXME: check for other things to clean up */ | |
ledit_search_cleanup(); | |
basic_key_cleanup(); | |
+ command_key_cleanup(); | |
ledit_buffer_destroy(buffer); | |
ledit_window_destroy(window); | |
ledit_theme_destroy(&common, theme); |