summaryrefslogtreecommitdiffstats
path: root/common/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/msg.c')
-rw-r--r--common/msg.c168
1 files changed, 108 insertions, 60 deletions
diff --git a/common/msg.c b/common/msg.c
index b14bd5a..840f2ab 100644
--- a/common/msg.c
+++ b/common/msg.c
@@ -42,10 +42,12 @@
#include "msg.h"
#include "msg_control.h"
-// log buffer size (lines) for terminal level and logfile level
-#define TERM_BUF 100
+// log buffer size (lines) logfile level
#define FILE_BUF 100
+// lines to accumulate before any client requests the terminal loglevel
+#define EARLY_TERM_BUF 100
+
// logfile lines to accumulate during init before we know the log file name.
// thousands of logfile lines during init can happen (especially with many
// scripts, big config, etc), so we set 5000. If it cycles and messages are
@@ -214,9 +216,9 @@ static void prepare_prefix(struct mp_log_root *root, bstr *out, int lev, int ter
// Set cursor state
if (new_lines && !root->status_lines) {
- bstr_xappend(root, out, bstr0("\033[?25l"));
+ bstr_xappend(root, out, bstr0(TERM_ESC_HIDE_CURSOR));
} else if (!new_lines && root->status_lines) {
- bstr_xappend(root, out, bstr0("\033[?25h"));
+ bstr_xappend(root, out, bstr0(TERM_ESC_RESTORE_CURSOR));
}
int line_skip = 0;
@@ -226,41 +228,49 @@ static void prepare_prefix(struct mp_log_root *root, bstr *out, int lev, int ter
bstr up_clear = bstr0("\033[A\033[K");
for (int i = 1; i < root->status_lines; ++i)
bstr_xappend(root, out, up_clear);
- // Reposition cursor after last message
- line_skip = (new_lines ? new_lines : root->blank_lines) - root->status_lines;
- line_skip = MPMIN(root->blank_lines - root->status_lines, line_skip);
- if (line_skip)
- bstr_xappend_asprintf(root, out, "\033[%dA", line_skip);
- } else if (new_lines) {
- line_skip = new_lines - root->blank_lines;
+ assert(root->status_lines > 0 && root->blank_lines >= root->status_lines);
+ line_skip = root->blank_lines - root->status_lines;
}
- if (line_skip < 0) {
- // Reposition cursor to keep status line at the same line
- line_skip = MPMIN(root->blank_lines, -line_skip);
- if (line_skip)
- bstr_xappend_asprintf(root, out, "\033[%dB", line_skip);
- }
+ if (new_lines)
+ line_skip -= MPMAX(0, root->blank_lines - new_lines);
+
+ if (line_skip)
+ bstr_xappend_asprintf(root, out, line_skip > 0 ? "\033[%dA" : "\033[%dB", abs(line_skip));
root->blank_lines = MPMAX(0, root->blank_lines - term_lines);
root->status_lines = new_lines;
root->blank_lines += root->status_lines;
}
-void mp_msg_flush_status_line(struct mp_log *log)
+void mp_msg_flush_status_line(struct mp_log *log, bool clear)
{
- if (log->root) {
- mp_mutex_lock(&log->root->lock);
- if (log->root->status_lines) {
- bstr term_msg = (bstr){0};
- prepare_prefix(log->root, &term_msg, MSGL_STATUS, 0);
- if (term_msg.len) {
- fprintf(stderr, "%.*s", BSTR_P(term_msg));
- talloc_free(term_msg.start);
- }
- }
- mp_mutex_unlock(&log->root->lock);
+ if (!log->root)
+ return;
+
+ mp_mutex_lock(&log->root->lock);
+ if (!log->root->status_lines)
+ goto done;
+
+ if (!clear) {
+ if (log->root->isatty[STDERR_FILENO])
+ fprintf(stderr, TERM_ESC_RESTORE_CURSOR);
+ fprintf(stderr, "\n");
+ log->root->blank_lines = 0;
+ log->root->status_lines = 0;
+ goto done;
}
+
+ bstr term_msg = {0};
+ prepare_prefix(log->root, &term_msg, MSGL_STATUS, 0);
+ if (term_msg.len) {
+ fprintf(stderr, "%.*s", BSTR_P(term_msg));
+ talloc_free(term_msg.start);
+ }
+
+done:
+ log->root->status_line.len = 0;
+ mp_mutex_unlock(&log->root->lock);
}
void mp_msg_set_term_title(struct mp_log *log, const char *title)
@@ -268,7 +278,7 @@ void mp_msg_set_term_title(struct mp_log *log, const char *title)
if (log->root && title) {
// Lock because printf to terminal is not necessarily atomic.
mp_mutex_lock(&log->root->lock);
- fprintf(stderr, "\e]0;%s\007", title);
+ fprintf(stderr, "\033]0;%s\007", title);
mp_mutex_unlock(&log->root->lock);
}
}
@@ -284,15 +294,18 @@ bool mp_msg_has_status_line(struct mpv_global *global)
static void set_term_color(void *talloc_ctx, bstr *text, int c)
{
- return c == -1 ? bstr_xappend(talloc_ctx, text, bstr0("\033[0m"))
- : bstr_xappend_asprintf(talloc_ctx, text,
- "\033[%d;3%dm", c >> 3, c & 7);
+ if (c == -1) {
+ bstr_xappend(talloc_ctx, text, bstr0("\033[0m"));
+ return;
+ }
+
+ bstr_xappend_asprintf(talloc_ctx, text, "\033[%d;3%dm", c >> 3, c & 7);
}
static void set_msg_color(void *talloc_ctx, bstr *text, int lev)
{
static const int v_colors[] = {9, 1, 3, -1, -1, 2, 8, 8, 8, -1};
- return set_term_color(talloc_ctx, text, v_colors[lev]);
+ set_term_color(talloc_ctx, text, v_colors[lev]);
}
static void pretty_print_module(struct mp_log_root *root, bstr *text,
@@ -325,31 +338,30 @@ static bool test_terminal_level(struct mp_log *log, int lev)
}
// This is very basic way to infer needed width for a string.
-static int term_disp_width(bstr str, size_t start, size_t end)
+static int term_disp_width(bstr str)
{
int width = 0;
- bool escape = false;
- const char *line = str.start;
- for (size_t i = start; i < end && i < str.len; ++i) {
- if (escape) {
- escape = !(line[i] >= '@' && line[i] <= '~');
+ while (str.len) {
+ if (bstr_eatstart0(&str, "\033[")) {
+ while (str.len && !((*str.start >= '@' && *str.start <= '~') || *str.start == 'm'))
+ str = bstr_cut(str, 1);
+ str = bstr_cut(str, 1);
continue;
}
- if (line[i] == '\033' && line[i + 1] == '[') {
- escape = true;
- ++i;
- continue;
- }
+ bstr code = bstr_split_utf8(str, &str);
+ if (code.len == 0)
+ return 0;
- if (line[i] == '\n')
+ if (code.len == 1 && *code.start == '\n')
continue;
+ // Only single-width characters are supported
width++;
// Assume that everything before \r should be discarded for simplicity
- if (line[i] == '\r')
+ if (code.len == 1 && *code.start == '\r')
width = 0;
}
@@ -378,7 +390,7 @@ static void append_terminal_line(struct mp_log *log, int lev,
bstr_xappend(root, term_msg, text);
*line_w = root->isatty[term_msg_fileno(root, lev)]
- ? term_disp_width(*term_msg, start, term_msg->len) : 0;
+ ? term_disp_width(bstr_splice(*term_msg, start, term_msg->len)) : 0;
}
static struct mp_log_buffer_entry *log_buffer_read(struct mp_log_buffer *buffer)
@@ -486,9 +498,9 @@ static void write_term_msg(struct mp_log *log, int lev, bstr text, bstr *out)
write_msg_to_buffers(log, lev, line);
}
- if (lev == MSGL_STATUS && print_term) {
+ if (lev == MSGL_STATUS) {
int line_w = 0;
- if (str.len)
+ if (str.len && print_term)
append_terminal_line(log, lev, str, &root->term_msg_tmp, &line_w);
term_msg_lines += !term_w ? (str.len ? 1 : 0)
: (line_w + term_w - 1) / term_w;
@@ -551,12 +563,9 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va)
int fileno = term_msg_fileno(root, lev);
FILE *stream = fileno == STDERR_FILENO ? stderr : stdout;
if (root->term_msg.len) {
- if (root->term_status_msg.len) {
- fprintf(stream, "%.*s%.*s", BSTR_P(root->term_msg),
- BSTR_P(root->term_status_msg));
- } else {
- fprintf(stream, "%.*s", BSTR_P(root->term_msg));
- }
+ fwrite(root->term_msg.start, root->term_msg.len, 1, stream);
+ if (root->term_status_msg.len)
+ fwrite(root->term_status_msg.start, root->term_status_msg.len, 1, stream);
fflush(stream);
}
}
@@ -738,6 +747,10 @@ void mp_msg_update_msglevels(struct mpv_global *global, struct MPOpts *opts)
root->module = opts->msg_module;
root->use_terminal = opts->use_terminal;
root->show_time = opts->msg_time;
+
+ if (root->really_quiet)
+ root->status_lines = 0;
+
for (int i = STDOUT_FILENO; i <= STDERR_FILENO && root->use_terminal; ++i) {
root->isatty[i] = isatty(i);
root->color[i] = opts->msg_color && root->isatty[i];
@@ -836,7 +849,9 @@ bool mp_msg_has_log_file(struct mpv_global *global)
void mp_msg_uninit(struct mpv_global *global)
{
struct mp_log_root *root = global->log->root;
- mp_msg_flush_status_line(global->log);
+ mp_msg_flush_status_line(global->log, true);
+ if (root->really_quiet && root->isatty[STDERR_FILENO])
+ fprintf(stderr, TERM_ESC_RESTORE_CURSOR);
terminate_log_file_thread(root);
mp_msg_log_buffer_destroy(root->early_buffer);
mp_msg_log_buffer_destroy(root->early_filebuffer);
@@ -903,7 +918,7 @@ void mp_msg_set_early_logging(struct mpv_global *global, bool enable)
struct mp_log_root *root = global->log->root;
mp_msg_set_early_logging_raw(global, enable, &root->early_buffer,
- TERM_BUF, MP_LOG_BUFFER_MSGL_TERM);
+ EARLY_TERM_BUF, MP_LOG_BUFFER_MSGL_TERM);
// normally MSGL_LOGFILE buffer gets a write thread, but not the early buf
mp_msg_set_early_logging_raw(global, enable, &root->early_filebuffer,
@@ -920,8 +935,6 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
mp_mutex_lock(&root->lock);
if (level == MP_LOG_BUFFER_MSGL_TERM) {
- size = TERM_BUF;
-
// The first thing which creates a terminal-level log buffer gets the
// early log buffer, if it exists. This is supposed to enable a script
// to grab log messages from before it was initialized. It's OK that
@@ -929,6 +942,7 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
if (root->early_buffer) {
struct mp_log_buffer *buffer = root->early_buffer;
root->early_buffer = NULL;
+ mp_msg_log_buffer_resize(buffer, size);
buffer->wakeup_cb = wakeup_cb;
buffer->wakeup_cb_ctx = wakeup_cb_ctx;
mp_mutex_unlock(&root->lock);
@@ -958,6 +972,40 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
return buffer;
}
+void mp_msg_log_buffer_resize(struct mp_log_buffer *buffer, int size)
+{
+ mp_mutex_lock(&buffer->lock);
+
+ assert(size > 0);
+ if (buffer->capacity < size &&
+ buffer->entry0 + buffer->num_entries <= buffer->capacity) {
+ // shortcut if buffer doesn't wrap
+ buffer->entries = talloc_realloc(buffer, buffer->entries,
+ struct mp_log_buffer_entry *, size);
+ } else if (buffer->capacity != size) {
+ struct mp_log_buffer_entry **entries =
+ talloc_array(buffer, struct mp_log_buffer_entry *, size);
+ int num_entries = 0;
+ for (int i = buffer->num_entries - 1; i >= 0; i--) {
+ int entry = (buffer->entry0 + i) % buffer->num_entries;
+ struct mp_log_buffer_entry *res = buffer->entries[entry];
+ if (num_entries < size) {
+ entries[num_entries++] = res;
+ } else {
+ talloc_free(res);
+ buffer->dropped += 1;
+ }
+ }
+ talloc_free(buffer->entries);
+ buffer->entries = entries;
+ buffer->entry0 = 0;
+ buffer->num_entries = num_entries;
+ }
+ buffer->capacity = size;
+
+ mp_mutex_unlock(&buffer->lock);
+}
+
void mp_msg_log_buffer_set_silent(struct mp_log_buffer *buffer, bool silent)
{
mp_mutex_lock(&buffer->lock);