From eee669a76b3c0b1928475d55d9e1333b3d15bb8c Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 25 Jul 2025 01:41:37 +0300 Subject: implemented the <^A> command for printing arbitrary strings * Greatly improved usability as a scripting language. * The command is in DEC TECO, but in contrast to DEC TECO, we also support string building constructs in ^A. * Required some refactoring: As we want it to write everything verbatim to stdout, the per-interface method is now teco_interface_msg_literal() and it has to deal with unprintable characters. When displaying in the UI, we use teco_curses_format_str() and TecoGtkLabel functions/widgets to deal with possible control codes. * Numbers printed with `=` have to be written with a trailing linefeed, which would also be visible as a reverse "LF" in the UI. Not sure whether this is acceptable - the alternative would be to strip the strings before displaying them. * Messages written to stdout are also auto-flushed at the moment. In the future we might want to put flushing under control of the language. Perhaps :^A could inhibit the flushing. --- src/interface.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'src/interface.c') diff --git a/src/interface.c b/src/interface.c index 9ec1bed..cf8f1ca 100644 --- a/src/interface.c +++ b/src/interface.c @@ -81,35 +81,52 @@ teco_interface_undo_set_clipboard(const gchar *name, gchar *str, gsize len) } } +void +teco_interface_msg(teco_msg_t type, const gchar *fmt, ...) +{ + gchar buf[512]; + va_list ap; + + va_start(ap, fmt); + /* + * If the buffer could ever be exceeded, perhaps + * use g_strdup_vprintf() instead. + */ + gint len = g_vsnprintf(buf, sizeof(buf), fmt, ap); + g_assert(0 <= len && len < sizeof(buf)); + va_end(ap); + + teco_interface_msg_literal(type, buf, len); +} + /** - * Print a message to the appropriate stdio streams. + * Print a raw message to the appropriate stdio streams. * - * This method has similar semantics to `vprintf`, i.e. - * it leaves `ap` undefined. Therefore to pass the format - * string and arguments to another `vprintf`-like function, - * you have to copy the arguments via `va_copy`. + * This deliberately does not echo (i.e. escape non-printable characters) + * the string. Either they are supposed to be written verbatim + * (TECO_MSG_USER) or are already echoed. + * Everything higher than TECO_MSG_USER is also terminated by LF. + * + * @fixme TECO_MSG_USER could always be flushed. + * This however makes the message disappear, though. + * We might also want to put flushing under control of the language instead. */ void -teco_interface_stdio_vmsg(teco_msg_t type, const gchar *fmt, va_list ap) +teco_interface_stdio_msg(teco_msg_t type, const gchar *str, gsize len) { - FILE *stream = stdout; - switch (type) { case TECO_MSG_USER: + fwrite(str, 1, len, stdout); + //fflush(stdout); break; case TECO_MSG_INFO: - fputs("Info: ", stream); + g_fprintf(stdout, "Info: %.*s\n", (gint)len, str); break; case TECO_MSG_WARNING: - stream = stderr; - fputs("Warning: ", stream); + g_fprintf(stderr, "Warning: %.*s\n", (gint)len, str); break; case TECO_MSG_ERROR: - stream = stderr; - fputs("Error: ", stream); + g_fprintf(stderr, "Error: %.*s\n", (gint)len, str); break; } - - g_vfprintf(stream, fmt, ap); - fputc('\n', stream); } -- cgit v1.2.3