1
1
#nullable enable
2
+ using System . Buffers ;
2
3
using System . ComponentModel ;
3
4
using System . Runtime . InteropServices ;
4
5
using Microsoft . Extensions . Logging ;
5
6
using static Terminal . Gui . WindowsConsole ;
6
7
7
8
namespace Terminal . Gui ;
8
9
9
- internal class WindowsOutput : IConsoleOutput
10
+ internal partial class WindowsOutput : IConsoleOutput
10
11
{
11
- [ DllImport ( "kernel32.dll" , EntryPoint = "WriteConsole" , SetLastError = true , CharSet = CharSet . Unicode ) ]
12
- private static extern bool WriteConsole (
12
+ [ LibraryImport ( "kernel32.dll" , EntryPoint = "WriteConsoleW" , SetLastError = true , StringMarshalling = StringMarshalling . Utf16 ) ]
13
+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
14
+ private static partial bool WriteConsole (
13
15
nint hConsoleOutput ,
14
- string lpbufer ,
16
+ ReadOnlySpan < char > lpbufer ,
15
17
uint numberOfCharsToWriten ,
16
18
out uint lpNumberOfCharsWritten ,
17
19
nint lpReserved
@@ -84,7 +86,7 @@ public WindowsOutput ()
84
86
}
85
87
}
86
88
87
- public void Write ( string str )
89
+ public void Write ( ReadOnlySpan < char > str )
88
90
{
89
91
if ( ! WriteConsole ( _screenBuffer , str , ( uint ) str . Length , out uint _ , nint . Zero ) )
90
92
{
@@ -183,7 +185,6 @@ public void Write (IOutputBuffer buffer)
183
185
184
186
public bool WriteToConsole ( Size size , ExtendedCharInfo [ ] charInfoBuffer , Coord bufferSize , SmallRect window , bool force16Colors )
185
187
{
186
- var stringBuilder = new StringBuilder ( ) ;
187
188
188
189
//Debug.WriteLine ("WriteToConsole");
189
190
@@ -213,10 +214,10 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord
213
214
}
214
215
else
215
216
{
216
- stringBuilder . Clear ( ) ;
217
+ StringBuilder stringBuilder = new ( ) ;
217
218
218
219
stringBuilder . Append ( EscSeqUtils . CSI_SaveCursorPosition ) ;
219
- stringBuilder . Append ( EscSeqUtils . CSI_SetCursorPosition ( 0 , 0 ) ) ;
220
+ EscSeqUtils . CSI_AppendCursorPosition ( stringBuilder , 0 , 0 ) ;
220
221
221
222
Attribute ? prev = null ;
222
223
@@ -227,8 +228,8 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord
227
228
if ( attr != prev )
228
229
{
229
230
prev = attr ;
230
- stringBuilder . Append ( EscSeqUtils . CSI_SetForegroundColorRGB ( attr . Foreground . R , attr . Foreground . G , attr . Foreground . B ) ) ;
231
- stringBuilder . Append ( EscSeqUtils . CSI_SetBackgroundColorRGB ( attr . Background . R , attr . Background . G , attr . Background . B ) ) ;
231
+ EscSeqUtils . CSI_AppendForegroundColorRGB ( stringBuilder , attr . Foreground . R , attr . Foreground . G , attr . Foreground . B ) ;
232
+ EscSeqUtils . CSI_AppendBackgroundColorRGB ( stringBuilder , attr . Background . R , attr . Background . G , attr . Background . B ) ;
232
233
}
233
234
234
235
if ( info . Char != '\x1b ' )
@@ -247,14 +248,20 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord
247
248
stringBuilder . Append ( EscSeqUtils . CSI_RestoreCursorPosition ) ;
248
249
stringBuilder . Append ( EscSeqUtils . CSI_HideCursor ) ;
249
250
250
- var s = stringBuilder . ToString ( ) ;
251
+ // TODO: Potentially could stackalloc whenever reasonably small (<= 8 kB?) write buffer is needed.
252
+ char [ ] rentedWriteArray = ArrayPool < char > . Shared . Rent ( minimumLength : stringBuilder . Length ) ;
253
+ try
254
+ {
255
+ Span < char > writeBuffer = rentedWriteArray . AsSpan ( 0 , stringBuilder . Length ) ;
256
+ stringBuilder . CopyTo ( 0 , writeBuffer , stringBuilder . Length ) ;
251
257
252
- // TODO: requires extensive testing if we go down this route
253
- // If console output has changed
254
- //if (s != _lastWrite)
255
- //{
256
- // supply console with the new content
257
- result = WriteConsole ( _screenBuffer , s , ( uint ) s . Length , out uint _ , nint . Zero ) ;
258
+ // Supply console with the new content.
259
+ result = WriteConsole ( _screenBuffer , writeBuffer , ( uint ) writeBuffer . Length , out uint _ , nint . Zero ) ;
260
+ }
261
+ finally
262
+ {
263
+ ArrayPool < char > . Shared . Return ( rentedWriteArray ) ;
264
+ }
258
265
259
266
foreach ( SixelToRender sixel in Application . Sixel )
260
267
{
@@ -297,9 +304,10 @@ public Size GetWindowSize ()
297
304
/// <inheritdoc/>
298
305
public void SetCursorVisibility ( CursorVisibility visibility )
299
306
{
300
- var sb = new StringBuilder ( ) ;
301
- sb . Append ( visibility != CursorVisibility . Invisible ? EscSeqUtils . CSI_ShowCursor : EscSeqUtils . CSI_HideCursor ) ;
302
- Write ( sb . ToString ( ) ) ;
307
+ string cursorVisibilitySequence = visibility != CursorVisibility . Invisible
308
+ ? EscSeqUtils . CSI_ShowCursor
309
+ : EscSeqUtils . CSI_HideCursor ;
310
+ Write ( cursorVisibilitySequence ) ;
303
311
}
304
312
305
313
private Point _lastCursorPosition ;
0 commit comments