1
+ /*
2
+ * Copyright (c) 2021, the original author or authors.
3
+ *
4
+ * This software is distributable under the BSD license. See the terms of the
5
+ * BSD license in the documentation provided with this software.
6
+ *
7
+ * https://opensource.org/licenses/BSD-3-Clause
8
+ */
9
+ package org .jline .utils ;
10
+
11
+ import java .io .ByteArrayOutputStream ;
12
+ import java .io .IOException ;
13
+ import java .io .OutputStream ;
14
+ import java .nio .ByteBuffer ;
15
+ import java .nio .CharBuffer ;
16
+ import java .nio .charset .Charset ;
17
+ import java .nio .charset .CharsetDecoder ;
18
+ import java .nio .charset .CoderResult ;
19
+ import java .nio .charset .CodingErrorAction ;
20
+ import java .nio .charset .StandardCharsets ;
21
+ import java .util .ArrayList ;
22
+ import java .util .List ;
23
+
24
+ import org .jline .terminal .Attributes ;
25
+ import org .jline .terminal .Size ;
26
+ import org .jline .terminal .Terminal ;
27
+ import org .jline .terminal .TerminalBuilder ;
28
+ import org .jline .terminal .impl .LineDisciplineTerminal ;
29
+ import org .junit .Test ;
30
+
31
+ import static org .jline .utils .InfoCmp .Capability .enter_ca_mode ;
32
+ import static org .jline .utils .InfoCmp .Capability .exit_ca_mode ;
33
+ import static org .junit .Assert .assertEquals ;
34
+
35
+ public class DisplayTest {
36
+
37
+ @ Test
38
+ public void i737 () throws IOException {
39
+ int rows = 10 ;
40
+ int cols = 25 ;
41
+ try (VirtualTerminal terminal = new VirtualTerminal ("jline" , "xterm" , StandardCharsets .UTF_8 , cols , rows )) {
42
+ Attributes savedAttributes = terminal .enterRawMode ();
43
+ terminal .puts (enter_ca_mode );
44
+ int height = terminal .getHeight ();
45
+
46
+ Display display = new Display (terminal , true );
47
+ display .resize (height , terminal .getWidth ());
48
+
49
+ // Build Strings to displayed
50
+ List <AttributedString > lines1 = new ArrayList <>();
51
+ for (int i = 1 ; i < height + 1 ; i ++) {
52
+ lines1 .add (new AttributedString (String .format ("%03d: %s" , i , "Chaine de test..." )));
53
+ }
54
+
55
+ List <AttributedString > lines2 = new ArrayList <>();
56
+ for (int i = 0 ; i < height ; i ++) {
57
+ lines2 .add (new AttributedString (String .format ("%03d: %s" , i , "Chaine de test..." )));
58
+ }
59
+
60
+ display .update (lines1 , 0 );
61
+
62
+ display .update (lines2 , 0 );
63
+
64
+ long [] screen = terminal .dump ();
65
+ List <AttributedString > lines = new ArrayList <>();
66
+ for (int r = 0 ; r < rows ; r ++) {
67
+ AttributedStringBuilder sb = new AttributedStringBuilder ();
68
+ for (int i = 0 ; i < cols ; i ++) {
69
+ sb .append ((char ) screen [i + cols * r ]);
70
+ }
71
+ lines .add (sb .toAttributedString ());
72
+ }
73
+ assertEquals ("009: Chaine de test... " , lines .get (rows -1 ).toString ());
74
+
75
+ terminal .setAttributes (savedAttributes );
76
+ terminal .puts (exit_ca_mode );
77
+ }
78
+ }
79
+
80
+ static class VirtualTerminal extends LineDisciplineTerminal {
81
+ private final ScreenTerminal virtual ;
82
+ private final OutputStream masterInputOutput ;
83
+ public VirtualTerminal (String name , String type , Charset encoding , int cols , int rows ) throws IOException {
84
+ super (name , type , new DelegateOutputStream (), encoding );
85
+ setSize (new Size (cols , rows ));
86
+ virtual = new ScreenTerminal (cols , rows );
87
+ ((DelegateOutputStream ) masterOutput ).output = new MasterOutputStream ();
88
+ masterInputOutput = new OutputStream () {
89
+ @ Override
90
+ public void write (int b ) throws IOException {
91
+ VirtualTerminal .this .processInputByte (b );
92
+ }
93
+ };
94
+ }
95
+
96
+ public long [] dump () {
97
+ long [] screen = new long [size .getRows () * size .getColumns ()];
98
+ virtual .dump (screen , 0 , 0 , size .getRows (), size .getColumns (), null );
99
+ return screen ;
100
+ }
101
+
102
+ private static class DelegateOutputStream extends OutputStream {
103
+ OutputStream output ;
104
+
105
+ @ Override
106
+ public void write (int b ) throws IOException {
107
+ output .write (b );
108
+ }
109
+
110
+ @ Override
111
+ public void write (byte [] b ) throws IOException {
112
+ output .write (b );
113
+ }
114
+
115
+ @ Override
116
+ public void write (byte [] b , int off , int len ) throws IOException {
117
+ output .write (b , off , len );
118
+ }
119
+
120
+ @ Override
121
+ public void flush () throws IOException {
122
+ output .flush ();
123
+ }
124
+
125
+ @ Override
126
+ public void close () throws IOException {
127
+ output .close ();
128
+ }
129
+ }
130
+
131
+ private class MasterOutputStream extends OutputStream {
132
+ private final ByteArrayOutputStream buffer = new ByteArrayOutputStream ();
133
+ private final CharsetDecoder decoder = Charset .defaultCharset ().newDecoder ()
134
+ .onMalformedInput (CodingErrorAction .REPLACE )
135
+ .onUnmappableCharacter (CodingErrorAction .REPLACE );
136
+
137
+ @ Override
138
+ public synchronized void write (int b ) {
139
+ buffer .write (b );
140
+ }
141
+
142
+ @ Override
143
+ public void write (byte [] b , int off , int len ) throws IOException {
144
+ buffer .write (b , off , len );
145
+ }
146
+
147
+ @ Override
148
+ public synchronized void flush () throws IOException {
149
+ int size = buffer .size ();
150
+ if (size > 0 ) {
151
+ CharBuffer out ;
152
+ for (; ; ) {
153
+ out = CharBuffer .allocate (size );
154
+ ByteBuffer in = ByteBuffer .wrap (buffer .toByteArray ());
155
+ CoderResult result = decoder .decode (in , out , false );
156
+ if (result .isOverflow ()) {
157
+ size *= 2 ;
158
+ } else {
159
+ buffer .reset ();
160
+ buffer .write (in .array (), in .arrayOffset (), in .remaining ());
161
+ break ;
162
+ }
163
+ }
164
+ if (out .position () > 0 ) {
165
+ out .flip ();
166
+ virtual .write (out );
167
+ masterInputOutput .write (virtual .read ().getBytes ());
168
+ }
169
+ }
170
+ }
171
+
172
+ @ Override
173
+ public void close () throws IOException {
174
+ flush ();
175
+ }
176
+ }
177
+ }
178
+
179
+ public static void main (String [] args ) throws InterruptedException , IOException {
180
+
181
+ try (Terminal terminal = TerminalBuilder .builder ().build ()) {
182
+ Attributes savedAttributes = terminal .enterRawMode ();
183
+ terminal .puts (enter_ca_mode );
184
+ int height = terminal .getHeight ();
185
+
186
+ Display display = new Display (terminal , true );
187
+ display .resize (height , terminal .getWidth ());
188
+
189
+ // Build Strings to displayed
190
+ List <AttributedString > lines1 = new ArrayList <>();
191
+ for (int i = 1 ; i < height + 1 ; i ++) {
192
+ lines1 .add (new AttributedString (String .format ("%03d: %s" , i , "Chaine de test..." )));
193
+ }
194
+
195
+ List <AttributedString > lines2 = new ArrayList <>();
196
+ for (int i = 0 ; i < height ; i ++) {
197
+ lines2 .add (new AttributedString (String .format ("%03d: %s" , i , "Chaine de test..." )));
198
+ }
199
+
200
+ // Display with tempo
201
+ display .update (lines1 , 0 );
202
+ Thread .sleep (3000 );
203
+
204
+ display .update (lines2 , 0 );
205
+ Thread .sleep (3000 );
206
+
207
+ terminal .setAttributes (savedAttributes );
208
+ terminal .puts (exit_ca_mode );
209
+ }
210
+ }
211
+ }
0 commit comments