]> git.neil.brown.name Git - edlib.git/commitdiff
Simplify some doc:char handlers.
authorNeilBrown <neil@brown.name>
Sat, 15 Jul 2023 21:53:13 +0000 (07:53 +1000)
committerNeilBrown <neil@brown.name>
Tue, 18 Jul 2023 11:49:42 +0000 (21:49 +1000)
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 <neil@brown.name>
core-log.c
core-pane.h
doc-dir.c
doc-list.c
doc-text.c

index 1e81511d388353f152c7301f9a0430ac52d9b455..7eeeea5159bff0dd7bccc5b770382af62dfb6207 100644 (file)
@@ -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)
index 4b61b4d881a5c651cbda3ce17453b3a3440a07d0..5922fd44ea4674e5763207d3dad46f8dd214b27c 100644 (file)
@@ -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
index a28fba0d2724c157dea92885649aef8229007a27..db356f67156b69141593fbd080d685dfaf9b384f 100644 (file)
--- 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)
index 1d83eec9d11ade4e4251a6c1442949f16a21a686..cc2bd9091de4c327f52fe410659e5b20f6dcbd67 100644 (file)
@@ -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)
index b9ff27e297ed9660d6026b59b75480f229c15ff6..7d114b481d30516d64f5e1483ca5d60791bbdcb9 100644 (file)
@@ -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);