]> git.neil.brown.name Git - edlib.git/commitdiff
Support inline pane data.
authorNeilBrown <neil@brown.name>
Tue, 4 Jul 2023 03:14:15 +0000 (13:14 +1000)
committerNeilBrown <neil@brown.name>
Wed, 12 Jul 2023 22:17:52 +0000 (08:17 +1000)
If a NULL data pointer is passed to __pane_register(), then a larger
memory allocation will be made to hold both the pane and the data.

If a type is defined with PANE_DATA_TYPE then that will be the size
passed to __pane_register by pane_register().

Similarly DOC_DATA_TYPE can give a type for a document.  The "struct
doc" must appear first in this type.

If PANE_DATA_TYPE is defined, then "core-pane.h" must be included after
the type has been declared, which will usually be after "core.h" is included.

Signed-off-by: NeilBrown <neil@brown.name>
Makefile
core-doc.c
core-editor.c
core-pane.c
core-pane.h [new file with mode: 0644]
core.h
lang-python.c
misc.h

index f16bbed476397d846b9a230056681841bac187cf..68d30c7b957993b1c405195a28e4be8fabd8e530 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -136,7 +136,7 @@ QUIET_LIB     = $(Q:@=@echo    '     LIB      '$@;)
 QUIET_SCRIPT  = $(Q:@=@echo    '     SCRIPT   '$@;)
 
 SO = $(patsubst O/%.o,lib/edlib-%.so,$(SHOBJ))
-H = list.h core.h misc.h safe.h vfunc.h
+H = list.h core.h core-pane.h misc.h safe.h vfunc.h
 edlib: $(OBJ) lib/libedlib.so
        $(QUIET_LINK)$(CC) $(CPPFLAGS) $(CFLAGS) -rdynamic -Wl,--disable-new-dtags -o $@ $(OBJ) -Llib -Wl,-rpath=`pwd`/lib -ledlib $(LDLIBS)
 
index c5b89cfad257e4d3574ad16309c4f5f119f6a4a3..acfc7c23fb6598b5f1b8df37d773152b2aea14be 100644 (file)
@@ -49,6 +49,7 @@ struct doc_data {
 
 static void doc_init(struct doc *d safe)
 {
+       d->self = d;
        INIT_HLIST_HEAD(&d->marks);
        INIT_TLIST_HEAD(&d->points, 0);
        d->views = NULL;
@@ -62,17 +63,23 @@ static void doc_init(struct doc *d safe)
 
 struct pane *__doc_register(struct pane *parent safe,
                            struct command *handle safe,
-                           struct doc *doc safe,
-                           void *data safe,
-                           short data_size)
+                           struct doc *doc,
+                           unsigned short data_size)
 {
        struct pane *p;
 
-       ASSERT(data_size == 0 || data == (void*)doc);
+       if (doc == NULL && data_size < sizeof(*doc))
+               /* Not enough room for the doc ! */
+               return NULL;
+
        /* Documents are always registered against the root */
        parent = pane_root(parent);
-       doc_init(doc);
        p = __pane_register(parent, 0, handle, doc, data_size);
+       if (!p)
+               return p;
+       if (!doc)
+               doc = &p->doc;
+       doc_init(doc);
        return p;
 }
 
index ba87f6762106b30bb6d40acc86ca83a68fd7bb4d..bb3fc339c211f1b3aebc83c6224c688d9e5cfdb4 100644 (file)
@@ -342,7 +342,7 @@ DEF_CMD(editor_free_store)
 DEF_EXTERN_CMD(edlib_do_free)
 {
        if (ci->home->data_size)
-               unalloc_buf_safe(ci->home->data, ci->home->data_size, pane);
+               unalloc_buf_safe(ci->home->_data, ci->home->data_size, pane);
        return 1;
 }
 
index c30555194c5295314f3a3eec111b5375324a124a..6242655623f35d08d5007026274ca5eaae2c82a0 100644 (file)
@@ -153,21 +153,21 @@ static struct pane *__do_pane_register(struct pane *parent, short z,
                                       void *data, short data_size)
 {
        struct pane *p;
+       short alloc_size = data_size;
 
-       alloc(p, pane);
+       if (data)
+               alloc_size = sizeof(data);
+
+       p = alloc_zbuf(offsetof(struct pane, data) + alloc_size, pane);
        pane_init(p, parent);
        p->z = z;
        if (parent)
                p->abs_z = parent->abs_z + 1;
        p->handle = command_get(handle);
-       if (!data)
-               /* type of 'data' should correlate with type of handle,
-                * which should be parameterised...
-                */
-               p->data = handle;
-       else
+       if (data) {
                p->data = data;
-       p->data_size = data_size;
+               p->data_size = data_size;
+       }
        p->name = handle->name;
        if (z >= 0) {
                if (parent && parent->focus == NULL)
diff --git a/core-pane.h b/core-pane.h
new file mode 100644 (file)
index 0000000..4b61b4d
--- /dev/null
@@ -0,0 +1,153 @@
+struct pane {
+       const char              *name; /* For easy discovery in gdb */
+       struct pane             *parent safe;
+       struct list_head        siblings;
+       struct list_head        children;
+       struct pane             *focus;
+       short                   x,y,z;
+       short                   h,w;
+       short                   cx, cy; /* cursor position */
+       short                   abs_z;
+
+       short                   damaged;
+       short                   data_size;      /* only needed by edlib_do_free */
+
+       int                     marks;
+       int                     refs;
+       /* timestamp is low bits of time in milliseconds when some
+        * command started.  This makes it easy to check when we
+        * have done too much work
+        */
+       unsigned int            timestamp;
+
+       struct pane             *root safe;
+       struct command          *handle;
+       struct attrset          *attrs;
+       struct list_head        notifiers, notifiees;
+       union {
+               struct doc      doc;
+#ifdef PANE_DATA_TYPE
+               PANE_DATA_TYPE  data;
+#else
+               void            *data safe;
+#endif
+#ifdef DOC_DATA_TYPE
+               DOC_DATA_TYPE   doc_data;
+#endif
+               void            *_data;
+       };
+};
+
+static inline unsigned int ts_to_ms(struct timespec *ts safe)
+{
+       return ts->tv_nsec / 1000 / 1000 + ts->tv_sec * 1000;
+}
+
+static inline bool pane_too_long(struct pane *p safe, unsigned int msec)
+{
+       extern bool edlib_timing_allowed;
+       struct timespec ts;
+       unsigned int duration;
+       if (!edlib_timing_allowed)
+               return False;
+       clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+       duration = ts_to_ms(&ts) - p->timestamp;
+       if (msec < 100)
+               msec = 100;
+       return (duration > msec);
+}
+
+static inline void pane_set_time(struct pane *p safe)
+{
+       struct timespec ts;
+
+       clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+       p->timestamp = ts_to_ms(&ts);
+}
+
+static inline struct pane * safe pane_root(struct pane *p safe)
+{
+       return p->root;
+}
+
+static inline struct pane *safe pane_leaf(struct pane *p safe)
+{
+       struct pane *f;
+
+       while ((f = p->focus) != NULL)
+               p = f;
+       return p;
+}
+
+static inline struct pane *pane_get(struct pane *p safe) safe
+{
+       p->refs += 1;
+       return p;
+}
+static inline void pane_put(struct pane *p safe)
+{
+       p->refs -= 1;
+       pane_free(p);
+}
+
+static inline int do_call_val(enum target_type type, struct pane *home,
+                             struct command *comm2a,
+                             const char *key safe, struct pane *focus safe,
+                             int num,  struct mark *m,  const char *str,
+                             int num2, struct mark *m2, const char *str2,
+                             int x, int y, struct command *comm2b,
+                             struct commcache *ccache)
+{
+       struct cmd_info ci = {.key = key, .focus = focus, .home = focus,
+                             .num = num, .mark = m, .str = str,
+                             .num2 = num2, .mark2 = m2, .str2 = str2,
+                             .comm2 = comm2a ?: comm2b, .x = x, .y = y,
+                             .comm = safe_cast NULL};
+       int ret;
+
+       if ((type == TYPE_pane || type == TYPE_home) && !home)
+               return 0;
+       if (type == TYPE_comm && !comm2a)
+               return 0;
+       ASSERT(!comm2a || !comm2b || comm2a == comm2b || type == TYPE_comm);
+
+       switch(type) {
+       default:
+       case TYPE_home:
+               if (home)
+                       ci.home = home;
+               /* fall-through */
+       case TYPE_focus:
+               if (ccache) {
+                       ci.home = ccache->home;
+                       ci.comm = ccache->comm;
+               }
+               ret = key_handle(&ci);
+               break;
+       case TYPE_pane:
+               if (!home->handle || (home->damaged & DAMAGED_DEAD))
+                       return Efail;
+               if (times_up_fast())
+                       return Efail;
+               if (home)
+                       ci.home = home;
+               ci.comm = home->handle;
+               ret = ci.comm->func(&ci);
+               break;
+       case TYPE_comm:
+               if (times_up_fast())
+                       return Efail;
+               if (home)
+                       ci.home = home;
+               ci.comm = comm2a;
+               ci.comm2 = comm2b;
+               ret = ci.comm->func(&ci);
+               ccache = NULL;
+               break;
+       }
+       if (ccache) {
+               ccache->comm = ci.comm;
+               ccache->home = ci.home;
+       }
+       return ret;
+}
diff --git a/core.h b/core.h
index 90cda1e975fd1016b6964146abd81fdacf3cd5bb..c6d1e66c40b936ef98f95dde605dd4507f1f0211 100644 (file)
--- a/core.h
+++ b/core.h
@@ -61,61 +61,7 @@ void LOG_BT(void);
  * Each document and contains a reference to the editor which is the root of the
  * pane tree.
  */
-struct pane {
-       const char              *name; /* For easy discovery in gdb */
-       struct pane             *parent safe;
-       struct list_head        siblings;
-       struct list_head        children;
-       struct pane             *focus;
-       short                   x,y,z;
-       short                   h,w;
-       short                   cx, cy; /* cursor position */
-       short                   abs_z;
-
-       short                   damaged;
-       short                   data_size;      /* only needed by edlib_do_free */
-
-       int                     marks;
-       int                     refs;
-       /* timestamp is low bits of time in milliseconds when some
-        * command started.  This makes it easy to check when we
-        * have done too much work
-        */
-       unsigned int            timestamp;
-
-       struct pane             *root safe;
-       struct command          *handle;
-       void                    *data safe;
-       struct attrset          *attrs;
-       struct list_head        notifiers, notifiees;
-};
-
-static inline unsigned int ts_to_ms(struct timespec *ts safe)
-{
-       return ts->tv_nsec / 1000 / 1000 + ts->tv_sec * 1000;
-}
-
-static inline bool pane_too_long(struct pane *p safe, unsigned int msec)
-{
-       extern bool edlib_timing_allowed;
-       struct timespec ts;
-       unsigned int duration;
-       if (!edlib_timing_allowed)
-               return False;
-       clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
-       duration = ts_to_ms(&ts) - p->timestamp;
-       if (msec < 100)
-               msec = 100;
-       return (duration > msec);
-}
-
-static inline void pane_set_time(struct pane *p safe)
-{
-       struct timespec ts;
-
-       clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
-       p->timestamp = ts_to_ms(&ts);
-}
+struct pane ;
 
 struct command {
        int     (*func)(const struct cmd_info *ci safe);
@@ -177,6 +123,12 @@ bool edlib_testing(struct pane *p safe);
 void edlib_init(struct pane *ed safe);
 
 struct doc {
+       /* This pointer always points to itelf. It allows
+        * a pane to have a pointer to a doc, or an embedded doc,
+        * and following the pointer at that location will always
+        * lead to the doc.
+        */
+       struct doc              *self;
        struct hlist_head       marks;
        struct tlist_head       points;
        struct docview {
@@ -500,29 +452,24 @@ struct pane * __pane_register(struct pane *parent safe, short z,
                              struct command *handle safe, void *data,
                              short data_size);
 #define pane_register(...) VFUNC(pane_register, __VA_ARGS__)
+#ifdef PANE_DATA_TYPE
+#define pane_register4(p,z,h,d) __pane_register(p,z,h,d,sizeof(d))
+#define pane_register3(p,z,h) __pane_register(p,z,h,NULL, sizeof(PANE_DATA_TYPE))
+#else
 #define pane_register4(p,z,h,d) __pane_register(p,z,h,d,sizeof((d)[0]))
 #define pane_register3(p,z,h) __pane_register(p,z,h,NULL, 0)
+#endif
 
 struct pane *__doc_register(struct pane *parent safe,
                            struct command *handle safe,
-                           struct doc *doc safe,
-                           void *data safe,
-                           short data_size);
-#define doc_register(p,h,d) __doc_register(p,h,&(d)->doc,d,sizeof((d)[0]))
-
-static inline struct pane * safe pane_root(struct pane *p safe)
-{
-       return p->root;
-}
+                           struct doc *doc,
+                           unsigned short data_size);
 
-static inline struct pane *safe pane_leaf(struct pane *p safe)
-{
-       struct pane *f;
-
-       while ((f = p->focus) != NULL)
-               p = f;
-       return p;
-}
+#ifdef DOC_DATA_TYPE
+#define doc_register(p,h) __doc_register(p, h, NULL, sizeof(DOC_DATA_TYPE))
+#else
+#define doc_register(p,h,d) __doc_register(p,h,&(d)->doc,sizeof((d)[0]))
+#endif
 
 void pane_reparent(struct pane *p safe, struct pane *newparent safe);
 void pane_move_after(struct pane *p safe, struct pane *after);
@@ -557,16 +504,6 @@ static inline int pane_attr_get_int(struct pane *p safe, const char *key safe,
        return rv;
 }
 void pane_free(struct pane *p safe);
-static inline struct pane *pane_get(struct pane *p safe) safe
-{
-       p->refs += 1;
-       return p;
-}
-static inline void pane_put(struct pane *p safe)
-{
-       p->refs -= 1;
-       pane_free(p);
-}
 
 /* Inlines */
 
@@ -773,67 +710,6 @@ char *do_call_strsave(enum target_type type, struct pane *home,
 #define call_ret(_ret, key, _focus, ...) CALL(_ret, focus, _focus, key, _focus, ##__VA_ARGS__)
 #define call_comm(key, _focus, comm, ...) _CALL(val, focus, _focus, key, comm, _focus, ##__VA_ARGS__)
 
-static inline int do_call_val(enum target_type type, struct pane *home,
-                             struct command *comm2a,
-                             const char *key safe, struct pane *focus safe,
-                             int num,  struct mark *m,  const char *str,
-                             int num2, struct mark *m2, const char *str2,
-                             int x, int y, struct command *comm2b,
-                             struct commcache *ccache)
-{
-       struct cmd_info ci = {.key = key, .focus = focus, .home = focus,
-                             .num = num, .mark = m, .str = str,
-                             .num2 = num2, .mark2 = m2, .str2 = str2,
-                             .comm2 = comm2a ?: comm2b, .x = x, .y = y,
-                             .comm = safe_cast NULL};
-       int ret;
-
-       if ((type == TYPE_pane || type == TYPE_home) && !home)
-               return 0;
-       if (type == TYPE_comm && !comm2a)
-               return 0;
-       ASSERT(!comm2a || !comm2b || comm2a == comm2b || type == TYPE_comm);
-
-       switch(type) {
-       default:
-       case TYPE_home:
-               if (home)
-                       ci.home = home;
-               /* fall-through */
-       case TYPE_focus:
-               if (ccache) {
-                       ci.home = ccache->home;
-                       ci.comm = ccache->comm;
-               }
-               ret = key_handle(&ci);
-               break;
-       case TYPE_pane:
-               if (!home->handle || (home->damaged & DAMAGED_DEAD))
-                       return Efail;
-               if (times_up_fast())
-                       return Efail;
-               if (home)
-                       ci.home = home;
-               ci.comm = home->handle;
-               ret = ci.comm->func(&ci);
-               break;
-       case TYPE_comm:
-               if (times_up_fast())
-                       return Efail;
-               if (home)
-                       ci.home = home;
-               ci.comm = comm2a;
-               ci.comm2 = comm2b;
-               ret = ci.comm->func(&ci);
-               ccache = NULL;
-               break;
-       }
-       if (ccache) {
-               ccache->comm = ci.comm;
-               ccache->home = ci.home;
-       }
-       return ret;
-}
 
 #define pane_notify(...) VFUNC(NOTIFY, __VA_ARGS__)
 #define NOTIFY9(not, focus, num, m, str, num2, m2, str2, comm2) \
@@ -870,3 +746,8 @@ static inline int do_call_val(enum target_type type, struct pane *home,
        do_pane_notify(home, not, focus, num, NULL, NULL, 0, NULL, NULL, NULL)
 #define HOMENOTIFY3(home, not, focus) \
        do_pane_notify(home, not, focus, 0, NULL, NULL, 0, NULL, NULL, NULL)
+
+#if !defined(PANE_DATA_TYPE) && !defined(DOC_DATA_TYPE)
+/* If you define PANE_DATA_TYPEor DOC_DATA_TYPE, you need to include this yourself */
+#include "core-pane.h"
+#endif
index 93236f8a14c364406cf452941af8e04055bc3e6e..95ee86b838767b60fa4bc2ca8bcc3b4d11ee70a4 100644 (file)
@@ -764,7 +764,7 @@ static int Doc_init(Doc *self, PyObject *args, PyObject *kwds)
                return -1;
 
        self->cmd.func = python_doc_call_func;
-       self->pane = __doc_register(parent->pane, &self->cmd, &self->doc, self, 0);
+       self->pane = __doc_register(parent->pane, &self->cmd, &self->doc, 0);
        if (self->pane)
                pane_get(self->pane);
        self->doc.refcnt = mark_refcnt;
diff --git a/misc.h b/misc.h
index 1d04044c399972d33d830c7dd56f125ef2514a70..9283cdab2199ac684f2bb8648c83a2af5dfc22d8 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -137,6 +137,7 @@ void __unalloc(struct mempool *pool safe, void *obj, int size);
        do { var = __alloc(&mem##pool, sizeof((var)[0]), 1); } while (0)
 
 #define alloc_buf(size, pool) __alloc(&mem##pool, size, 0)
+#define alloc_zbuf(size, pool) __alloc(&mem##pool, size, 1)
 
 #define unalloc(var, pool)                                             \
        do { __unalloc(&mem##pool, var, sizeof((var)[0])); (var)=NULL; } while (0)