From 3eeb4e91ed259b29d1ec19ffd786838bf46930ee Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 16 Jul 2023 07:53:13 +1000 Subject: [PATCH] Simplify some doc:char handlers. Create a shared inline function that does the bulk of the work of a 'doc:char' function and only needs to be given next and prev functions which update the doc_ref and report the character. Signed-off-by: NeilBrown --- core-log.c | 122 +++++++++++++++++++++------------------------------ core-pane.h | 49 +++++++++++++++++++++ doc-dir.c | 95 +++++++++++++--------------------------- doc-list.c | 83 ++++++++++++----------------------- doc-text.c | 124 ++++------------------------------------------------ 5 files changed, 167 insertions(+), 306 deletions(-) diff --git a/core-log.c b/core-log.c index 1e81511d..7eeeea51 100644 --- a/core-log.c +++ b/core-log.c @@ -21,7 +21,10 @@ struct doc_ref { struct logbuf *b; unsigned int o; }; +struct log; #define DOC_DATA_TYPE struct log +#define DOC_NEXT log_next +#define DOC_PREV log_prev #include "core.h" #include "internal.h" @@ -251,88 +254,63 @@ DEF_CMD(log_set_ref) return 1; } -static int log_step(struct pane *home safe, struct mark *mark safe, int num, int num2) +static inline wint_t log_next(struct log *log safe, struct doc_ref *r safe, bool bytes) { - struct log *log = &home->doc_data; - struct mark *m = mark; - bool forward = num; - bool move = num2; - struct doc_ref ref; wint_t ret; - ref = m->ref; - if (forward) { - if (!ref.b) - ret = WEOF; - else { - const char *s = &ref.b->text[ref.o]; - - ret = get_utf8(&s, ref.b->text + ref.b->end); - ref.o = s - ref.b->text; - if (ref.o >= ref.b->end) { - if (ref.b == list_last_entry(&log->log, - struct logbuf, h)) - ref.b = NULL; - else - ref.b = list_next_entry(ref.b, h); - ref.o = 0; - } - } - } else { - if (list_empty(&log->log)) - ret = WEOF; - else if (!ref.b) { - ref.b = list_last_entry(&log->log, struct logbuf, h); - ref.o = utf8_round_len(ref.b->text, ref.b->end - 1); - } else if (ref.o == 0) { - if (ref.b != list_first_entry(&log->log, - struct logbuf, h)) { - ref.b = list_prev_entry(ref.b, h); - ref.o = utf8_round_len(ref.b->text, - ref.b->end - 1); - } else - ret = WEOF; - } else - ref.o = utf8_round_len(ref.b->text, ref.o - 1); - if ((ref.b != m->ref.b || ref.o != m->ref.o) && ref.b) { - const char *s = ref.b->text + ref.o; - ret = get_utf8(&s, ref.b->text + ref.b->end); + if (!r->b) + ret = WEOF; + else { + const char *s = &r->b->text[r->o]; + + if (bytes) + ret = *s++; + else + ret = get_utf8(&s, r->b->text + r->b->end); + r->o = s - r->b->text; + if (r->o >= r->b->end) { + if (r->b == list_last_entry(&log->log, + struct logbuf, h)) + r->b = NULL; + else + r->b = list_next_entry(r->b, h); + r->o = 0; } } - if (move) { - mark_step(m, forward); - m->ref = ref; + return ret; +} + +static inline wint_t log_prev(struct log *log safe, struct doc_ref *r safe, bool bytes) +{ + const char *s; + + if (list_empty(&log->log)) + return WEOF; + else if (!r->b) { + r->b = list_last_entry(&log->log, struct logbuf, h); + r->o = r->b->end; + } else if (r->o == 0) { + if (r->b != list_first_entry(&log->log, + struct logbuf, h)) { + r->b = list_prev_entry(r->b, h); + r->o = r->b->end; + } else + return WEOF; } - return CHAR_RET(ret); + if (bytes) + r->o -= 1; + else + r->o = utf8_round_len(r->b->text, r->o - 1); + s = r->b->text + r->o; + if (bytes) + return *s; + else + return get_utf8(&s, r->b->text + r->b->end); } DEF_CMD(log_char) { - struct mark *m = ci->mark; - struct mark *end = ci->mark2; - int steps = ci->num; - int forward = steps > 0; - int ret = Einval; - - if (!m) - return Enoarg; - if (end && mark_same(m, end)) - return 1; - if (end && (end->seq < m->seq) != (steps < 0)) - /* Can never cross 'end' */ - return Einval; - while (steps && ret != CHAR_RET(WEOF) && (!end || !mark_same(m, end))) { - ret = log_step(ci->home, m, forward, 1); - steps -= forward*2 - 1; - } - if (end) - return 1 + (forward ? ci->num - steps : steps - ci->num); - if (ret == CHAR_RET(WEOF) || ci->num2 == 0) - return ret; - if (ci->num && (ci->num2 < 0) == forward) - return ret; - /* Want the 'next' char */ - return log_step(ci->home, m, ci->num2 > 0, 0); + return do_char_byte(ci); } DEF_CMD(log_val_marks) diff --git a/core-pane.h b/core-pane.h index 4b61b4d8..5922fd44 100644 --- a/core-pane.h +++ b/core-pane.h @@ -151,3 +151,52 @@ static inline int do_call_val(enum target_type type, struct pane *home, } return ret; } + +#if defined(PRIVATE_DOC_REF) && defined(DOC_DATA_TYPE) && defined(DOC_NEXT) +static inline wint_t DOC_NEXT(DOC_DATA_TYPE *doc safe, struct doc_ref *r safe, bool byte); +static inline wint_t DOC_PREV(DOC_DATA_TYPE *doc safe, struct doc_ref *r safe, bool byte); +static inline int do_char_byte(const struct cmd_info *ci safe) +{ + struct mark *m = ci->mark; + struct mark *end = ci->mark2; + DOC_DATA_TYPE *doc = &ci->home->doc_data; + struct doc_ref r; + int steps = ci->num; + int forward = steps > 0; + wint_t ret = ' '; + int byte = strcmp(ci->key, "doc:byte") == 0; + + if (!m) + return Enoarg; + if (end && mark_same(m, end)) + return 1; + if (end && (end->seq < m->seq) != (steps < 0)) + /* Can never cross 'end' */ + return Einval; + while (steps && ret != CHAR_RET(WEOF) && (!end || !mark_same(m, end))) { + #ifdef DOC_SHARESREF + mark_step_sharesref(m, forward); + #else + mark_step(m, forward); + #endif + if (forward) + ret = DOC_NEXT(doc, &m->ref, byte); + else + ret = DOC_PREV(doc, &m->ref, byte); + steps -= forward*2 - 1; + } + if (end) + return 1 + (forward ? ci->num - steps : steps - ci->num); + if (ret == WEOF || ci->num2 == 0) + return CHAR_RET(ret); + if (ci->num && (ci->num2 < 0) == forward) + return CHAR_RET(ret); + /* Want the 'next' char */ + r = m->ref; + if (ci->num2 > 0) + ret = DOC_NEXT(doc, &r, byte); + else + ret = DOC_PREV(doc, &r, byte); + return CHAR_RET(ret); +} +#endif diff --git a/doc-dir.c b/doc-dir.c index a28fba0d..db356f67 100644 --- a/doc-dir.c +++ b/doc-dir.c @@ -47,8 +47,11 @@ struct doc_ref { struct dir_ent *d; unsigned int ignore; }; - +#define DOC_SHARESREF #define DOC_DATA_TYPE struct directory +struct directory; +#define DOC_NEXT dir_next +#define DOC_PREV dir_prev #include "core.h" struct dir_ent { @@ -380,79 +383,43 @@ DEF_CMD(dir_same_file) return 1; } -static int dir_step(struct pane *home safe, struct mark *mark safe, - int num, int num2) +static inline wint_t dir_next(struct directory *dr safe, struct doc_ref *r safe, bool bytes) { - struct mark *m = mark; - bool forward = num; - bool move = num2; - struct directory *dr = &home->doc_data; - struct dir_ent *d; - wint_t ret = '\n'; + struct dir_ent *d = r->d; - if (!mark_valid(mark)) - /* FIXME this might be needed after deleting lots - * of dir entries, and refreshing. - */ + if (d == NULL) return WEOF; - d = m->ref.d; - if (forward) { - if (d == NULL) - ret = WEOF; - else { - if (d == list_last_entry(&dr->ents, - struct dir_ent, lst)) - d = NULL; - else - d = list_next_entry(d, lst); - } - } else { - if (d == list_first_entry(&dr->ents, struct dir_ent, lst)) + else { + if (d == list_last_entry(&dr->ents, + struct dir_ent, lst)) d = NULL; - else if (d == NULL) - d = list_last_entry(&dr->ents, struct dir_ent, lst); else - d = list_prev_entry(d, lst); - if (!d) { - ret = WEOF; - d = m->ref.d; - } - } - if (move) { - mark_step_sharesref(m, forward); - m->ref.d = d; + d = list_next_entry(d, lst); } - /* return value must be +ve, so use high bits to ensure this. */ - return CHAR_RET(ret); + r->d = d; + return '\n'; } -DEF_CMD(dir_char) +static inline wint_t dir_prev(struct directory *dr safe, struct doc_ref *r safe, bool bytes) { - struct mark *m = ci->mark; - struct mark *end = ci->mark2; - int steps = ci->num; - int forward = steps > 0; - int ret = Einval; + struct dir_ent *d = r->d; - if (!m) - return Enoarg; - if (end && mark_same(m, end)) - return 1; - if (end && (end->seq < m->seq) != (steps < 0)) - /* Can never cross 'end' */ - return Einval; - while (steps && ret != CHAR_RET(WEOF) && (!end || !mark_same(m, end))) { - ret = dir_step(ci->home, m, forward, 1); - steps -= forward*2 - 1; - } - if (end) - return 1 + (forward ? ci->num - steps : steps - ci->num); - if (ret == CHAR_RET(WEOF) || ci->num2 == 0) - return ret; - if (ci->num && (ci->num2 < 0) == forward) - return ret; - /* Want the 'next' char */ - return dir_step(ci->home, m, ci->num2 > 0, 0); + if (d == list_first_entry(&dr->ents, struct dir_ent, lst)) + d = NULL; + else if (d == NULL) + d = list_last_entry(&dr->ents, struct dir_ent, lst); + else + d = list_prev_entry(d, lst); + if (!d) + return WEOF; + + r->d = d; + return '\n'; +} + +DEF_CMD(dir_char) +{ + return do_char_byte(ci); } DEF_CMD(dir_set_ref) diff --git a/doc-list.c b/doc-list.c index 1d83eec9..cc2bd909 100644 --- a/doc-list.c +++ b/doc-list.c @@ -19,7 +19,11 @@ struct doc_ref { unsigned int i; }; +#define DOC_SHARESREF #define DOC_DATA_TYPE struct list +struct list; +#define DOC_NEXT list_next +#define DOC_PREV list_prev #include "core.h" #include "misc.h" @@ -34,64 +38,33 @@ struct list { }; #include "core-pane.h" -DEF_CMD(list_char) +static inline wint_t list_next(struct list *l safe, struct doc_ref *r safe, bool bytes) { - struct list *l = &ci->home->doc_data; - struct mark *m = ci->mark; - struct mark *end = ci->mark2; - int steps = ci->num; - int forward = steps > 0; - int ret = Einval; + if (r->p == NULL) + return WEOF; - if (!m) - return Enoarg; + if (r->p == list_last_entry(&l->content, struct elmnt, list)) + r->p = NULL; + else + r->p = list_next_entry(r->p, list); + return ' '; +} - if (end && mark_same(m, end)) - return 1; - if (end && (end->seq < m->seq) != (steps < 0)) - /* Can never cross 'end' */ - return Einval; - while (steps && ret != CHAR_RET(WEOF) && - (!end || !mark_same(m, end))) { - if (forward) { - if (m->ref.p == NULL) - ret = CHAR_RET(WEOF); - else { - ret = CHAR_RET(' '); - mark_step_sharesref(m, 1); - if (m->ref.p == list_last_entry(&l->content, struct elmnt, list)) - m->ref.p = NULL; - else - m->ref.p = list_next_entry(m->ref.p, list); - steps -= 1; - } - } else { - if (m->ref.p == list_first_entry_or_null(&l->content, struct elmnt, list)) - ret = CHAR_RET(WEOF); - else { - ret = CHAR_RET(' '); - mark_step_sharesref(m, 0); - if (m->ref.p == NULL) - m->ref.p = list_last_entry(&l->content, struct elmnt, list); - else - m->ref.p = list_prev_entry(m->ref.p, list); - steps += 1; - } - } - } - if (end) - return 1 + (forward ? ci->num - steps : steps - ci->num); - if (ret == CHAR_RET(WEOF) || ci->num2 == 0) - return ret; - if (ci->num && (ci->num2 < 0) == forward) - return ret; - /* Want the 'next' char */ - if (ci->num2 > 0 && m->ref.p == NULL) - return CHAR_RET(WEOF); - if (ci->num2 < 0 && m->ref.p == - list_first_entry_or_null(&l->content, struct elmnt, list)) - return CHAR_RET(WEOF); - return CHAR_RET(' '); +static inline wint_t list_prev(struct list *l safe, struct doc_ref *r safe, bool bytes) +{ + if (r->p == list_first_entry_or_null(&l->content, struct elmnt, list)) + return WEOF; + + if (r->p == NULL) + r->p = list_last_entry(&l->content, struct elmnt, list); + else + r->p = list_prev_entry(r->p, list); + return ' '; +} + +DEF_CMD(list_char) +{ + return do_char_byte(ci); } DEF_CMD(list_set_ref) diff --git a/doc-text.c b/doc-text.c index b9ff27e2..7d114b48 100644 --- a/doc-text.c +++ b/doc-text.c @@ -78,7 +78,10 @@ struct doc_ref { struct text_chunk *c; unsigned int o; }; +struct text; #define DOC_DATA_TYPE struct text +#define DOC_NEXT text_next +#define DOC_PREV text_prev #include "core.h" #include "misc.h" @@ -1587,7 +1590,7 @@ static void text_add_str(struct text *t safe, struct mark *pm safe, ; } -static wint_t text_next(struct text *t safe, struct doc_ref *r safe, bool bytes) +static inline wint_t text_next(struct text *t safe, struct doc_ref *r safe, bool bytes) { wint_t ret = WERR; const char *c; @@ -1607,7 +1610,7 @@ static wint_t text_next(struct text *t safe, struct doc_ref *r safe, bool bytes) return ret; } -static wint_t text_prev(struct text *t safe, struct doc_ref *r safe, bool bytes) +static inline wint_t text_prev(struct text *t safe, struct doc_ref *r safe, bool bytes) { wint_t ret; const char *c; @@ -1635,119 +1638,10 @@ static wint_t text_prev(struct text *t safe, struct doc_ref *r safe, bool bytes) return ret; } -static int text_step(struct pane *home safe, struct mark *mark safe, - int num, int num2) +DEF_CMD(text_char_byte) { - struct mark *m = mark; - bool forward = num; - bool move = num2; - struct text *t = &home->doc_data; - struct doc_ref r; - wint_t ret; - - ASSERT(m->owner == home); - - r = m->ref; - if (forward) - ret = text_next(t, &r, 0); - else - ret = text_prev(t, &r, 0); - - if (move) { - mark_step(m, forward); - m->ref = r; - } - /* return value must be +ve, so use high bits to ensure this. */ - return CHAR_RET(ret); + return do_char_byte(ci); } - -DEF_CMD(text_char) -{ - struct mark *m = ci->mark; - struct mark *end = ci->mark2; - int steps = ci->num; - int forward = steps > 0; - int ret = Einval; - - if (!m) - return Enoarg; - if (end && mark_same(m, end)) - return 1; - if (end && (end->seq < m->seq) != (steps < 0)) - /* Can never cross 'end' */ - return Einval; - while (steps && ret != CHAR_RET(WEOF) && (!end || !mark_same(m, end))) { - ret = text_step(ci->home, m, forward, 1); - steps -= forward*2 - 1; - } - if (end) - return 1 + (forward ? ci->num - steps : steps - ci->num); - if (ret == CHAR_RET(WEOF) || ci->num2 == 0) - return ret; - if (ci->num && (ci->num2 < 0) == forward) - return ret; - /* Want the 'next' char */ - return text_step(ci->home, m, ci->num2 > 0, 0); -} - -static int text_step_bytes(struct pane *home safe, struct mark *mark safe, - int num, int num2) -{ - struct mark *m = mark; - bool forward = num; - bool move = num2; - struct text *t = &home->doc_data; - struct doc_ref r; - wint_t ret; - - if (!m) - return Enoarg; - - ASSERT(m->owner == home); - - r = m->ref; - if (forward) - ret = text_next(t, &r, 1); - else - ret = text_prev(t, &r, 1); - - if (move) { - mark_step(m, forward); - m->ref = r; - } - /* return value must be +ve, so use high bits to ensure this. */ - return CHAR_RET(ret); -} - -DEF_CMD(text_byte) -{ - struct mark *m = ci->mark; - struct mark *end = ci->mark2; - int steps = ci->num; - int forward = steps > 0; - int ret = Einval; - - if (!m) - return Enoarg; - if (end && mark_same(m, end)) - return 1; - if (end && (end->seq < m->seq) != (steps < 0)) - /* Can never cross 'end' */ - return Einval; - while (steps && ret != CHAR_RET(WEOF) && (!end || !mark_same(m, end))) { - ret = text_step_bytes(ci->home, m, forward, 1); - steps -= forward*2 - 1; - } - if (end) - return 1 + (forward ? ci->num - steps : steps - ci->num); - if (ret == CHAR_RET(WEOF) || ci->num2 == 0) - return ret; - if (ci->num && (ci->num2 < 0) == forward) - return ret; - /* Want the 'next' char */ - return text_step_bytes(ci->home, m, ci->num2 > 0, 0); -} - static bool _text_ref_same(struct text *t safe, struct doc_ref *r1 safe, struct doc_ref *r2 safe) { @@ -2678,8 +2572,8 @@ void edlib_init(struct pane *ed safe) key_add(text_map, "doc:set-attr", &text_set_attr); key_add(text_map, "doc:get-attr", &text_doc_get_attr); key_add(text_map, "doc:replace", &text_replace); - key_add(text_map, "doc:char", &text_char); - key_add(text_map, "doc:byte", &text_byte); + key_add(text_map, "doc:char", &text_char_byte); + key_add(text_map, "doc:byte", &text_char_byte); key_add(text_map, "doc:modified", &text_modified); key_add(text_map, "doc:set:readonly", &text_readonly); key_add(text_map, "doc:notify:doc:revisit", &text_revisited); -- 2.39.5