aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interface.c')
-rw-r--r--src/interface.c81
1 files changed, 66 insertions, 15 deletions
diff --git a/src/interface.c b/src/interface.c
index 9ec1bed..2343a16 100644
--- a/src/interface.c
+++ b/src/interface.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2025 Robin Haberkorn
+ * Copyright (C) 2012-2026 Robin Haberkorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#endif
#include <stdarg.h>
+#include <string.h>
#include <stdio.h>
#include <glib.h>
@@ -36,6 +37,9 @@
//#define DEBUG
+/** minimum level of messages to print to stdout/stderr */
+teco_msg_t teco_interface_msg_level = TECO_MSG_USER;
+
teco_view_t *teco_interface_current_view = NULL;
TECO_DEFINE_UNDO_CALL(teco_interface_show_view, teco_view_t *);
@@ -81,35 +85,82 @@ teco_interface_undo_set_clipboard(const gchar *name, gchar *str, gsize len)
}
}
+void
+teco_interface_msg(teco_msg_t type, const gchar *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ g_autofree gchar *buf = g_strdup_vprintf(fmt, ap);
+ va_end(ap);
+
+ teco_interface_msg_literal(type, buf, strlen(buf));
+}
+
/**
- * 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 on UNIX since stdout/stderr
+ * have been redirected to /dev/null.
+ * Also it would probably be detrimental for performance in scripts
+ * that write individual characters.
+ * Perhaps we should 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;
+ /* "user"-level messages are always printed */
+ if (type != TECO_MSG_USER && type < teco_interface_msg_level)
+ return;
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);
+/**
+ * Get character from stdin.
+ *
+ * @param widechar If TRUE reads one glyph encoded in UTF-8.
+ * If FALSE, returns exactly one byte.
+ * @return Codepoint or -1 in case of EOF.
+ */
+teco_int_t
+teco_interface_stdio_getch(gboolean widechar)
+{
+ gchar buf[4];
+ gint i = 0;
+ gint32 cp;
+
+ do {
+ if (G_UNLIKELY(fread(buf+i, 1, 1, stdin) < 1))
+ return -1; /* EOF */
+ if (!widechar || !buf[i])
+ return (guchar)buf[i];
+
+ /* doesn't work as expected when passed a null byte */
+ cp = g_utf8_get_char_validated(buf, ++i);
+ if (i >= sizeof(buf) || cp != -2)
+ i = 0;
+ } while (cp < 0);
+
+ return cp;
}