-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change interactive window behavior when typing inside readonly area #5339
Changes from all commits
c1d1761
f40a5f7
1c40267
4b58de6
a3cd53c
b7d872c
5c61156
e9137a0
72ef9aa
b2c9128
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -577,7 +577,25 @@ private void RestoreUncommittedInput() | |
/// </summary> | ||
public bool Paste() | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
if (!TextView.Selection.IsEmpty) | ||
{ | ||
if (CutOrDeleteSelection(isCut: false)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
} | ||
else if (IsInActivePrompt(TextView.Caret.Position.BufferPosition)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
else if (MapToEditableBuffer(TextView.Caret.Position.BufferPosition) == null) | ||
{ | ||
return false; | ||
} | ||
|
||
string format = Evaluator.FormatClipboard(); | ||
if (format != null) | ||
|
@@ -1164,6 +1182,32 @@ private int GetPromptIndexForPoint(ReadOnlyCollection<SnapshotSpan> sourceSpans, | |
} | ||
return index; | ||
} | ||
|
||
private bool IsInActivePrompt(SnapshotPoint point) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even better, see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @genlu Yes, I appear to have misunderstood what the method was trying to do. |
||
var editableBuffer = ReadingStandardInput ? StandardInputBuffer : CurrentLanguageBuffer; | ||
if (editableBuffer == null) | ||
{ | ||
return false; | ||
} | ||
|
||
var sourceSpans = GetSourceSpans(point.Snapshot); | ||
var index = GetSourceSpanIndex(sourceSpans, point); | ||
if (index == sourceSpans.Count) | ||
{ | ||
index--; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @amcasey Well, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true in practice, but we probably don't want to depend on it. I'm very surprised to learn that |
||
} | ||
|
||
if (!IsPrompt(sourceSpans[index])) | ||
{ | ||
return false; | ||
} | ||
|
||
Debug.Assert(index + 1 < sourceSpans.Count); | ||
var followingSpan = sourceSpans[index + 1]; | ||
// if the following span is editable, then the prompt is active. | ||
return GetPositionInBuffer(followingSpan.Start, editableBuffer) != null; | ||
} | ||
|
||
/// <summary> | ||
/// Return the index of the span containing the point. Returns the | ||
|
@@ -2119,17 +2163,37 @@ public bool Delete() | |
bool handled = false; | ||
if (!TextView.Selection.IsEmpty) | ||
{ | ||
if (TextView.Selection.Mode == TextSelectionMode.Stream || ReduceBoxSelectionToEditableBox()) | ||
if (CutOrDeleteSelection(isCut: false)) | ||
{ | ||
CutOrDeleteSelection(isCut: false); | ||
MoveCaretToClosestEditableBuffer(); | ||
handled = true; | ||
} | ||
} | ||
|
||
else if (IsInActivePrompt(TextView.Caret.Position.BufferPosition)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
return handled; | ||
} | ||
|
||
private bool IsStreamSelectionInEditableBuffer(ITextSelection selection) | ||
{ | ||
Debug.Assert(selection.Mode == TextSelectionMode.Stream); | ||
|
||
var editableBuffer = (ReadingStandardInput) ? StandardInputBuffer : CurrentLanguageBuffer; | ||
var selectedSpans = selection.SelectedSpans; | ||
|
||
foreach (var selectedSpan in selectedSpans) | ||
{ | ||
var spans = TextView.BufferGraph.MapDownToBuffer(selectedSpan, SpanTrackingMode.EdgeInclusive, editableBuffer); | ||
if (spans.Count > 0) | ||
{ | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
private bool ReduceBoxSelectionToEditableBox(bool isDelete = true) | ||
{ | ||
Debug.Assert(TextView.Selection.Mode == TextSelectionMode.Box); | ||
|
@@ -2202,8 +2266,7 @@ private bool ReduceBoxSelectionToEditableBox(ref VirtualSnapshotPoint selectionT | |
if (selectionLeftColumn > maxPromptLength || maxPromptLength == minPromptLength) | ||
{ | ||
selectionTopLine = editableLine; | ||
selectionLeftColumn = Math.Max(selectionLeftColumn, maxPromptLength); | ||
result = false; | ||
selectionLeftColumn = Math.Max(selectionLeftColumn, maxPromptLength); | ||
} | ||
} | ||
else | ||
|
@@ -2261,16 +2324,24 @@ private void MeasurePrompts(int startLine, int endLine, out int minPromptLength, | |
/// <summary>Implements <see cref="IInteractiveWindowOperations.Cut"/>.</summary> | ||
public void Cut() | ||
{ | ||
if (TextView.Selection.IsEmpty) | ||
if (!TextView.Selection.IsEmpty) | ||
{ | ||
CutOrDeleteCurrentLine(isCut: true); | ||
if (CutOrDeleteSelection(isCut: true)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
return; | ||
} | ||
else | ||
|
||
var caretPosition = TextView.Caret.Position.BufferPosition; | ||
|
||
// don't cut and move caret if it's in readonly buffer (except in active prompt) | ||
if (MapToEditableBuffer(caretPosition) != null || | ||
IsInActivePrompt(caretPosition)) | ||
{ | ||
CutOrDeleteSelection(isCut: true); | ||
CutOrDeleteCurrentLine(isCut: true); | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
|
||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
|
||
private void CutOrDeleteCurrentLine(bool isCut) | ||
|
@@ -2285,15 +2356,26 @@ private void CutOrDeleteCurrentLine(bool isCut) | |
} | ||
|
||
/// <summary> | ||
/// Deletes currently selected text from the language buffer and optionally saves it to the clipboard. | ||
/// </summary> | ||
private void CutOrDeleteSelection(bool isCut) | ||
/// If any of currently selected text is editable, then deletes editable selection, optionally saves it | ||
/// to the clipboard. Otherwise do nothing (and preserve selection). | ||
/// </summary> | ||
private bool CutOrDeleteSelection(bool isCut) | ||
{ | ||
CutOrDelete(TextView.Selection.SelectedSpans, isCut); | ||
|
||
// if the selection spans over prompts the prompts remain selected, so clear manually: | ||
TextView.Selection.Clear(); | ||
} | ||
if (!TextView.Selection.IsEmpty) | ||
{ | ||
bool isEditable = TextView.Selection.Mode == TextSelectionMode.Stream ? | ||
IsStreamSelectionInEditableBuffer(TextView.Selection) : | ||
ReduceBoxSelectionToEditableBox(); | ||
if (isEditable) | ||
{ | ||
CutOrDelete(TextView.Selection.SelectedSpans, isCut); | ||
// if the selection spans over prompts the prompts remain selected, so clear manually: | ||
TextView.Selection.Clear(); | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
private void CutOrDelete(IEnumerable<SnapshotSpan> projectionSpans, bool isCut) | ||
{ | ||
|
@@ -2464,31 +2546,41 @@ public bool Backspace() | |
{ | ||
if (TextView.Selection.Mode == TextSelectionMode.Stream || ReduceBoxSelectionToEditableBox()) | ||
{ | ||
CutOrDeleteSelection(isCut: false); | ||
MoveCaretToClosestEditableBuffer(); | ||
handled = true; | ||
if (CutOrDeleteSelection(isCut: false)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
handled = true; | ||
} | ||
} | ||
} | ||
else if (TextView.Caret.Position.VirtualSpaces == 0) | ||
{ | ||
DeletePreviousCharacter(); | ||
handled = true; | ||
if (IsInActivePrompt(TextView.Caret.Position.BufferPosition)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
if (DeletePreviousCharacter()) | ||
{ | ||
handled = true; | ||
} | ||
} | ||
|
||
return handled; | ||
} | ||
|
||
/// <summary> | ||
/// Deletes characters preceding the current caret position in the current language buffer. | ||
/// | ||
/// Returns true if the previous character was deleted | ||
/// </summary> | ||
private void DeletePreviousCharacter() | ||
private bool DeletePreviousCharacter() | ||
{ | ||
SnapshotPoint? point = MapToEditableBuffer(TextView.Caret.Position.BufferPosition); | ||
|
||
// We are not in an editable buffer, or we are at the start of the buffer, nothing to delete. | ||
if (point == null || point.Value == 0) | ||
{ | ||
return; | ||
return false; | ||
} | ||
|
||
var line = point.Value.GetContainingLine(); | ||
|
@@ -2506,6 +2598,7 @@ private void DeletePreviousCharacter() | |
point.Value.Snapshot.TextBuffer.Delete(new Span(point.Value.Position - characterSize, characterSize)); | ||
|
||
ScrollToCaret(); | ||
return true; | ||
} | ||
|
||
/// <summary> | ||
|
@@ -2624,8 +2717,25 @@ private bool HandlePostServicesReturn(bool trySubmit) | |
return false; | ||
} | ||
|
||
if (!TextView.Selection.IsEmpty) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comments as in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
{ | ||
if (CutOrDeleteSelection(isCut: false)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
} | ||
else if (IsInActivePrompt(TextView.Caret.Position.BufferPosition)) | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
|
||
// handle "RETURN" command that is not handled by either editor or service | ||
var langCaret = GetPositionInLanguageBuffer(TextView.Caret.Position.BufferPosition); | ||
|
||
if (langCaret != null) | ||
{ | ||
int caretPosition = langCaret.Value.Position; | ||
|
@@ -2634,20 +2744,16 @@ private bool HandlePostServicesReturn(bool trySubmit) | |
if (trySubmit && caretPosition >= CurrentLanguageBuffer.CurrentSnapshot.Length && CanExecuteActiveCode()) | ||
{ | ||
var dummy = SubmitAsync(); | ||
return true; | ||
} | ||
|
||
// insert new line (triggers secondary prompt injection in buffer changed event): | ||
CurrentLanguageBuffer.Insert(caretPosition, _lineBreakString); | ||
IndentCurrentLine(TextView.Caret.Position.BufferPosition); | ||
ScrollToCaret(); | ||
|
||
else | ||
{ | ||
// insert new line (triggers secondary prompt injection in buffer changed event): | ||
CurrentLanguageBuffer.Insert(caretPosition, _lineBreakString); | ||
IndentCurrentLine(TextView.Caret.Position.BufferPosition); | ||
ScrollToCaret(); | ||
} | ||
return true; | ||
} | ||
else | ||
{ | ||
MoveCaretToClosestEditableBuffer(); | ||
} | ||
|
||
return false; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Else return false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.