msg: allow to truncate the message to terminal width

This commit is contained in:
Kacper Michajłow 2024-09-23 02:13:17 +02:00
parent 95f0046309
commit bf025cd289
9 changed files with 106 additions and 15 deletions

View File

@ -0,0 +1 @@
add `term-clip-cc`

View File

@ -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.

View File

@ -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) {

View File

@ -25,6 +25,8 @@
#include "osdep/compiler.h"
#define TERM_MSG_0 "\xFC"
struct mp_log;
// A mp_log instance that never outputs anything.

View File

@ -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;

View File

@ -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);

View File

@ -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},

View File

@ -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

View File

@ -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();
}
}