mirror of https://github.com/mpv-player/mpv
msg: allow to truncate the message to terminal width
This commit is contained in:
parent
95f0046309
commit
bf025cd289
|
@ -0,0 +1 @@
|
|||
add `term-clip-cc`
|
|
@ -3377,6 +3377,11 @@ Property list
|
|||
See ``--cursor-autohide``. Setting this to a new value will always update
|
||||
the cursor, and reset the internal timer.
|
||||
|
||||
``term-clip-cc``
|
||||
Inserts the symbol to force line truncation to the current terminal width.
|
||||
This can be used for ``show-text`` and other OSD messages. It must be the
|
||||
first character in the line. It takes effect until the end of the line.
|
||||
|
||||
``osd-sym-cc``
|
||||
Inserts the current OSD symbol as opaque OSD control code (cc). This makes
|
||||
sense only with the ``show-text`` command or options which set OSD messages.
|
||||
|
|
37
common/msg.c
37
common/msg.c
|
@ -374,7 +374,7 @@ static bool test_terminal_level(struct mp_log *log, int lev)
|
|||
}
|
||||
|
||||
static void append_terminal_line(struct mp_log *log, int lev,
|
||||
bstr text, bstr *term_msg, int *line_w)
|
||||
bstr text, bstr *term_msg, int *line_w, int term_w)
|
||||
{
|
||||
struct mp_log_root *root = log->root;
|
||||
|
||||
|
@ -394,8 +394,35 @@ static void append_terminal_line(struct mp_log *log, int lev,
|
|||
}
|
||||
|
||||
bstr_xappend(root, term_msg, text);
|
||||
|
||||
const unsigned char *cut_pos = NULL;
|
||||
int width = term_disp_width(bstr_splice(*term_msg, start, term_msg->len),
|
||||
term_w - 3, &cut_pos);
|
||||
if (cut_pos) {
|
||||
int new_len = cut_pos - term_msg->start;
|
||||
bstr rem = {(unsigned char *)cut_pos, term_msg->len - new_len};
|
||||
term_msg->len = new_len;
|
||||
|
||||
bstr_xappend(root, term_msg, bstr0("..."));
|
||||
|
||||
while (rem.len) {
|
||||
if (bstr_eatstart0(&rem, "\033[")) {
|
||||
bstr_xappend(root, term_msg, bstr0("\033["));
|
||||
|
||||
while (rem.len && !((*rem.start >= '@' && *rem.start <= '~') || *rem.start == 'm')) {
|
||||
bstr_xappend(root, term_msg, bstr_splice(rem, 0, 1));
|
||||
rem = bstr_cut(rem, 1);
|
||||
}
|
||||
bstr_xappend(root, term_msg, bstr_splice(rem, 0, 1));
|
||||
}
|
||||
rem = bstr_cut(rem, 1);
|
||||
}
|
||||
|
||||
bstr_xappend(root, term_msg, bstr0("\n"));
|
||||
width += 3;
|
||||
}
|
||||
*line_w = root->isatty[term_msg_fileno(root, lev)]
|
||||
? term_disp_width(bstr_splice(*term_msg, start, term_msg->len)) : 0;
|
||||
? width : 0;
|
||||
}
|
||||
|
||||
static struct mp_log_buffer_entry *log_buffer_read(struct mp_log_buffer *buffer)
|
||||
|
@ -496,7 +523,8 @@ static void write_term_msg(struct mp_log *log, int lev, bstr text, bstr *out)
|
|||
|
||||
if (print_term) {
|
||||
int line_w;
|
||||
append_terminal_line(log, lev, line, &root->term_msg_tmp, &line_w);
|
||||
append_terminal_line(log, lev, line, &root->term_msg_tmp, &line_w,
|
||||
bstr_eatstart0(&line, TERM_MSG_0) ? term_w : INT_MAX);
|
||||
term_msg_lines += (!line_w || !term_w)
|
||||
? 1 : (line_w + term_w - 1) / term_w;
|
||||
}
|
||||
|
@ -506,7 +534,8 @@ static void write_term_msg(struct mp_log *log, int lev, bstr text, bstr *out)
|
|||
if (lev == MSGL_STATUS) {
|
||||
int line_w = 0;
|
||||
if (str.len && print_term)
|
||||
append_terminal_line(log, lev, str, &root->term_msg_tmp, &line_w);
|
||||
append_terminal_line(log, lev, str, &root->term_msg_tmp, &line_w,
|
||||
bstr_eatstart0(&str, TERM_MSG_0) ? term_w : INT_MAX);
|
||||
term_msg_lines += !term_w ? (str.len ? 1 : 0)
|
||||
: (line_w + term_w - 1) / term_w;
|
||||
} else if (str.len) {
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "osdep/compiler.h"
|
||||
|
||||
#define TERM_MSG_0 "\xFC"
|
||||
|
||||
struct mp_log;
|
||||
|
||||
// A mp_log instance that never outputs anything.
|
||||
|
|
|
@ -662,20 +662,26 @@ static int ucdToCharacterWidth(const int val)
|
|||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
int term_disp_width(bstr str)
|
||||
#include "common/common.h"
|
||||
|
||||
int term_disp_width(bstr str, int max_width, const unsigned char **cut_pos)
|
||||
{
|
||||
static const int ambiguous_width = 1;
|
||||
|
||||
int width = 0;
|
||||
|
||||
const unsigned char *prev_pos = str.start;
|
||||
while (str.len) {
|
||||
int current_width = 0;
|
||||
|
||||
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;
|
||||
goto next;
|
||||
}
|
||||
|
||||
prev_pos = str.start;
|
||||
int cp = bstr_decode_utf8(str, &str);
|
||||
|
||||
// Stop processing on any invalid input
|
||||
|
@ -684,18 +690,17 @@ int term_disp_width(bstr str)
|
|||
|
||||
if (cp == '\r') {
|
||||
width = 0;
|
||||
continue;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (cp < 0x20)
|
||||
continue;
|
||||
goto next;
|
||||
|
||||
if (cp <= 0x7E) {
|
||||
width++;
|
||||
continue;
|
||||
current_width = 1;
|
||||
goto next;
|
||||
}
|
||||
|
||||
int grapheme_width = 0;
|
||||
int state = 0;
|
||||
|
||||
while (true) {
|
||||
|
@ -711,7 +716,7 @@ int term_disp_width(bstr str)
|
|||
if (cp == 0xFE0F)
|
||||
w = 2;
|
||||
|
||||
grapheme_width += w;
|
||||
current_width += w;
|
||||
|
||||
if (!str.len)
|
||||
break;
|
||||
|
@ -730,7 +735,20 @@ int term_disp_width(bstr str)
|
|||
|
||||
str = cluster_end;
|
||||
}
|
||||
width += grapheme_width > 2 ? 2 : grapheme_width;
|
||||
|
||||
next:
|
||||
current_width = MPMIN(current_width, 2);
|
||||
if (width + current_width > max_width) {
|
||||
assert(prev_pos < str.start + str.len);
|
||||
*cut_pos = prev_pos;
|
||||
break;
|
||||
}
|
||||
width += current_width;
|
||||
if (width == max_width) {
|
||||
if (str.len)
|
||||
*cut_pos = str.start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* @brief Determines the number of columns required to display a given string.
|
||||
*
|
||||
* @param str Sequence of UTF-8 chars
|
||||
* @param max_width Maximum allowed width of string
|
||||
* @param cut_pos If max_width is exceeded, this will be initialized to last
|
||||
* full printable character before width limit.
|
||||
* @return int width of the string
|
||||
*/
|
||||
int term_disp_width(bstr str);
|
||||
int term_disp_width(bstr str, int max_width, const unsigned char **cut_pos);
|
||||
|
|
|
@ -2926,6 +2926,12 @@ static int mp_property_osd_ass(void *ctx, struct m_property *prop,
|
|||
return m_property_read_sub(props, action, arg);
|
||||
}
|
||||
|
||||
static int mp_property_term_clip(void *ctx, struct m_property *prop,
|
||||
int action, void *arg)
|
||||
{
|
||||
return m_property_strdup_ro(action, arg, TERM_MSG_0);
|
||||
}
|
||||
|
||||
static int mp_property_term_size(void *ctx, struct m_property *prop,
|
||||
int action, void *arg)
|
||||
{
|
||||
|
@ -4159,6 +4165,8 @@ static const struct m_property mp_properties_base[] = {
|
|||
{"osd-sym-cc", mp_property_osd_sym},
|
||||
{"osd-ass-cc", mp_property_osd_ass},
|
||||
|
||||
{"term-clip-cc", mp_property_term_clip},
|
||||
|
||||
{"mouse-pos", mp_property_mouse_pos},
|
||||
{"touch-pos", mp_property_touch_pos},
|
||||
|
||||
|
|
|
@ -207,6 +207,10 @@ void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines)
|
|||
in += 1;
|
||||
continue;
|
||||
}
|
||||
if (*in == TERM_MSG_0[0]) {
|
||||
in += 1;
|
||||
continue;
|
||||
}
|
||||
if (escape_ass && *in == '{')
|
||||
bstr_xappend(NULL, dst, bstr0("\\"));
|
||||
// Replace newlines with \N for escape-ass. This is necessary to apply
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
|
||||
#include "test_utils.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "misc/codepoint_width.h"
|
||||
|
||||
#define W(s) term_disp_width((bstr)bstr0_lit(s))
|
||||
#define W(s) term_disp_width((bstr)bstr0_lit(s), INT_MAX, &(const unsigned char *){NULL})
|
||||
|
||||
int main(void) {
|
||||
assert_int_equal(W("A"), 1); // Single ASCII character
|
||||
|
@ -64,4 +66,23 @@ int main(void) {
|
|||
|
||||
// ASCII characters with carriage return
|
||||
assert_int_equal(W("ABC\rDEF"), 3);
|
||||
|
||||
bstr str = bstr0("ABCDEF");
|
||||
const unsigned char *cut_pos;
|
||||
|
||||
cut_pos = NULL;
|
||||
assert_int_equal(term_disp_width(str, 3, &cut_pos), 3);
|
||||
assert_int_equal(cut_pos - str.start, 3);
|
||||
|
||||
cut_pos = NULL;
|
||||
assert_int_equal(term_disp_width(str, -2, &cut_pos), 0);
|
||||
assert_int_equal(cut_pos - str.start, 0);
|
||||
|
||||
cut_pos = NULL;
|
||||
assert_int_equal(term_disp_width(str, str.len, &cut_pos), 6);
|
||||
if (cut_pos) {
|
||||
printf("%s:%d: cut_pos != NULL\n", __FILE__, __LINE__);
|
||||
fflush(stdout);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue