History

msg: allow to truncate the message to terminal width

Kacper Michajłow committed 2 years ago

Commit bf025cd1 parent 95f00469 files · +106 −15Browse files

Unified · Split

9 files
  1. DOCS/interface-changes/term-clip-cc.txt +1 −0
  2. DOCS/man/input.rst +5 −0
  3. common/msg.c +33 −4
  4. common/msg.h +2 −0
  5. misc/codepoint_width.c +27 −9
  6. misc/codepoint_width.h +4 −1
  7. player/command.c +8 −0
  8. sub/osd_libass.c +4 −0
  9. test/codepoint_width.c +22 −1
DOCS/interface-changes/term-clip-cc.txt+1−0
@@ -0,0 +1 @@
1+add `term-clip-cc`
DOCS/man/input.rst+5−0
@@ -3377,6 +3377,11 @@ Property list · 3376 unmodified lines
33773377 See ``--cursor-autohide``. Setting this to a new value will always update
33783378 the cursor, and reset the internal timer.
33793379
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+
33803385 ``osd-sym-cc``
33813386 Inserts the current OSD symbol as opaque OSD control code (cc). This makes
33823387 sense only with the ``show-text`` command or options which set OSD messages.
common/msg.c+33−4
@@ -374,7 +374,7 @@ static bool test_terminal_level(struct mp_log *log, int lev) · 373 unmodified lines
374374 }
375375
376376 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)
378378 {
379379 struct mp_log_root *root = log->root;
380380
@@ -394,8 +394,35 @@ static void append_terminal_line(struct mp_log *log, int lev, · 13 unmodified lines
394394 }
395395
396396 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+ }
397424 *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;
399426 }
400427
401428 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
496523
497524 if (print_term) {
498525 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);
500528 term_msg_lines += (!line_w || !term_w)
501529 ? 1 : (line_w + term_w - 1) / term_w;
502530 }
@@ -506,7 +534,8 @@ static void write_term_msg(struct mp_log *log, int lev, bstr text, bstr *out) · 3 unmodified lines
506534 if (lev == MSGL_STATUS) {
507535 int line_w = 0;
508536 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);
510539 term_msg_lines += !term_w ? (str.len ? 1 : 0)
511540 : (line_w + term_w - 1) / term_w;
512541 } else if (str.len) {
common/msg.h+2−0
@@ -25,6 +25,8 @@ · 24 unmodified lines
2525
2626 #include "osdep/compiler.h"
2727
28+#define TERM_MSG_0 "\xFC"
29+
2830 struct mp_log;
2931
3032 // A mp_log instance that never outputs anything.
misc/codepoint_width.c+27−9
@@ -662,20 +662,26 @@ static int ucdToCharacterWidth(const int val) · 661 unmodified lines
662662 * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
663663 */
664664
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)
666668 {
667669 static const int ambiguous_width = 1;
668670
669671 int width = 0;
670672
673+ const unsigned char *prev_pos = str.start;
671674 while (str.len) {
675+ int current_width = 0;
676+
672677 if (bstr_eatstart0(&str, "\033[")) {
673678 while (str.len && !((*str.start >= '@' && *str.start <= '~') || *str.start == 'm'))
674679 str = bstr_cut(str, 1);
675680 str = bstr_cut(str, 1);
676− continue;
681+ goto next;
677682 }
678683
684+ prev_pos = str.start;
679685 int cp = bstr_decode_utf8(str, &str);
680686
681687 // Stop processing on any invalid input
@@ -684,18 +690,17 @@ int term_disp_width(bstr str) · 2 unmodified lines
684690
685691 if (cp == '\r') {
686692 width = 0;
687− continue;
693+ goto next;
688694 }
689695
690696 if (cp < 0x20)
691− continue;
697+ goto next;
692698
693699 if (cp <= 0x7E) {
694− width++;
695− continue;
700+ current_width = 1;
701+ goto next;
696702 }
697703
698− int grapheme_width = 0;
699704 int state = 0;
700705
701706 while (true) {
@@ -711,7 +716,7 @@ int term_disp_width(bstr str) · 9 unmodified lines
711716 if (cp == 0xFE0F)
712717 w = 2;
713718
714− grapheme_width += w;
719+ current_width += w;
715720
716721 if (!str.len)
717722 break;
@@ -730,7 +735,20 @@ int term_disp_width(bstr str) · 12 unmodified lines
730735
731736 str = cluster_end;
732737 }
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+ }
734752 }
735753
736754 return width;
misc/codepoint_width.h+4−1
@@ -6,6 +6,9 @@ · 5 unmodified lines
66 * @brief Determines the number of columns required to display a given string.
77 *
88 * @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.
912 * @return int width of the string
1013 */
11−int term_disp_width(bstr str);
14+int term_disp_width(bstr str, int max_width, const unsigned char **cut_pos);
player/command.c+8−0
@@ -2926,6 +2926,12 @@ static int mp_property_osd_ass(void *ctx, struct m_property *prop, · 2925 unmodified lines
29262926 return m_property_read_sub(props, action, arg);
29272927 }
29282928
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+
29292935 static int mp_property_term_size(void *ctx, struct m_property *prop,
29302936 int action, void *arg)
29312937 {
@@ -4159,6 +4165,8 @@ static const struct m_property mp_properties_base[] = { · 1227 unmodified lines
41594165 {"osd-sym-cc", mp_property_osd_sym},
41604166 {"osd-ass-cc", mp_property_osd_ass},
41614167
4168+ {"term-clip-cc", mp_property_term_clip},
4169+
41624170 {"mouse-pos", mp_property_mouse_pos},
41634171 {"touch-pos", mp_property_touch_pos},
41644172
sub/osd_libass.c+4−0
@@ -207,6 +207,10 @@ void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines) · 206 unmodified lines
207207 in += 1;
208208 continue;
209209 }
210+ if (*in == TERM_MSG_0[0]) {
211+ in += 1;
212+ continue;
213+ }
210214 if (escape_ass && *in == '{')
211215 bstr_xappend(NULL, dst, bstr0("\\"));
212216 // Replace newlines with \N for escape-ass. This is necessary to apply
test/codepoint_width.c+22−1
@@ -17,9 +17,11 @@ · 16 unmodified lines
1717
1818 #include "test_utils.h"
1919
20+#include <limits.h>
21+
2022 #include "misc/codepoint_width.h"
2123
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})
2325
2426 int main(void) {
2527 assert_int_equal(W("A"), 1); // Single ASCII character
@@ -64,4 +66,23 @@ int main(void) { · 38 unmodified lines
6466
6567 // ASCII characters with carriage return
6668 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+ }
6788 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t