diff options
Diffstat (limited to 'common/msg.c')
-rw-r--r-- | common/msg.c | 168 |
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); |