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
|
See ``--cursor-autohide``. Setting this to a new value will always update
|
||||||
the cursor, and reset the internal timer.
|
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``
|
``osd-sym-cc``
|
||||||
Inserts the current OSD symbol as opaque OSD control code (cc). This makes
|
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.
|
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,
|
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;
|
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);
|
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)]
|
*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)
|
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) {
|
if (print_term) {
|
||||||
int line_w;
|
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)
|
term_msg_lines += (!line_w || !term_w)
|
||||||
? 1 : (line_w + term_w - 1) / 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) {
|
if (lev == MSGL_STATUS) {
|
||||||
int line_w = 0;
|
int line_w = 0;
|
||||||
if (str.len && print_term)
|
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)
|
term_msg_lines += !term_w ? (str.len ? 1 : 0)
|
||||||
: (line_w + term_w - 1) / term_w;
|
: (line_w + term_w - 1) / term_w;
|
||||||
} else if (str.len) {
|
} else if (str.len) {
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "osdep/compiler.h"
|
#include "osdep/compiler.h"
|
||||||
|
|
||||||
|
#define TERM_MSG_0 "\xFC"
|
||||||
|
|
||||||
struct mp_log;
|
struct mp_log;
|
||||||
|
|
||||||
// A mp_log instance that never outputs anything.
|
// 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/>.
|
* 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;
|
static const int ambiguous_width = 1;
|
||||||
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
|
||||||
|
const unsigned char *prev_pos = str.start;
|
||||||
while (str.len) {
|
while (str.len) {
|
||||||
|
int current_width = 0;
|
||||||
|
|
||||||
if (bstr_eatstart0(&str, "\033[")) {
|
if (bstr_eatstart0(&str, "\033[")) {
|
||||||
while (str.len && !((*str.start >= '@' && *str.start <= '~') || *str.start == 'm'))
|
while (str.len && !((*str.start >= '@' && *str.start <= '~') || *str.start == 'm'))
|
||||||
str = bstr_cut(str, 1);
|
str = bstr_cut(str, 1);
|
||||||
str = bstr_cut(str, 1);
|
str = bstr_cut(str, 1);
|
||||||
continue;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prev_pos = str.start;
|
||||||
int cp = bstr_decode_utf8(str, &str);
|
int cp = bstr_decode_utf8(str, &str);
|
||||||
|
|
||||||
// Stop processing on any invalid input
|
// Stop processing on any invalid input
|
||||||
|
@ -684,18 +690,17 @@ int term_disp_width(bstr str)
|
||||||
|
|
||||||
if (cp == '\r') {
|
if (cp == '\r') {
|
||||||
width = 0;
|
width = 0;
|
||||||
continue;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cp < 0x20)
|
if (cp < 0x20)
|
||||||
continue;
|
goto next;
|
||||||
|
|
||||||
if (cp <= 0x7E) {
|
if (cp <= 0x7E) {
|
||||||
width++;
|
current_width = 1;
|
||||||
continue;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
int grapheme_width = 0;
|
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -711,7 +716,7 @@ int term_disp_width(bstr str)
|
||||||
if (cp == 0xFE0F)
|
if (cp == 0xFE0F)
|
||||||
w = 2;
|
w = 2;
|
||||||
|
|
||||||
grapheme_width += w;
|
current_width += w;
|
||||||
|
|
||||||
if (!str.len)
|
if (!str.len)
|
||||||
break;
|
break;
|
||||||
|
@ -730,7 +735,20 @@ int term_disp_width(bstr str)
|
||||||
|
|
||||||
str = cluster_end;
|
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;
|
return width;
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
* @brief Determines the number of columns required to display a given string.
|
* @brief Determines the number of columns required to display a given string.
|
||||||
*
|
*
|
||||||
* @param str Sequence of UTF-8 chars
|
* @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
|
* @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);
|
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,
|
static int mp_property_term_size(void *ctx, struct m_property *prop,
|
||||||
int action, void *arg)
|
int action, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -4159,6 +4165,8 @@ static const struct m_property mp_properties_base[] = {
|
||||||
{"osd-sym-cc", mp_property_osd_sym},
|
{"osd-sym-cc", mp_property_osd_sym},
|
||||||
{"osd-ass-cc", mp_property_osd_ass},
|
{"osd-ass-cc", mp_property_osd_ass},
|
||||||
|
|
||||||
|
{"term-clip-cc", mp_property_term_clip},
|
||||||
|
|
||||||
{"mouse-pos", mp_property_mouse_pos},
|
{"mouse-pos", mp_property_mouse_pos},
|
||||||
{"touch-pos", mp_property_touch_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;
|
in += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (*in == TERM_MSG_0[0]) {
|
||||||
|
in += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (escape_ass && *in == '{')
|
if (escape_ass && *in == '{')
|
||||||
bstr_xappend(NULL, dst, bstr0("\\"));
|
bstr_xappend(NULL, dst, bstr0("\\"));
|
||||||
// Replace newlines with \N for escape-ass. This is necessary to apply
|
// Replace newlines with \N for escape-ass. This is necessary to apply
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
|
|
||||||
#include "test_utils.h"
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "misc/codepoint_width.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) {
|
int main(void) {
|
||||||
assert_int_equal(W("A"), 1); // Single ASCII character
|
assert_int_equal(W("A"), 1); // Single ASCII character
|
||||||
|
@ -64,4 +66,23 @@ int main(void) {
|
||||||
|
|
||||||
// ASCII characters with carriage return
|
// ASCII characters with carriage return
|
||||||
assert_int_equal(W("ABC\rDEF"), 3);
|
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