Unified · Split
| @@ -0,0 +1 @@ | ||
| 1 | +add `term-clip-cc` | |
| @@ -3377,6 +3377,11 @@ Property list · 3376 unmodified lines | ||
| 3377 | 3377 | See ``--cursor-autohide``. Setting this to a new value will always update |
| 3378 | 3378 | the cursor, and reset the internal timer. |
| 3379 | 3379 | |
| 3380 | +``term-clip-cc`` | |
| 3381 | + Inserts the symbol to force line truncation to the current terminal width. | |
| 3382 | + This can be used for ``show-text`` and other OSD messages. It must be the | |
| 3383 | + first character in the line. It takes effect until the end of the line. | |
| 3384 | + | |
| 3380 | 3385 | ``osd-sym-cc`` |
| 3381 | 3386 | Inserts the current OSD symbol as opaque OSD control code (cc). This makes |
| 3382 | 3387 | sense only with the ``show-text`` command or options which set OSD messages. |
| @@ -374,7 +374,7 @@ static bool test_terminal_level(struct mp_log *log, int lev) · 373 unmodified lines | ||
| 374 | 374 | } |
| 375 | 375 | |
| 376 | 376 | static void append_terminal_line(struct mp_log *log, int lev, |
| 377 | − bstr text, bstr *term_msg, int *line_w) | |
| 377 | + bstr text, bstr *term_msg, int *line_w, int term_w) | |
| 378 | 378 | { |
| 379 | 379 | struct mp_log_root *root = log->root; |
| 380 | 380 | |
| @@ -394,8 +394,35 @@ static void append_terminal_line(struct mp_log *log, int lev, · 13 unmodified lines | ||
| 394 | 394 | } |
| 395 | 395 | |
| 396 | 396 | bstr_xappend(root, term_msg, text); |
| 397 | + | |
| 398 | + const unsigned char *cut_pos = NULL; | |
| 399 | + int width = term_disp_width(bstr_splice(*term_msg, start, term_msg->len), | |
| 400 | + term_w - 3, &cut_pos); | |
| 401 | + if (cut_pos) { | |
| 402 | + int new_len = cut_pos - term_msg->start; | |
| 403 | + bstr rem = {(unsigned char *)cut_pos, term_msg->len - new_len}; | |
| 404 | + term_msg->len = new_len; | |
| 405 | + | |
| 406 | + bstr_xappend(root, term_msg, bstr0("...")); | |
| 407 | + | |
| 408 | + while (rem.len) { | |
| 409 | + if (bstr_eatstart0(&rem, "\033[")) { | |
| 410 | + bstr_xappend(root, term_msg, bstr0("\033[")); | |
| 411 | + | |
| 412 | + while (rem.len && !((*rem.start >= '@' && *rem.start <= '~') || *rem.start == 'm')) { | |
| 413 | + bstr_xappend(root, term_msg, bstr_splice(rem, 0, 1)); | |
| 414 | + rem = bstr_cut(rem, 1); | |
| 415 | + } | |
| 416 | + bstr_xappend(root, term_msg, bstr_splice(rem, 0, 1)); | |
| 417 | + } | |
| 418 | + rem = bstr_cut(rem, 1); | |
| 419 | + } | |
| 420 | + | |
| 421 | + bstr_xappend(root, term_msg, bstr0("\n")); | |
| 422 | + width += 3; | |
| 423 | + } | |
| 397 | 424 | *line_w = root->isatty[term_msg_fileno(root, lev)] |
| 398 | − ? term_disp_width(bstr_splice(*term_msg, start, term_msg->len)) : 0; | |
| 425 | + ? width : 0; | |
| 399 | 426 | } |
| 400 | 427 | |
| 401 | 428 | 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) · 94 unmodified lines | ||
| 496 | 523 | |
| 497 | 524 | if (print_term) { |
| 498 | 525 | int line_w; |
| 499 | − append_terminal_line(log, lev, line, &root->term_msg_tmp, &line_w); | |
| 526 | + append_terminal_line(log, lev, line, &root->term_msg_tmp, &line_w, | |
| 527 | + bstr_eatstart0(&line, TERM_MSG_0) ? term_w : INT_MAX); | |
| 500 | 528 | term_msg_lines += (!line_w || !term_w) |
| 501 | 529 | ? 1 : (line_w + term_w - 1) / term_w; |
| 502 | 530 | } |
| @@ -506,7 +534,8 @@ static void write_term_msg(struct mp_log *log, int lev, bstr text, bstr *out) · 3 unmodified lines | ||
| 506 | 534 | if (lev == MSGL_STATUS) { |
| 507 | 535 | int line_w = 0; |
| 508 | 536 | if (str.len && print_term) |
| 509 | − append_terminal_line(log, lev, str, &root->term_msg_tmp, &line_w); | |
| 537 | + append_terminal_line(log, lev, str, &root->term_msg_tmp, &line_w, | |
| 538 | + bstr_eatstart0(&str, TERM_MSG_0) ? term_w : INT_MAX); | |
| 510 | 539 | term_msg_lines += !term_w ? (str.len ? 1 : 0) |
| 511 | 540 | : (line_w + term_w - 1) / term_w; |
| 512 | 541 | } else if (str.len) { |
| @@ -25,6 +25,8 @@ · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | #include "osdep/compiler.h" |
| 27 | 27 | |
| 28 | +#define TERM_MSG_0 "\xFC" | |
| 29 | + | |
| 28 | 30 | struct mp_log; |
| 29 | 31 | |
| 30 | 32 | // A mp_log instance that never outputs anything. |
| @@ -662,20 +662,26 @@ static int ucdToCharacterWidth(const int val) · 661 unmodified lines | ||
| 662 | 662 | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
| 663 | 663 | */ |
| 664 | 664 | |
| 665 | −int term_disp_width(bstr str) | |
| 665 | +#include "common/common.h" | |
| 666 | + | |
| 667 | +int term_disp_width(bstr str, int max_width, const unsigned char **cut_pos) | |
| 666 | 668 | { |
| 667 | 669 | static const int ambiguous_width = 1; |
| 668 | 670 | |
| 669 | 671 | int width = 0; |
| 670 | 672 | |
| 673 | + const unsigned char *prev_pos = str.start; | |
| 671 | 674 | while (str.len) { |
| 675 | + int current_width = 0; | |
| 676 | + | |
| 672 | 677 | if (bstr_eatstart0(&str, "\033[")) { |
| 673 | 678 | while (str.len && !((*str.start >= '@' && *str.start <= '~') || *str.start == 'm')) |
| 674 | 679 | str = bstr_cut(str, 1); |
| 675 | 680 | str = bstr_cut(str, 1); |
| 676 | − continue; | |
| 681 | + goto next; | |
| 677 | 682 | } |
| 678 | 683 | |
| 684 | + prev_pos = str.start; | |
| 679 | 685 | int cp = bstr_decode_utf8(str, &str); |
| 680 | 686 | |
| 681 | 687 | // Stop processing on any invalid input |
| @@ -684,18 +690,17 @@ int term_disp_width(bstr str) · 2 unmodified lines | ||
| 684 | 690 | |
| 685 | 691 | if (cp == '\r') { |
| 686 | 692 | width = 0; |
| 687 | − continue; | |
| 693 | + goto next; | |
| 688 | 694 | } |
| 689 | 695 | |
| 690 | 696 | if (cp < 0x20) |
| 691 | − continue; | |
| 697 | + goto next; | |
| 692 | 698 | |
| 693 | 699 | if (cp <= 0x7E) { |
| 694 | − width++; | |
| 695 | − continue; | |
| 700 | + current_width = 1; | |
| 701 | + goto next; | |
| 696 | 702 | } |
| 697 | 703 | |
| 698 | − int grapheme_width = 0; | |
| 699 | 704 | int state = 0; |
| 700 | 705 | |
| 701 | 706 | while (true) { |
| @@ -711,7 +716,7 @@ int term_disp_width(bstr str) · 9 unmodified lines | ||
| 711 | 716 | if (cp == 0xFE0F) |
| 712 | 717 | w = 2; |
| 713 | 718 | |
| 714 | − grapheme_width += w; | |
| 719 | + current_width += w; | |
| 715 | 720 | |
| 716 | 721 | if (!str.len) |
| 717 | 722 | break; |
| @@ -730,7 +735,20 @@ int term_disp_width(bstr str) · 12 unmodified lines | ||
| 730 | 735 | |
| 731 | 736 | str = cluster_end; |
| 732 | 737 | } |
| 733 | − width += grapheme_width > 2 ? 2 : grapheme_width; | |
| 738 | + | |
| 739 | +next: | |
| 740 | + current_width = MPMIN(current_width, 2); | |
| 741 | + if (width + current_width > max_width) { | |
| 742 | + assert(prev_pos < str.start + str.len); | |
| 743 | + *cut_pos = prev_pos; | |
| 744 | + break; | |
| 745 | + } | |
| 746 | + width += current_width; | |
| 747 | + if (width == max_width) { | |
| 748 | + if (str.len) | |
| 749 | + *cut_pos = str.start; | |
| 750 | + break; | |
| 751 | + } | |
| 734 | 752 | } |
| 735 | 753 | |
| 736 | 754 | return width; |
| @@ -6,6 +6,9 @@ · 5 unmodified lines | ||
| 6 | 6 | * @brief Determines the number of columns required to display a given string. |
| 7 | 7 | * |
| 8 | 8 | * @param str Sequence of UTF-8 chars |
| 9 | + * @param max_width Maximum allowed width of string | |
| 10 | + * @param cut_pos If max_width is exceeded, this will be initialized to last | |
| 11 | + * full printable character before width limit. | |
| 9 | 12 | * @return int width of the string |
| 10 | 13 | */ |
| 11 | −int term_disp_width(bstr str); | |
| 14 | +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, · 2925 unmodified lines | ||
| 2926 | 2926 | return m_property_read_sub(props, action, arg); |
| 2927 | 2927 | } |
| 2928 | 2928 | |
| 2929 | +static int mp_property_term_clip(void *ctx, struct m_property *prop, | |
| 2930 | + int action, void *arg) | |
| 2931 | +{ | |
| 2932 | + return m_property_strdup_ro(action, arg, TERM_MSG_0); | |
| 2933 | +} | |
| 2934 | + | |
| 2929 | 2935 | static int mp_property_term_size(void *ctx, struct m_property *prop, |
| 2930 | 2936 | int action, void *arg) |
| 2931 | 2937 | { |
| @@ -4159,6 +4165,8 @@ static const struct m_property mp_properties_base[] = { · 1227 unmodified lines | ||
| 4159 | 4165 | {"osd-sym-cc", mp_property_osd_sym}, |
| 4160 | 4166 | {"osd-ass-cc", mp_property_osd_ass}, |
| 4161 | 4167 | |
| 4168 | + {"term-clip-cc", mp_property_term_clip}, | |
| 4169 | + | |
| 4162 | 4170 | {"mouse-pos", mp_property_mouse_pos}, |
| 4163 | 4171 | {"touch-pos", mp_property_touch_pos}, |
| 4164 | 4172 | |
| @@ -207,6 +207,10 @@ void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines) · 206 unmodified lines | ||
| 207 | 207 | in += 1; |
| 208 | 208 | continue; |
| 209 | 209 | } |
| 210 | + if (*in == TERM_MSG_0[0]) { | |
| 211 | + in += 1; | |
| 212 | + continue; | |
| 213 | + } | |
| 210 | 214 | if (escape_ass && *in == '{') |
| 211 | 215 | bstr_xappend(NULL, dst, bstr0("\\")); |
| 212 | 216 | // Replace newlines with \N for escape-ass. This is necessary to apply |
| @@ -17,9 +17,11 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include "test_utils.h" |
| 19 | 19 | |
| 20 | +#include <limits.h> | |
| 21 | + | |
| 20 | 22 | #include "misc/codepoint_width.h" |
| 21 | 23 | |
| 22 | −#define W(s) term_disp_width((bstr)bstr0_lit(s)) | |
| 24 | +#define W(s) term_disp_width((bstr)bstr0_lit(s), INT_MAX, &(const unsigned char *){NULL}) | |
| 23 | 25 | |
| 24 | 26 | int main(void) { |
| 25 | 27 | assert_int_equal(W("A"), 1); // Single ASCII character |
| @@ -64,4 +66,23 @@ int main(void) { · 38 unmodified lines | ||
| 64 | 66 | |
| 65 | 67 | // ASCII characters with carriage return |
| 66 | 68 | assert_int_equal(W("ABC\rDEF"), 3); |
| 69 | + | |
| 70 | + bstr str = bstr0("ABCDEF"); | |
| 71 | + const unsigned char *cut_pos; | |
| 72 | + | |
| 73 | + cut_pos = NULL; | |
| 74 | + assert_int_equal(term_disp_width(str, 3, &cut_pos), 3); | |
| 75 | + assert_int_equal(cut_pos - str.start, 3); | |
| 76 | + | |
| 77 | + cut_pos = NULL; | |
| 78 | + assert_int_equal(term_disp_width(str, -2, &cut_pos), 0); | |
| 79 | + assert_int_equal(cut_pos - str.start, 0); | |
| 80 | + | |
| 81 | + cut_pos = NULL; | |
| 82 | + assert_int_equal(term_disp_width(str, str.len, &cut_pos), 6); | |
| 83 | + if (cut_pos) { | |
| 84 | + printf("%s:%d: cut_pos != NULL\n", __FILE__, __LINE__); | |
| 85 | + fflush(stdout); | |
| 86 | + abort(); | |
| 87 | + } | |
| 67 | 88 | } |