Skip to content

Commit e6f2301

Browse files
committed
Safely render the rest of basic editing and undo/redo
Including revert line, forward delete, and case-changing. Undo/redo tested across characters and strings, insertions and deletions.
1 parent 4cb0f6c commit e6f2301

File tree

6 files changed

+40
-8
lines changed

6 files changed

+40
-8
lines changed

PSReadLine/BasicEditing.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ public static void RevertLine(ConsoleKeyInfo? key = null, object arg = null)
7373
_singleton._edits[_singleton._undoEditIndex - 1].Undo();
7474
_singleton._undoEditIndex--;
7575
}
76-
_singleton.Render();
76+
// Undo has already safely rendered the character removals
77+
_singleton.SafeRender();
7778
}
7879

7980
/// <summary>
@@ -86,8 +87,10 @@ public static void CancelLine(ConsoleKeyInfo? key = null, object arg = null)
8687
_singleton._current = _singleton._buffer.Length;
8788

8889
using var _ = _singleton._prediction.DisableScoped();
90+
// The behavior of this is as expected under a screen reader
8991
_singleton.ForceRender();
9092

93+
// Display a literal ^C in bright red then reset formatting
9194
_singleton._console.Write("\x1b[91m^C\x1b[0m");
9295

9396
_singleton._buffer.Clear(); // Clear so we don't actually run the input
@@ -138,7 +141,8 @@ private static void ForwardDeleteImpl(int endPosition, Action<ConsoleKeyInfo?, o
138141
!InViEditMode()));
139142

140143
buffer.Remove(current, length);
141-
_singleton.Render();
144+
// Moves cursor to current (backwards probably) and then deletes length
145+
_singleton.SafeRender($"\x1b[{length}P", current);
142146
}
143147
}
144148

@@ -168,6 +172,7 @@ private static void BackwardDeleteSubstring(int position, Action<ConsoleKeyInfo?
168172

169173
_singleton.RemoveTextToViRegister(position, count, instigator, arg: null, !InViEditMode());
170174
_singleton._current = position;
175+
// TODO: This seems to only be used in Vi mode which we need to evaluate under a screen reader
171176
_singleton.Render();
172177
}
173178
}
@@ -268,7 +273,8 @@ private static void UpdateWordCase(bool toUpper)
268273
Replace(_singleton._current, wordlen, word);
269274

270275
_singleton.MoveCursor(endOfWord);
271-
_singleton.Render();
276+
// Replace has already safely rendered the replacement
277+
_singleton.SafeRender();
272278
}
273279

274280
/// <summary>
@@ -311,7 +317,8 @@ public static void CapitalizeWord(ConsoleKeyInfo? key = null, object arg = null)
311317
}
312318

313319
_singleton.MoveCursor(endOfWord);
314-
_singleton.Render();
320+
// Replace has already safely rendered the replacement
321+
_singleton.SafeRender();
315322
}
316323

317324
private bool AcceptLineImpl(bool validate)
@@ -337,6 +344,7 @@ private bool AcceptLineImpl(bool validate)
337344

338345
if (renderNeeded)
339346
{
347+
// TODO: Evaluate this under a screen reader
340348
ForceRender();
341349
}
342350

@@ -363,6 +371,7 @@ private bool AcceptLineImpl(bool validate)
363371
_statusLinePrompt = "";
364372
_statusBuffer.Append(errorMessage);
365373
_statusIsErrorMessage = true;
374+
// TODO: Evaluate this under a screen reader
366375
Render();
367376
return false;
368377
}

PSReadLine/Completion.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ private void CompleteImpl(bool menuSelect)
236236
// completions, then we'll be showing the possible completions where it's very
237237
// unlikely that we would add a trailing backslash.
238238

239+
// Replace has already safely rendered the replacement
239240
DoReplacementForCompletion(completions.CompletionMatches[0], completions);
240241
return;
241242
}
@@ -835,6 +836,7 @@ private static string GetMenuItem(string item, int columnWidth)
835836
return item;
836837
}
837838

839+
// TODO: Test menu completions under a screen reader
838840
private void MenuCompleteImpl(Menu menu, CommandCompletion completions)
839841
{
840842
var menuStack = new Stack<Menu>(10);

PSReadLine/KeyBindings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@ public static void ShowKeyBindings(ConsoleKeyInfo? key = null, object arg = null
681681
public static void WhatIsKey(ConsoleKeyInfo? key = null, object arg = null)
682682
{
683683
_singleton._statusLinePrompt = "what-is-key: ";
684+
// TODO: Evaluate this under a screen reader
684685
_singleton.Render();
685686
var toLookup = ReadKey();
686687
var buffer = new StringBuilder();

PSReadLine/ReadLine.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ internal static PSKeyInfo ReadKey()
287287
_singleton._initialY = newCursorTop;
288288
if (bufferLen > 0)
289289
{
290+
// TODO: Evaluate this under a screen reader
290291
_singleton.Render();
291292
}
292293
}
@@ -332,6 +333,7 @@ internal static PSKeyInfo ReadKey()
332333
_singleton._getNextHistoryIndex = _singleton._history.Count;
333334
_singleton._current = 0;
334335
_singleton._buffer.Clear();
336+
// TODO: Evaluate this under a screen reader
335337
_singleton.Render();
336338
throw new OperationCanceledException();
337339
}
@@ -1110,6 +1112,8 @@ public static void InvokePrompt(ConsoleKeyInfo? key = null, object arg = null)
11101112
_singleton._previousRender.UpdateConsoleInfo(console);
11111113
_singleton._previousRender.initialY = _singleton._initialY;
11121114

1115+
// TODO: Evaluate this under a screen reader
1116+
// It appears that VS Code's shell integration injects into the prompt
11131117
_singleton.Render();
11141118
console.CursorVisible = true;
11151119
}

PSReadLine/Render.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ private void RenderWithPredictionQueryPaused()
218218
Render();
219219
}
220220

221-
private void SafeRender(string s, int? cursorBefore = null, int? cursorAfter = null)
221+
private void SafeRender(string s = null, int? cursorBefore = null, int? cursorAfter = null)
222222
{
223223
// Render as usual if we're not supporting a screen reader
224224
if (!_singleton.Options.ScreenReader)
@@ -233,7 +233,8 @@ private void SafeRender(string s, int? cursorBefore = null, int? cursorAfter = n
233233

234234
// Directly write without re-rendering
235235
// This means using ANSI escapes for movement
236-
_console.Write(s);
236+
if (!string.IsNullOrEmpty(s))
237+
_console.Write(s);
237238

238239
// Some commands adjust the cursor after writing
239240
if (cursorAfter.HasValue)
@@ -1707,6 +1708,7 @@ public static void Ding()
17071708
_singleton._mockableMethods.Ding();
17081709
}
17091710

1711+
// TODO: Evaluate this under a screen reader
17101712
private bool PromptYesOrNo(string s)
17111713
{
17121714
_statusLinePrompt = s;

PSReadLine/UndoRedo.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ public static void Undo(ConsoleKeyInfo? key = null, object arg = null)
127127
{
128128
_singleton._current = Math.Max(0, _singleton._buffer.Length + ViEndOfLineFactor);
129129
}
130-
_singleton.Render();
130+
// Undo has already safely rendered the character removals
131+
_singleton.SafeRender();
131132
}
132133
else
133134
{
@@ -144,7 +145,8 @@ public static void Redo(ConsoleKeyInfo? key = null, object arg = null)
144145
{
145146
_singleton._edits[_singleton._undoEditIndex].Redo();
146147
_singleton._undoEditIndex++;
147-
_singleton.Render();
148+
// Redo has already safely rendered the character removals
149+
_singleton.SafeRender();
148150
}
149151
else
150152
{
@@ -183,12 +185,16 @@ public override void Undo()
183185
Debug.Assert(_singleton._buffer[_insertStartPosition] == _insertedCharacter, "Character to undo is not what it should be");
184186
_singleton._buffer.Remove(_insertStartPosition, 1);
185187
_singleton._current = _insertStartPosition;
188+
// Same as remove
189+
_singleton.SafeRender("\x1b[1P", _insertStartPosition);
186190
}
187191

188192
public override void Redo()
189193
{
190194
_singleton._buffer.Insert(_insertStartPosition, _insertedCharacter);
191195
_singleton._current++;
196+
// Same as insert
197+
_singleton.SafeRender(_insertedCharacter.ToString(), _insertStartPosition);
192198
}
193199
}
194200

@@ -217,12 +223,16 @@ public override void Undo()
217223
"Character to undo is not what it should be");
218224
_singleton._buffer.Remove(_insertStartPosition, _insertedString.Length);
219225
_singleton._current = _insertStartPosition;
226+
// Same as remove
227+
_singleton.SafeRender($"\x1b[{_insertedString.Length}P", _insertStartPosition);
220228
}
221229

222230
public override void Redo()
223231
{
224232
_singleton._buffer.Insert(_insertStartPosition, _insertedString);
225233
_singleton._current += _insertedString.Length;
234+
// Same as insert
235+
_singleton.SafeRender(_insertedString, _insertStartPosition);
226236
}
227237
}
228238

@@ -292,12 +302,16 @@ public override void Undo()
292302
_singleton._current = _moveCursorToEndWhenUndo
293303
? _deleteStartPosition + _deletedString.Length
294304
: _deleteStartPosition;
305+
// Same as insert
306+
_singleton.SafeRender(_deletedString, _deleteStartPosition, _singleton._current);
295307
}
296308

297309
public override void Redo()
298310
{
299311
_singleton._buffer.Remove(_deleteStartPosition, _deletedString.Length);
300312
_singleton._current = _deleteStartPosition;
313+
// Same as remove
314+
_singleton.SafeRender($"\x1b[{_deletedString.Length}P", _deleteStartPosition);
301315
}
302316
}
303317

0 commit comments

Comments
 (0)