提交 7797531d 编写于 作者: C Charles Stoner

Use readonly regions

上级 b8b647d0
......@@ -34,6 +34,34 @@ namespace Microsoft.VisualStudio.InteractiveWindow
/// </summary>
internal partial class InteractiveWindow : IInteractiveWindow, IInteractiveWindowOperations2
{
private enum ReplSpanKind
{
/// <summary>
/// Primary, secondary, or standard input prompt.
/// </summary>
Prompt,
/// <summary>
/// Line break inserted at end of output.
/// </summary>
LineBreak,
/// <summary>
/// The span represents output from the program (standard output).
/// </summary>
Output,
/// <summary>
/// The span represents code inputted after a prompt or secondary prompt.
/// </summary>
Language,
/// <summary>
/// The span represents the input for a standard input (non code input).
/// </summary>
StandardInput,
}
private bool _adornmentToMinimize;
private readonly IWpfTextView _textView;
......@@ -61,10 +89,7 @@ internal partial class InteractiveWindow : IInteractiveWindow, IInteractiveWindo
private readonly ITextBuffer _outputBuffer;
private readonly IProjectionBuffer _projectionBuffer;
private readonly ITextBuffer _standardInputBuffer;
private readonly ITextBuffer _promptBuffer;
private readonly ITextBuffer _secondaryPromptBuffer;
private readonly ITextBuffer _standardInputPromptBuffer;
private readonly ITextBuffer _outputLineBreakBuffer;
private readonly IContentType _inertType;
private ITextBuffer _currentLanguageBuffer;
private string _historySearch;
......@@ -463,12 +488,13 @@ void IInteractiveWindowOperations.SelectAll()
// Grab the span following the prompt (either language or standard input).
var projectionSpan = sourceSpans[promptIndex + 1];
var inputSnapshot = projectionSpan.Snapshot;
var kind = GetSpanKind(projectionSpan);
Debug.Assert(GetSpanKind(inputSnapshot) == ReplSpanKind.Language || GetSpanKind(inputSnapshot) == ReplSpanKind.StandardInput);
Debug.Assert(kind == ReplSpanKind.Language || kind == ReplSpanKind.StandardInput);
// Language input block is a projection of the entire snapshot;
// std input block is a projection of a single span:
SnapshotPoint inputBufferEnd = GetSpanKind(inputSnapshot) == ReplSpanKind.Language ?
SnapshotPoint inputBufferEnd = (kind == ReplSpanKind.Language) ?
new SnapshotPoint(inputSnapshot, inputSnapshot.Length) :
projectionSpan.End;
......@@ -504,7 +530,7 @@ void IInteractiveWindowOperations.SelectAll()
int nextPromptIndex = -1;
for (int i = promptIndex + 1; i < sourceSpans.Count; i++)
{
if (IsPrompt(sourceSpans[i].Snapshot))
if (IsPrompt(sourceSpans[i]))
{
nextPromptIndex = i;
break;
......@@ -521,7 +547,7 @@ void IInteractiveWindowOperations.SelectAll()
}
var lastSpanBeforeNextPrompt = sourceSpans[nextPromptIndex - 1];
Debug.Assert(GetSpanKind(lastSpanBeforeNextPrompt.Snapshot) == ReplSpanKind.Output);
Debug.Assert(GetSpanKind(lastSpanBeforeNextPrompt) == ReplSpanKind.Output);
// select all text in between the language buffer and the next prompt:
return new SnapshotSpan(
......@@ -558,7 +584,7 @@ private void IndentCurrentLine(SnapshotPoint caretPosition)
var sourceSpans = GetSourceSpans(caretPosition.Snapshot);
var promptIndex = GetPromptIndexForPoint(sourceSpans, caretPosition);
var promptSpan = sourceSpans[promptIndex];
Debug.Assert(IsPrompt(promptSpan.Snapshot));
Debug.Assert(IsPrompt(promptSpan));
int promptLength = promptSpan.Length;
Debug.Assert(promptLength == 2 || promptLength == 0); // Not required, just expected.
var adjustedIndentationValue = indentation.GetValueOrDefault() - promptLength;
......@@ -790,19 +816,23 @@ private StringBuilder GetTextWithoutPrompts(StringBuilder builder, SnapshotSpan
{
continue;
}
var sourceSnapshot = sourceSpan.Snapshot;
var mappedSpans = _textView.BufferGraph.MapDownToBuffer(span, SpanTrackingMode.EdgeExclusive, sourceSnapshot.TextBuffer);
if (mappedSpans.Count == 0)
{
break;
}
if (!IsPrompt(sourceSnapshot))
if (!IsPrompt(sourceSpan))
{
var sourceSnapshot = sourceSpan.Snapshot;
var mappedSpans = _textView.BufferGraph.MapDownToBuffer(span, SpanTrackingMode.EdgeExclusive, sourceSnapshot.TextBuffer);
bool added = false;
foreach (var mappedSpan in mappedSpans)
{
var intersection = sourceSpan.Span.Intersection(mappedSpan);
Debug.Assert(intersection.HasValue);
builder.Append(sourceSnapshot.GetText(intersection.Value));
if (intersection.HasValue)
{
builder.Append(sourceSnapshot.GetText(intersection.Value));
added = true;
}
}
if (!added)
{
break;
}
}
}
......@@ -1288,36 +1318,13 @@ private void SetActiveCodeToHistory(History.Entry entry)
private void ClearInput()
{
var sourceSpans = _projectionBuffer.CurrentSnapshot.GetSourceSpans();
Debug.Assert(sourceSpans.Count > 0);
// Finds the last primary prompt (standard input or code input).
// Removes all spans following the primary prompt from the projection buffer.
int i = sourceSpans.Count - 1;
while (i >= 0)
if (_stdInputStart != null)
{
var sourceSnapshot = sourceSpans[i].Snapshot;
if (GetSpanKind(sourceSnapshot) == ReplSpanKind.Prompt || GetSpanKind(sourceSnapshot) == ReplSpanKind.StandardInputPrompt)
{
Debug.Assert(i != sourceSpans.Count - 1);
break;
}
i--;
_standardInputBuffer.Delete(Span.FromBounds(_stdInputStart.Value, _standardInputBuffer.CurrentSnapshot.Length));
}
if (i >= 0)
else
{
var sourceSnapshot = sourceSpans[i].Snapshot;
if (GetSpanKind(sourceSnapshot) != ReplSpanKind.StandardInputPrompt)
{
_currentLanguageBuffer.Delete(new Span(0, _currentLanguageBuffer.CurrentSnapshot.Length));
}
else
{
Debug.Assert(_stdInputStart != null);
_standardInputBuffer.Delete(Span.FromBounds(_stdInputStart.Value, _standardInputBuffer.CurrentSnapshot.Length));
}
_currentLanguageBuffer.Delete(new Span(0, _currentLanguageBuffer.CurrentSnapshot.Length));
}
}
......@@ -1340,7 +1347,7 @@ TextReader IInteractiveWindow.ReadStandardInput()
{
var snapshot = _projectionBuffer.CurrentSnapshot;
var spanCount = snapshot.SpanCount;
if (spanCount > 0 && IsLanguage(snapshot.GetSourceSpan(spanCount - 1).Snapshot))
if (spanCount > 0 && GetSpanKind(snapshot.GetSourceSpan(spanCount - 1)) == ReplSpanKind.Language)
{
// we need to remove our input prompt.
uiOnly.RemoveLastInputPrompt();
......@@ -1420,9 +1427,9 @@ private void SubmitStandardInput()
_inputEvent.Set();
}
#endregion
#endregion
#region Output
#region Output
Span IInteractiveWindow.Write(string text)
{
......@@ -1475,9 +1482,9 @@ private void OnAdornmentLoaded(object source, EventArgs e)
Caret.EnsureVisible();
}
#endregion
#endregion
#region Execution
#region Execution
private bool CanExecuteActiveCode()
{
......@@ -1503,35 +1510,23 @@ private bool CanExecuteActiveCode()
return _evaluator.CanExecuteCode(input);
}
#endregion
#endregion
#region Buffers, Spans and Prompts
private ITrackingSpan CreateStandardInputPrompt()
#region Buffers, Spans and Prompts
private object CreateStandardInputPrompt()
{
return CreateTrackingSpan(_standardInputPromptBuffer, string.Empty);
return string.Empty;
}
private ITrackingSpan CreatePrimaryPrompt()
private object CreatePrimaryPrompt()
{
return CreateTrackingSpan(_promptBuffer, _evaluator.GetPrompt());
return _evaluator.GetPrompt();
}
private ITrackingSpan CreateSecondaryPrompt()
private object CreateSecondaryPrompt()
{
// TODO (crwilcox) format prompt used to get a blank here but now gets "> " from get prompt.
return CreateTrackingSpan(_secondaryPromptBuffer, _evaluator.GetPrompt());
}
private static ITrackingSpan CreateTrackingSpan(ITextBuffer buffer, string textToAppend)
{
using (var edit = buffer.CreateEdit())
{
var snapshot = edit.Snapshot;
int offset = snapshot.Length;
edit.Insert(offset, textToAppend);
snapshot = edit.Apply();
return new CustomTrackingSpan(snapshot, new Span(offset, snapshot.Length - offset), PointTrackingMode.Negative, PointTrackingMode.Negative);
}
return _evaluator.GetPrompt();
}
/// <summary>
......@@ -1545,15 +1540,15 @@ private void MeasurePrompts(int startLine, int endLine, out int minPromptLength,
var sourceSpans = projectionSnapshot.GetSourceSpans();
var promptSpanIndex = GetProjectionSpanIndexFromEditableBufferPosition(projectionSnapshot, sourceSpans.Count, startLine) - 1;
var promptSpan = sourceSpans[promptSpanIndex];
Debug.Assert(IsPrompt(promptSpan.Snapshot));
Debug.Assert(IsPrompt(promptSpan));
minPromptLength = maxPromptLength = promptSpan.Length;
}
private ReplSpanKind GetSpanKind(ITextSnapshot snapshot)
private ReplSpanKind GetSpanKind(SnapshotSpan span)
{
var textBuffer = snapshot.TextBuffer;
if ((textBuffer == _outputBuffer) || (textBuffer == _outputLineBreakBuffer))
var textBuffer = span.Snapshot.TextBuffer;
if (textBuffer == _outputBuffer)
{
return ReplSpanKind.Output;
}
......@@ -1561,30 +1556,18 @@ private ReplSpanKind GetSpanKind(ITextSnapshot snapshot)
{
return ReplSpanKind.StandardInput;
}
if (textBuffer == _promptBuffer)
{
return ReplSpanKind.Prompt;
}
if (textBuffer == _secondaryPromptBuffer)
{
return ReplSpanKind.SecondaryPrompt;
}
if (textBuffer == _standardInputPromptBuffer)
if (textBuffer.ContentType == _inertType)
{
return ReplSpanKind.StandardInputPrompt;
return (span.Length == _lineBreakString.Length) && string.Equals(span.GetText(), _lineBreakString) ?
ReplSpanKind.LineBreak :
ReplSpanKind.Prompt;
}
return ReplSpanKind.Language;
}
private bool IsPrompt(ITextSnapshot snapshot)
{
var kind = GetSpanKind(snapshot);
return (kind == ReplSpanKind.Prompt) || (kind == ReplSpanKind.SecondaryPrompt) || (kind == ReplSpanKind.StandardInputPrompt);
}
private bool IsLanguage(ITextSnapshot snapshot)
private bool IsPrompt(SnapshotSpan span)
{
return GetSpanKind(snapshot) == ReplSpanKind.Language;
return GetSpanKind(span) == ReplSpanKind.Prompt;
}
private static ReadOnlyCollection<SnapshotSpan> GetSourceSpans(ITextSnapshot snapshot)
......@@ -1600,7 +1583,7 @@ private int GetPromptIndexForPoint(ReadOnlyCollection<SnapshotSpan> sourceSpans,
index--;
}
// Find the nearest preceding prompt.
while (!IsPrompt(sourceSpans[index].Snapshot))
while (!IsPrompt(sourceSpans[index]))
{
index--;
}
......@@ -1708,9 +1691,9 @@ private struct SpanRangeEdit
{
public readonly int Start;
public readonly int End;
public readonly ITrackingSpan[] Replacement;
public readonly object[] Replacement;
public SpanRangeEdit(int start, int count, ITrackingSpan[] replacement)
public SpanRangeEdit(int start, int count, object[] replacement)
{
Start = start;
End = start + count;
......@@ -1818,7 +1801,7 @@ private void ProjectionBufferChanged(object sender, TextContentChangedEventArgs
int i = 0;
int lineBreakCount = newSubjectEndLineNumber - newSubjectStartLine.LineNumber;
var newSpans = new ITrackingSpan[lineBreakCount * SpansPerLineOfInput + 1];
var newSpans = new object[lineBreakCount * SpansPerLineOfInput + 1];
var subjectLine = newSubjectStartLine;
while (true)
......@@ -1868,7 +1851,7 @@ private int GetProjectionSpanIndexFromEditableBufferPosition(IProjectionSnapshot
// and ending at the end of the projection buffer, each language buffer projection is on a separate line:
// [prompt)[language)...[prompt)[language)<end of projection buffer>
int result = projectionSpansCount - (surfaceSnapshot.LineCount - surfaceLineNumber) * SpansPerLineOfInput + 1;
Debug.Assert(GetSpanKind(surfaceSnapshot.GetSourceSpan(result).Snapshot) == ReplSpanKind.Language);
Debug.Assert(GetSpanKind(surfaceSnapshot.GetSourceSpan(result)) == ReplSpanKind.Language);
return result;
}
......@@ -1911,9 +1894,14 @@ private void ReplaceProjectionSpans(ReadOnlyCollection<SnapshotSpan> oldProjecti
_projectionBuffer.ReplaceSpans(start, end - start, replacement, EditOptions.None, s_suppressPromptInjectionTag);
}
private static ITrackingSpan CreateTrackingSpan(SnapshotSpan snapshotSpan)
private object CreateTrackingSpan(SnapshotSpan snapshotSpan)
{
return new CustomTrackingSpan(snapshotSpan.Snapshot, snapshotSpan.Span, PointTrackingMode.Negative, PointTrackingMode.Negative);
var snapshot = snapshotSpan.Snapshot;
if (snapshot.ContentType == _inertType)
{
return snapshotSpan.GetText();
}
return new CustomTrackingSpan(snapshot, snapshotSpan.Span, PointTrackingMode.Negative, PointTrackingMode.Negative);
}
private ITrackingSpan CreateLanguageSpanForLine(ITextSnapshotLine languageLine)
......@@ -1936,7 +1924,7 @@ private void AppendLineNoPromptInjection(ITextBuffer buffer)
}
}
private void AppendProjectionSpans(ITrackingSpan span1, ITrackingSpan span2)
private void AppendProjectionSpans(object span1, object span2)
{
int index = _projectionBuffer.CurrentSnapshot.SpanCount;
_projectionBuffer.ReplaceSpans(index, 0, new[] { span1, span2 }, EditOptions.None, editTag: s_suppressPromptInjectionTag);
......
......@@ -108,7 +108,6 @@
<Compile Include="Output\SortedSpans.cs" />
<Compile Include="Output\ZoomableInlineAdornment.cs" />
<Compile Include="PredefinedInteractiveTextViewRoles.cs" />
<Compile Include="ReplSpanKind.cs" />
<Compile Include="SmartIndent\InteractiveSmartIndenter.cs" />
<Compile Include="SmartIndent\InteractiveSmartIndenterProvider.cs" />
<Compile Include="SmartUpDownOption.cs" />
......
......@@ -60,10 +60,7 @@ internal partial class InteractiveWindow
_outputBuffer = bufferFactory.CreateTextBuffer(replOutputContentType);
_standardInputBuffer = bufferFactory.CreateTextBuffer();
_promptBuffer = bufferFactory.CreateTextBuffer();
_secondaryPromptBuffer = bufferFactory.CreateTextBuffer();
_standardInputPromptBuffer = bufferFactory.CreateTextBuffer();
_outputLineBreakBuffer = bufferFactory.CreateTextBuffer();
_inertType = bufferFactory.InertContentType;
var projBuffer = projectionBufferFactory.CreateProjectionBuffer(
new EditResolver(this),
......@@ -217,7 +214,7 @@ public Task<ExecutionResult> ResetAsync(bool initialize)
{
var snapshot = _window._projectionBuffer.CurrentSnapshot;
var spanCount = snapshot.SpanCount;
Debug.Assert(_window.IsLanguage(snapshot.GetSourceSpan(spanCount - 1).Snapshot));
Debug.Assert(_window.GetSpanKind(snapshot.GetSourceSpan(spanCount - 1)) == ReplSpanKind.Language);
StoreUncommittedInput();
RemoveProjectionSpans(spanCount - 2, 2);
_window._currentLanguageBuffer = null;
......@@ -434,8 +431,8 @@ private void AppendInput(string text)
var snapshot = _window._projectionBuffer.CurrentSnapshot;
var spanCount = snapshot.SpanCount;
var inputSpan = snapshot.GetSourceSpan(spanCount - 1);
Debug.Assert(_window.GetSpanKind(inputSpan.Snapshot) == ReplSpanKind.Language ||
_window.GetSpanKind(inputSpan.Snapshot) == ReplSpanKind.StandardInput);
Debug.Assert(_window.GetSpanKind(inputSpan) == ReplSpanKind.Language ||
_window.GetSpanKind(inputSpan) == ReplSpanKind.StandardInput);
var buffer = inputSpan.Snapshot.TextBuffer;
var span = inputSpan.Span;
......@@ -618,10 +615,9 @@ public void NewOutputBuffer()
{
// Stop growing the current output projection span.
var sourceSpan = _window._projectionBuffer.CurrentSnapshot.GetSourceSpan(_currentOutputProjectionSpan);
var sourceSnapshot = sourceSpan.Snapshot;
Debug.Assert(_window.GetSpanKind(sourceSnapshot) == ReplSpanKind.Output);
Debug.Assert(_window.GetSpanKind(sourceSpan) == ReplSpanKind.Output);
var nonGrowingSpan = new CustomTrackingSpan(
sourceSnapshot,
sourceSpan.Snapshot,
sourceSpan.Span,
PointTrackingMode.Negative,
PointTrackingMode.Negative);
......@@ -650,7 +646,7 @@ private int AppendProjectionSpan(ITrackingSpan span)
return index;
}
private void InsertProjectionSpan(int index, ITrackingSpan span)
private void InsertProjectionSpan(int index, object span)
{
_window._projectionBuffer.ReplaceSpans(index, 0, new[] { span }, EditOptions.None, editTag: s_suppressPromptInjectionTag);
}
......@@ -674,12 +670,11 @@ internal void AppendOutput(IEnumerable<string> output, int outputLength)
{
Debug.Assert(output.Any());
// we maintain this invariant so that projections don't split "\r\n" in half
// (the editor isn't happy about it and our line counting also gets simpler):
// we maintain this invariant so that projections don't split "\r\n" in half:
Debug.Assert(!_window._outputBuffer.CurrentSnapshot.EndsWith('\r'));
var projectionSpans = _window._projectionBuffer.CurrentSnapshot.GetSourceSpans();
Debug.Assert(_window.GetSpanKind(projectionSpans[_currentOutputProjectionSpan].Snapshot) == ReplSpanKind.Output);
Debug.Assert(_window.GetSpanKind(projectionSpans[_currentOutputProjectionSpan]) == ReplSpanKind.Output);
int lineBreakProjectionSpanIndex = _currentOutputProjectionSpan + 1;
......@@ -688,26 +683,25 @@ internal void AppendOutput(IEnumerable<string> output, int outputLength)
if (lineBreakProjectionSpanIndex < projectionSpans.Count)
{
var oldSpan = projectionSpans[lineBreakProjectionSpanIndex];
hasLineBreakProjection = _window.GetSpanKind(oldSpan.Snapshot) == ReplSpanKind.Output && string.Equals(oldSpan.GetText(), _window._lineBreakString);
hasLineBreakProjection = _window.GetSpanKind(oldSpan) == ReplSpanKind.LineBreak;
}
Debug.Assert(output.Last().Last() != '\r');
bool endsWithLineBreak = output.Last().Last() == '\n';
bool insertLineBreak = !endsWithLineBreak && !hasLineBreakProjection;
bool removeLineBreak = endsWithLineBreak && hasLineBreakProjection;
// insert text to the subject buffer.
int oldBufferLength = _window._outputBuffer.CurrentSnapshot.Length;
InsertOutput(output, oldBufferLength);
if (removeLineBreak)
if (endsWithLineBreak && hasLineBreakProjection)
{
// Remove line break.
RemoveProjectionSpans(lineBreakProjectionSpanIndex, 1);
}
else if (insertLineBreak)
else if (!endsWithLineBreak && !hasLineBreakProjection)
{
InsertProjectionSpan(lineBreakProjectionSpanIndex, CreateTrackingSpan(_window._outputLineBreakBuffer, _window._lineBreakString));
// Insert line break.
InsertProjectionSpan(lineBreakProjectionSpanIndex, _window._lineBreakString);
}
// caret didn't move since last time we moved it to track output:
......@@ -826,13 +820,14 @@ private ITextBuffer GetLanguageBuffer(SnapshotPoint point)
// Grab the span following the prompt (either language or standard input).
var projectionSpan = sourceSpans[promptIndex + 1];
var inputSnapshot = projectionSpan.Snapshot;
if (_window.GetSpanKind(inputSnapshot) != ReplSpanKind.Language)
var kind = _window.GetSpanKind(projectionSpan);
if (kind != ReplSpanKind.Language)
{
Debug.Assert(_window.GetSpanKind(inputSnapshot) == ReplSpanKind.StandardInput);
Debug.Assert(kind == ReplSpanKind.StandardInput);
return null;
}
var inputSnapshot = projectionSpan.Snapshot;
var inputBuffer = inputSnapshot.TextBuffer;
var projectedSpans = _window._textView.BufferGraph.MapUpToBuffer(
......@@ -914,7 +909,7 @@ public int IndexOfLastStandardInputSpan(ReadOnlyCollection<SnapshotSpan> sourceS
{
for (int i = sourceSpans.Count - 1; i >= 0; i--)
{
if (_window.GetSpanKind(sourceSpans[i].Snapshot) == ReplSpanKind.StandardInput)
if (_window.GetSpanKind(sourceSpans[i]) == ReplSpanKind.StandardInput)
{
return i;
}
......@@ -927,7 +922,7 @@ public void RemoveLastInputPrompt()
{
var snapshot = _window._projectionBuffer.CurrentSnapshot;
var spanCount = snapshot.SpanCount;
Debug.Assert(_window.IsPrompt(snapshot.GetSourceSpan(spanCount - SpansPerLineOfInput).Snapshot));
Debug.Assert(_window.IsPrompt(snapshot.GetSourceSpan(spanCount - SpansPerLineOfInput)));
// projection buffer update must be the last operation as it might trigger event that accesses prompt line mapping:
RemoveProjectionSpans(spanCount - SpansPerLineOfInput, SpansPerLineOfInput);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.InteractiveWindow
{
internal enum ReplSpanKind
{
None,
/// <summary>
/// The span represents output from the program (standard output)
/// </summary>
Output,
/// <summary>
/// The span represents a prompt for input of code.
/// </summary>
Prompt,
/// <summary>
/// The span represents a secondary prompt for more code.
/// </summary>
SecondaryPrompt,
/// <summary>
/// The span represents code inputted after a prompt or secondary prompt.
/// </summary>
Language,
/// <summary>
/// The span represents the prompt for input for standard input (non code input)
/// </summary>
StandardInputPrompt,
/// <summary>
/// The span represents the input for a standard input (non code input)
/// </summary>
StandardInput,
}
}
......@@ -573,8 +573,23 @@ public void ReformatBraces()
new TextChange(5, 1, " "),
new TextChange(7, 1, "\r\n"));
// Text from language buffer.
var actualText = snapshot.GetText();
Assert.Equal("{\r\n {\r\n }\r\n}", actualText);
// Text including prompts.
buffer = Window.TextView.TextBuffer;
snapshot = buffer.CurrentSnapshot;
actualText = snapshot.GetText();
Assert.Equal("> {\r\n> {\r\n> }\r\n> }", actualText);
// Prompts should be read-only.
var regions = buffer.GetReadOnlyExtents(new Span(0, snapshot.Length));
AssertEx.SetEqual(regions,
new Span(0, 2),
new Span(5, 2),
new Span(14, 2),
new Span(23, 2));
}
[Fact]
......@@ -721,6 +736,25 @@ private void CopyNoSelectionAndVerify(int start, int end, string expectedText, s
}
}
[Fact]
public void CancelMultiLineInput()
{
ApplyChanges(
Window.CurrentLanguageBuffer,
new TextChange(0, 0, "{\r\n {\r\n }\r\n}"));
// Text including prompts.
var buffer = Window.TextView.TextBuffer;
var snapshot = buffer.CurrentSnapshot;
Assert.Equal("> {\r\n> {\r\n> }\r\n> }", snapshot.GetText());
Task.Run(() => Window.Operations.Cancel()).PumpingWait();
// Text after cancel.
snapshot = buffer.CurrentSnapshot;
Assert.Equal("> ", snapshot.GetText());
}
private void Submit(string submission, string output)
{
Task.Run(() => Window.SubmitAsync(new[] { submission })).PumpingWait();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册