Add region mode (for inline TUIs) (attempt 2) - #127
Conversation
|
Hi, Adam I like the variadic function approach with While it makes the API more concise, there's also a caveat that comes with it: variadic functions require very cautious handling. For example, when we expect an The Best regards, Grigory |
|
Instead of a variadic, what do you think about typing all Agreed on copying-ing Thanks for the feedback. |
You mean something like this? #include "termbox2.h"
#define LENGTH(X) (sizeof(X) / sizeof(*X))
int tb_init_ex(size_t argc, const uintptr_t *argv);
int main(void) {
const uintptr_t args[] = {
TB_INIT_TTY, (uintptr_t)"/dev/tty",
TB_INIT_TTYFD, (uintptr_t)13,
TB_INIT_RFD, (uintptr_t)0,
TB_INIT_WFD, (uintptr_t)1,
TB_INIT_REGION, (uintptr_t)10,
};
tb_init_ex(LENGTH(args), args);
return 0;
}Yeah, it's definitely safer, but you're still forced to cast things explicitly sometimes, just as with the variadic approach. The good thing is that the compiler now forces you to do those casts properly, since it errors out with messages like this, for example, if you pass a For convenience's sake, we can introduce a small macro to make the #include "termbox2.h"
typedef uintptr_t tb_arg_t;
#define tb_arg(X) ((tb_arg_t)X)
#define LENGTH(X) (sizeof(X) / sizeof(*X))
int tb_init_ex(size_t argc, const tb_arg_t *argv);
int main(void) {
const tb_arg_t args[] = {
TB_INIT_TTY, tb_arg("/dev/tty"),
TB_INIT_TTYFD, tb_arg(13),
TB_INIT_RFD, tb_arg(0),
TB_INIT_WFD, tb_arg(1),
TB_INIT_REGION, tb_arg(10),
};
tb_init_ex(LENGTH(args), args);
return 0;
}As you can see, with Best regards, Grigory |
|
I'm scoping out termbox2 as a dependency for a nascent project of mine, and I'm participating on some issues that are relevant to myself. Why are you not using an options struct? That seems like the obvious way to simplify and centralize. Sorry if this is a dumb question in context I'm not privy to. |
|
Hi @stianhoiland, not a dumb question. A struct is a good option. The one downside is ABI compat issues particularly when using termbox as a shared library. The alternatives all come with some safety trade-off. termbox already doesn't optimize for safety in all cases (e.g., there are ways to shoot yourself with Here's a summary of the ideas so far: // struct (ABI compat issues)
struct tb_init_opts o = {0};
o.file = "/dev/tty";
o.region_h = 3;
tb_init_ex(&o);
// struct with size
struct tb_init_opts o = {0};
o.size = sizeof(o);
o.file = "/dev/tty";
o.region_h = 3;
tb_init_ex(&o); // only reads up to `o.size`
// variadic [arg1_type, arg1, ...]
tb_init_ex(2,
TB_INIT_TTY, "/dev/tty",
TB_INIT_REGION, 3
);
// variadic [arg_spec, arg1, ...]
tb_init_ex("fr",
"/dev/tty",
3
);
// uintptr_t array
uintptr_t o[] = {
TB_INIT_TTY, (uintptr_t)"/dev/tty",
TB_INIT_REGION, (uintptr_t)3,
};
tb_init_ex(2, &o);
// uintptr_t array 2
uintptr_t o[] = {
TB_INIT_TTY, (uintptr_t)"/dev/tty",
TB_INIT_REGION, (uintptr_t)3,
0, 0 // 0 signifies end
};
tb_init_ex(&o);
// string
tb_init_ex("file=/dev/tty,region_h=3"); |
|
Moved the |
Same approach as #114 except a new variadic function
tb_init_exis introduced which accepts a variable number of initialization options, including region mode. I think this is an improvement as it leaves room for future init options and doesn't require awkwardly callingtb_regionbefore init.