aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c21
-rw-r--r--src/screen.c56
-rw-r--r--src/vega.h5
3 files changed, 79 insertions, 3 deletions
diff --git a/src/main.c b/src/main.c
index 1d8cc4b..3fcf105 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,6 +11,7 @@
#include <unistd.h>
/* vega SURFACE MODULE [--store PATH]: one module, one screen, several surfaces.
+ * check what the module seems to mean but does not meet (exit 1)
* tui interactive terminal
* tui --dump WxH the terminal's frames as text, driven by a script
* cli plain lines for pipes, driven by a script
@@ -29,7 +30,7 @@ static char entry[VEGA_TEXT];
static size_t entry_length;
static bool typing;
-static bool load(const char *path, const char *store) {
+static bool load_module(const char *path) {
static unsigned char bytes[1 << 17];
FILE *file = fopen(path, "rb");
size_t size = file ? fread(bytes, 1, sizeof(bytes), file) : 0;
@@ -41,6 +42,15 @@ static bool load(const char *path, const char *store) {
fprintf(stderr, "vega: %s: %s\n", path, error);
return false;
}
+ return true;
+}
+
+static void print_finding(void *path, const char *name, const char *message) {
+ printf("%s: %s: %s\n", (const char *)path, name, message);
+}
+
+static bool load(const char *path, const char *store) {
+ if (!load_module(path)) return false;
if (store && pure_store_init(store) != PURE_OK) { fprintf(stderr, "vega: cannot open store %s\n", store); return false; }
PureResult started = pure_app_start(&app, &module, store ? pure_tree_data(store) : (PureData){0});
if (started != PURE_OK) { fprintf(stderr, "vega: cannot start (%d)\n", (int)started); return false; }
@@ -376,11 +386,16 @@ int main(int argc, char **argv) {
width <= 1000 && height <= 1000) dumped = true;
else usage = true;
}
- if (usage || (dumped && strcmp(argv[1], "tui"))) {
+ if (usage || (dumped && strcmp(argv[1], "tui")) || (!strcmp(argv[1], "check") && argc != 3)) {
fputs("vega tui|cli|say MODULE.pmod [--store PATH]\n"
- "vega tui MODULE.pmod [--store PATH] --dump WIDTHxHEIGHT < script\n", stderr);
+ "vega tui MODULE.pmod [--store PATH] --dump WIDTHxHEIGHT < script\n"
+ "vega check MODULE.pmod\n", stderr);
return 2;
}
+ if (!strcmp(argv[1], "check")) {
+ if (!load_module(argv[2])) return 2;
+ return vega_check(&module, print_finding, argv[2]) ? 1 : 0;
+ }
Surface surface = !strcmp(argv[1], "cli") ? SURFACE_CLI : !strcmp(argv[1], "say") ? SURFACE_SAY :
!strcmp(argv[1], "tui") ? SURFACE_TUI : (Surface)-1;
if ((int)surface < 0) { fprintf(stderr, "vega: unknown surface %s\n", argv[1]); return 2; }
diff --git a/src/screen.c b/src/screen.c
index 8e584a5..2d4c6dc 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -50,6 +50,62 @@ void vega_screen(VegaScreen *screen, const PureModule *m) {
}
}
+static bool is_view(const PureModule *m, int view, uint8_t type) {
+ return view >= 0 && m->view_type[view] == type;
+}
+
+unsigned vega_check(const PureModule *m, void (*report)(void *, const char *name, const char *message), void *context) {
+ unsigned found = 0;
+ char name[2 * PURE_MODULE_NAME + 8], message[256];
+#define FIND(...) do { snprintf(message, sizeof(message), __VA_ARGS__); report(context, name, message); ++found; } while (0)
+ int title = pure_module_view(m, "title");
+ snprintf(name, sizeof(name), "title");
+ if (title >= 0 && m->view_type[title] != PURE_VIEW_TEXT) FIND("a title is text; this one shows as a field");
+ for (uint32_t i = 0; i < m->views; ++i) {
+ if (m->view_table[i]) continue;
+ const char *view = m->view_names[i];
+ size_t length = strlen(view);
+ snprintf(name, sizeof(name), "%s", view);
+ if (length > 6 && !strcmp(view + length - 6, "_focus")) {
+ char table[PURE_MODULE_NAME];
+ snprintf(table, sizeof(table), "%.*s", (int)(length - 6), view);
+ int owner = pure_module_view(m, table);
+ if (!is_view(m, owner, PURE_VIEW_TABLE))
+ FIND("names no list or table %s; it shows as a field", table);
+ else if (m->view_type[i] != PURE_VIEW_NUM) FIND("the focused row is a number; %s shows no focus", table);
+ }
+ if (m->view_type[i] != PURE_VIEW_TABLE) continue;
+ int label = pure_module_column(m, i, "label"), tone = pure_module_column(m, i, "tone");
+ bool list = is_view(m, label, PURE_VIEW_TEXT);
+ unsigned shown = 0;
+ for (uint32_t k = 0; k < m->views; ++k) {
+ if (m->view_table[k] != i + 1) continue;
+ const char *column = m->view_names[k];
+ bool text = m->view_type[k] == PURE_VIEW_TEXT;
+ snprintf(name, sizeof(name), "%s.%s", view, column);
+ if ((int)k == label && !text) FIND("a list's label is text; %s shows as a table", view);
+ else if ((int)k == tone && text) FIND("a tone is a number (vega.normal ... vega.danger); %s", list ?
+ "the list ignores it" : "it shows as a column");
+ else if (list && (!strcmp(column, "badge") || !strcmp(column, "detail")) && !text)
+ FIND("a list's %s is text; this one is not shown", column);
+ else if (list && (int)k != label && (int)k != tone && strcmp(column, "badge") && strcmp(column, "detail"))
+ FIND("a list shows label, badge, detail and tone; this column is not shown");
+ shown += (int)k != tone || text;
+ }
+ snprintf(name, sizeof(name), "%s", view);
+ if (!list && !shown) FIND("a table with no column to show");
+ }
+ int prompt = -1;
+ for (uint32_t i = 0; i < m->inputs; ++i) {
+ if (m->input[i].kind != PURE_KIND_TEXT) continue;
+ snprintf(name, sizeof(name), "%s", m->input_names[i]);
+ if (prompt >= 0) FIND("only the first text input (%s) has a place to type into", m->input_names[prompt]);
+ else prompt = (int)i;
+ }
+#undef FIND
+ return found;
+}
+
typedef struct { char *out; size_t used; } Collect;
static bool collect(void *context, PureSpan span) {
diff --git a/src/vega.h b/src/vega.h
index 40aecaa..062639b 100644
--- a/src/vega.h
+++ b/src/vega.h
@@ -34,6 +34,11 @@ typedef struct {
} VegaScreen;
void vega_screen(VegaScreen *, const PureModule *);
+/* What a module seems to mean but does not meet: a list label that is not
+ * text, a _focus view without its table, a column a list never shows, a
+ * second text input. Each finding names the view or input it is about;
+ * returns how many there were. */
+unsigned vega_check(const PureModule *, void (*report)(void *, const char *name, const char *message), void *context);
/* A view (row ignored) or a column at a row as text; numbers in Pure's
* shortest form. false when it has no value (for example a missing item). */