@@ -110,6 +110,9 @@ class HistoryItem
110
110
111
111
static KeyHandler MakeKeyHandler ( Action < ConsoleKeyInfo ? , object > action , string briefDescription , string longDescription = null )
112
112
{
113
+ if ( string . IsNullOrWhiteSpace ( longDescription ) )
114
+ longDescription = PSReadLineResources . ResourceManager . GetString ( briefDescription + "Description" ) ;
115
+
113
116
return new KeyHandler
114
117
{
115
118
Action = action ,
@@ -476,6 +479,8 @@ static PSConsoleReadLine()
476
479
{ Keys . CtrlEnd , MakeKeyHandler ( ForwardDeleteLine , "ForwardDeleteLine" ) } ,
477
480
{ Keys . CtrlHome , MakeKeyHandler ( BackwardDeleteLine , "BackwardDeleteLine" ) } ,
478
481
{ Keys . CtrlRBracket , MakeKeyHandler ( GotoBrace , "GotoBrace" ) } ,
482
+ { Keys . CtrlAltQuestion , MakeKeyHandler ( ShowKeyBindings , "ShowKeyBindings" ) } ,
483
+ { Keys . AltQuestion , MakeKeyHandler ( WhatIsKey , "WhatIsKey" ) } ,
479
484
{ Keys . F3 , MakeKeyHandler ( CharacterSearch , "CharacterSearch" ) } ,
480
485
{ Keys . ShiftF3 , MakeKeyHandler ( CharacterSearchBackward , "CharacterSearchBackward" ) } ,
481
486
} ;
@@ -536,6 +541,8 @@ static PSConsoleReadLine()
536
541
{ Keys . AltY , MakeKeyHandler ( YankPop , "YankPop" ) } ,
537
542
{ Keys . AltBackspace , MakeKeyHandler ( BackwardKillWord , "BackwardKillWord" ) } ,
538
543
{ Keys . AltEquals , MakeKeyHandler ( PossibleCompletions , "PossibleCompletions" ) } ,
544
+ { Keys . CtrlAltQuestion , MakeKeyHandler ( ShowKeyBindings , "ShowKeyBindings" ) } ,
545
+ { Keys . AltQuestion , MakeKeyHandler ( WhatIsKey , "WhatIsKey" ) } ,
539
546
{ Keys . AltSpace , MakeKeyHandler ( SetMark , "SetMark" ) } , // useless entry here for completeness - brings up system menu on Windows
540
547
{ Keys . AltPeriod , MakeKeyHandler ( YankLastArg , "YankLastArg" ) } ,
541
548
{ Keys . AltUnderbar , MakeKeyHandler ( YankLastArg , "YankLastArg" ) } ,
@@ -3066,55 +3073,57 @@ public static void Ding()
3066
3073
// The unit test framework redirects stdout - so it would see Console.WriteLine calls.
3067
3074
// Unfortunately, we are testing exact placement of characters on the screen, so redirection
3068
3075
// doesn't work for us.
3069
- static private void WriteImpl ( string s )
3076
+ static private void WriteLine ( string s )
3070
3077
{
3071
- Debug . Assert ( s . Length <= Console . BufferWidth ) ;
3072
-
3073
3078
var handle = NativeMethods . GetStdHandle ( ( uint ) StandardHandleId . Output ) ;
3074
3079
3075
- var buffer = new CHAR_INFO [ s . Length ] ;
3076
- for ( int i = 0 ; i < s . Length ; i ++ )
3080
+ var buffer = new CHAR_INFO [ Console . BufferWidth ] ;
3081
+ int i = 0 ;
3082
+ int linesWritten = 0 ;
3083
+ int startLine = Console . CursorTop ;
3084
+ var space = new CHAR_INFO ( ' ' , Console . ForegroundColor , Console . BackgroundColor ) ;
3085
+ while ( i < s . Length )
3077
3086
{
3078
- Debug . Assert ( s [ i ] != '\n ' ) ;
3079
- buffer [ i ] = new CHAR_INFO ( s [ i ] , Console . ForegroundColor , Console . BackgroundColor ) ;
3080
- }
3087
+ int j ;
3088
+ for ( j = 0 ; j < buffer . Length && i < s . Length ; j ++ , i ++ )
3089
+ {
3090
+ if ( s [ i ] == '\n ' )
3091
+ {
3092
+ break ;
3093
+ }
3094
+ buffer [ j ] = new CHAR_INFO ( s [ i ] , Console . ForegroundColor , Console . BackgroundColor ) ;
3095
+ }
3081
3096
3082
- var bufferSize = new COORD
3083
- {
3084
- X = ( short ) s . Length ,
3085
- Y = 1
3086
- } ;
3087
- var bufferCoord = new COORD { X = 0 , Y = 0 } ;
3088
- var writeRegion = new SMALL_RECT
3089
- {
3090
- Top = ( short ) Console . CursorTop ,
3091
- Left = 0 ,
3092
- Bottom = ( short ) Console . CursorTop ,
3093
- Right = ( short ) s . Length
3094
- } ;
3095
- NativeMethods . WriteConsoleOutput ( handle , buffer , bufferSize , bufferCoord , ref writeRegion ) ;
3096
- }
3097
+ if ( i < s . Length && s [ i ] == '\n ' )
3098
+ {
3099
+ i ++ ;
3100
+ }
3097
3101
3098
- static private void WriteLine ( string s )
3099
- {
3100
- Debug . Assert ( s . Length <= Console . BufferWidth ) ;
3102
+ while ( j < buffer . Length )
3103
+ {
3104
+ buffer [ j ++ ] = space ;
3105
+ }
3101
3106
3102
- var spaces = Console . BufferWidth - s . Length ;
3103
- if ( spaces > 0 )
3104
- {
3105
- s = s + new string ( ' ' , spaces ) ;
3107
+ var bufferSize = new COORD
3108
+ {
3109
+ X = ( short ) Console . BufferWidth ,
3110
+ Y = 1
3111
+ } ;
3112
+ var bufferCoord = new COORD { X = 0 , Y = 0 } ;
3113
+ var writeRegion = new SMALL_RECT
3114
+ {
3115
+ Top = ( short ) ( startLine + linesWritten ) ,
3116
+ Left = 0 ,
3117
+ Bottom = ( short ) ( startLine + linesWritten ) ,
3118
+ Right = ( short ) Console . BufferWidth
3119
+ } ;
3120
+ NativeMethods . WriteConsoleOutput ( handle , buffer , bufferSize , bufferCoord , ref writeRegion ) ;
3121
+ linesWritten += 1 ;
3106
3122
}
3107
- WriteImpl ( s ) ;
3108
3123
3109
- _singleton . PlaceCursor ( 0 , Console . CursorTop + 1 ) ;
3124
+ _singleton . PlaceCursor ( 0 , Console . CursorTop + linesWritten ) ;
3110
3125
}
3111
3126
3112
- static private void Write ( string s )
3113
- {
3114
- WriteImpl ( s ) ;
3115
-
3116
- _singleton . PlaceCursor ( s . Length , Console . CursorTop ) ;
3117
- }
3118
3127
3119
3128
private bool PromptYesOrNo ( string s )
3120
3129
{
@@ -3224,6 +3233,96 @@ private void ClearDemoWindow()
3224
3233
3225
3234
#endregion Rendering
3226
3235
3236
+ #region Miscellaneous bindable functions
3237
+
3238
+ /// <summary>
3239
+ /// Show all bound keys
3240
+ /// </summary>
3241
+ public static void ShowKeyBindings ( ConsoleKeyInfo ? key = null , object arg = null )
3242
+ {
3243
+ var buffer = new StringBuilder ( ) ;
3244
+ buffer . AppendFormat ( "{0,-20} {1,-24} {2}\n " , "Key" , "Function" , "Description" ) ;
3245
+ buffer . AppendFormat ( "{0,-20} {1,-24} {2}\n " , "---" , "--------" , "-----------" ) ;
3246
+ var boundKeys = GetKeyHandlers ( includeBound : true , includeUnbound : false ) ;
3247
+ var maxDescriptionLength = Console . WindowWidth - 20 - 24 - 2 ;
3248
+ foreach ( var boundKey in boundKeys )
3249
+ {
3250
+ var description = boundKey . Description ;
3251
+ if ( description . Length >= maxDescriptionLength )
3252
+ {
3253
+ description = description . Substring ( 0 , maxDescriptionLength - 3 ) + "..." ;
3254
+ }
3255
+ buffer . AppendFormat ( "{0,-20} {1,-24} {2}\n " , boundKey . Key , boundKey . Function , description ) ;
3256
+ }
3257
+
3258
+ // Don't overwrite any of the line - so move to first line after the end of our buffer.
3259
+ var coords = _singleton . ConvertOffsetToCoordinates ( _singleton . _buffer . Length ) ;
3260
+ _singleton . PlaceCursor ( 0 , coords . Y + 1 ) ;
3261
+
3262
+ WriteLine ( buffer . ToString ( ) ) ;
3263
+ _singleton . _initialY = Console . CursorTop ;
3264
+ _singleton . Render ( ) ;
3265
+ }
3266
+
3267
+ /// <summary>
3268
+ /// Read a key and tell me what the key is bound to.
3269
+ /// </summary>
3270
+ public static void WhatIsKey ( ConsoleKeyInfo ? key = null , object arg = null )
3271
+ {
3272
+ _singleton . _statusLinePrompt = "what-is-key: " ;
3273
+ _singleton . Render ( ) ;
3274
+ var toLookup = ReadKey ( ) ;
3275
+ KeyHandler keyHandler ;
3276
+ var buffer = new StringBuilder ( ) ;
3277
+ _singleton . _dispatchTable . TryGetValue ( toLookup , out keyHandler ) ;
3278
+ buffer . Append ( toLookup . ToGestureString ( ) ) ;
3279
+ if ( keyHandler != null )
3280
+ {
3281
+ if ( keyHandler . BriefDescription == "ChordFirstKey" )
3282
+ {
3283
+ Dictionary < ConsoleKeyInfo , KeyHandler > secondKeyDispatchTable ;
3284
+ if ( _singleton . _chordDispatchTable . TryGetValue ( toLookup , out secondKeyDispatchTable ) )
3285
+ {
3286
+ toLookup = ReadKey ( ) ;
3287
+ secondKeyDispatchTable . TryGetValue ( toLookup , out keyHandler ) ;
3288
+ buffer . Append ( "," ) ;
3289
+ buffer . Append ( toLookup . ToGestureString ( ) ) ;
3290
+ }
3291
+ }
3292
+ }
3293
+ buffer . Append ( ": " ) ;
3294
+ if ( keyHandler != null )
3295
+ {
3296
+ buffer . Append ( keyHandler . BriefDescription ) ;
3297
+ if ( ! string . IsNullOrWhiteSpace ( keyHandler . LongDescription ) )
3298
+ {
3299
+ buffer . Append ( " - " ) ;
3300
+ buffer . Append ( keyHandler . LongDescription ) ;
3301
+ }
3302
+ }
3303
+ else if ( toLookup . KeyChar != 0 )
3304
+ {
3305
+ buffer . Append ( "SelfInsert" ) ;
3306
+ buffer . Append ( " - " ) ;
3307
+ buffer . Append ( PSReadLineResources . SelfInsertDescription ) ;
3308
+ }
3309
+ else
3310
+ {
3311
+ buffer . Append ( PSReadLineResources . KeyIsUnbound ) ;
3312
+ }
3313
+
3314
+ _singleton . _statusLinePrompt = null ;
3315
+ _singleton . Render ( ) ;
3316
+
3317
+ // Don't overwrite any of the line - so move to first line after the end of our buffer.
3318
+ var coords = _singleton . ConvertOffsetToCoordinates ( _singleton . _buffer . Length ) ;
3319
+ _singleton . PlaceCursor ( 0 , coords . Y + 1 ) ;
3320
+
3321
+ WriteLine ( buffer . ToString ( ) ) ;
3322
+ _singleton . _initialY = Console . CursorTop ;
3323
+ _singleton . Render ( ) ;
3324
+ }
3325
+
3227
3326
/// <summary>
3228
3327
/// Turn on demo mode (display events like keys pressed)
3229
3328
/// </summary>
@@ -3253,6 +3352,8 @@ public static void DisableDemoMode(ConsoleKeyInfo? key = null, object arg = null
3253
3352
_singleton . ClearDemoWindow ( ) ;
3254
3353
}
3255
3354
3355
+ #endregion Miscellaneous bindable functions
3356
+
3256
3357
private void SetOptionsInternal ( SetPSReadlineOption options )
3257
3358
{
3258
3359
if ( options . ContinuationPrompt != null )
0 commit comments