@@ -11,58 +11,125 @@ in the source distribution for its full text.
1111#include "CommandScreen.h"
1212
1313#include <assert.h>
14+ #include <locale.h>
15+ #include <stdio.h>
1416#include <stdlib.h>
1517#include <string.h>
18+ #include <wchar.h>
19+ #include <wctype.h>
1620
21+ #include "CRT.h"
1722#include "Macros.h"
1823#include "Panel.h"
1924#include "ProvideCurses.h"
2025
2126
22- static void CommandScreen_scan (InfoScreen * this ) {
23- Panel * panel = this -> display ;
24- int idx = MAXIMUM (Panel_getSelectedIndex (panel ), 0 );
25- Panel_prune (panel );
27+ static int CommandScreen_scanAscii (InfoScreen * this , const char * p , size_t total , char * line ) {
28+ int line_offset = 0 , line_size = 0 , last_spc_offset = -1 ;
29+ for (size_t i = 0 ; i < total ; i ++ , line_offset ++ ) {
30+ assert (line_offset >= 0 && (size_t )line_offset <= total );
31+ char c = line [line_offset ] = p [i ];
32+ if (c == ' ' ) {
33+ last_spc_offset = line_offset ;
34+ }
2635
27- const char * p = Process_getCommand (this -> process );
36+ if (line_offset == COLS ) {
37+ line_size = (last_spc_offset == -1 ) ? line_offset : last_spc_offset ;
38+ line [line_size ] = '\0' ;
39+ InfoScreen_addLine (this , line );
2840
29- size_t line_maxlen = COLS < 40 ? 40 : COLS ;
30- size_t line_offset = 0 ;
31- size_t last_space = 0 ;
32- char * line = xCalloc (line_maxlen + 1 , sizeof (char ));
41+ line_offset -= line_size ;
42+ last_spc_offset = -1 ;
43+ memcpy (line , p + i - line_offset , line_offset + 1 );
44+ }
45+ }
3346
34- for (; * p != '\0' ; p ++ ) {
35- if (line_offset >= line_maxlen ) {
36- assert (line_offset <= line_maxlen );
37- assert (last_space <= line_maxlen );
47+ return line_offset ;
48+ }
3849
39- size_t line_len = last_space <= 0 ? line_offset : last_space ;
40- char tmp = line [line_len ];
41- line [line_len ] = '\0' ;
42- InfoScreen_addLine (this , line );
43- line [line_len ] = tmp ;
50+ #ifdef HAVE_LIBNCURSESW
51+
52+ static int CommandScreen_scanWide (InfoScreen * this , const char * p , size_t total , char * line ) {
53+ mbstate_t state ;
54+ memset (& state , 0 , sizeof (state ));
55+ int line_cols = 0 , line_offset = 0 , line_size = 0 , width = 1 ;
56+ int last_spc_cols = -1 , last_spc_offset = -1 ;
57+ for (size_t i = 0 , bytes = 1 ; i < total ; bytes = 1 , width = 1 ) {
58+ assert (line_offset >= 0 && (size_t )line_offset <= total );
59+ unsigned char c = (unsigned char )p [i ];
60+ if (c < 0x80 ) { // skip mbrtowc for ASCII characters
61+ line [line_offset ] = c ;
62+ if (c == ' ' ) {
63+ last_spc_offset = line_offset ;
64+ last_spc_cols = line_cols ;
65+ }
66+ } else {
67+ wchar_t wc ;
68+ bytes = mbrtowc (& wc , p + i , total - i , & state );
69+ if (bytes != (size_t )-1 && bytes != (size_t )-2 ) {
70+ width = wcwidth (wc );
71+ width = MAXIMUM (width , 1 );
72+ } else {
73+ bytes = 1 ;
74+ }
75+ memcpy (line + line_offset , p + i , bytes );
76+ }
4477
45- assert (line_len <= line_offset );
46- line_offset -= line_len ;
47- memmove (line , line + line_len , line_offset );
78+ i += bytes ;
79+ line_offset += bytes ;
80+ line_cols += width ;
81+ if (line_cols < COLS ) {
82+ continue ;
83+ }
4884
49- last_space = 0 ;
85+ if (last_spc_offset >= 0 ) { // wrap by last space
86+ line_size = last_spc_offset ;
87+ line_cols -= last_spc_cols ;
88+ last_spc_offset = last_spc_cols = -1 ;
89+ } else if (line_cols > COLS ) { // wrap current wide char to next line
90+ line_size = line_offset - (int ) bytes ;
91+ line_cols = width ;
92+ } else { // wrap by current character
93+ line_size = line_offset ;
94+ line_cols = 0 ;
5095 }
5196
52- line [line_offset ++ ] = * p ;
53- if (* p == ' ' ) {
54- last_space = line_offset ;
97+ line [line_size ] = '\0' ;
98+ InfoScreen_addLine (this , line );
99+ line_offset -= line_size ;
100+ if (line_offset > 0 ) {
101+ memcpy (line , p + i - line_offset , line_offset + 1 );
55102 }
56103 }
57104
105+ return line_offset ;
106+ }
107+
108+ #endif // HAVE_LIBNCURSESW
109+
110+ static void CommandScreen_scan (InfoScreen * this ) {
111+ Panel * panel = this -> display ;
112+ int idx = Panel_getSelectedIndex (panel );
113+ Panel_prune (panel );
114+
115+ const char * p = Process_getCommand (this -> process );
116+ assert (p != NULL );
117+ size_t total = strlen (p );
118+ char line [total + 1 ];
119+
120+ int line_offset =
121+ #ifdef HAVE_LIBNCURSESW
122+ CRT_utf8 ? CommandScreen_scanWide (this , p , total , line ) :
123+ #endif
124+ CommandScreen_scanAscii (this , p , total , line );
125+
126+ assert (line_offset >= 0 && (size_t )line_offset <= total );
58127 if (line_offset > 0 ) {
59128 line [line_offset ] = '\0' ;
60129 InfoScreen_addLine (this , line );
61130 }
62131
63- free (line );
64-
65- Panel_setSelected (panel , idx );
132+ Panel_setSelected (panel , MAXIMUM (idx , 0 ));
66133}
67134
68135static void CommandScreen_draw (InfoScreen * this ) {
0 commit comments