Skip to content

Commit

Permalink
Merge pull request #555 from zooba/issue-406
Browse files Browse the repository at this point in the history
Issue 406
  • Loading branch information
zooba committed Jul 8, 2015
2 parents 00a8d07 + 9228a84 commit 586d9ac
Show file tree
Hide file tree
Showing 8 changed files with 607 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Python/Product/PythonTools/PythonTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@
<Link>IEnumerableExtensions.cs</Link>
</Compile>
<Compile Include="PythonTools\Repl\IMultipleScopeEvaluator.cs" />
<Compile Include="PythonTools\Repl\InlineReplAdornment.cs" />
<Compile Include="PythonTools\Repl\InlineReplAdornmentManager.cs" />
<Compile Include="PythonTools\Repl\InteractiveWindowCommands.cs" />
<Compile Include="PythonTools\Repl\InteractiveWindowProvider.cs" />
<Compile Include="IPythonToolsToolWindowService.cs" />
Expand All @@ -310,6 +312,8 @@
<Compile Include="PythonTools\Intellisense\PythonSuggestedImportAction.cs" />
<Compile Include="PythonTools\Project\IPythonProjectLaunchProperties.cs" />
<Compile Include="PythonTools\Project\PythonProjectLaunchProperties.cs" />
<Compile Include="PythonTools\Repl\ResizingAdorner.cs" />
<Compile Include="PythonTools\Repl\ZoomableInlineAdornment.cs" />
<Compile Include="PythonTools\SurveyNewsService.cs" />
<Compile Include="PythonTools\Options\GlobalInterpreterOptions.cs" />
<Compile Include="PythonTools\Options\GeneralOptions.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
using Microsoft.VisualStudioTools;
using Microsoft.VisualStudioTools.Project;
using SR = Microsoft.PythonTools.Project.SR;
using System.Windows.Media;
using System.Windows.Markup;

#if DEV14_OR_LATER
using IReplEvaluator = Microsoft.VisualStudio.InteractiveWindow.IInteractiveEvaluator;
Expand Down Expand Up @@ -361,6 +363,7 @@ private void OutputThread() {
case "RDLN": HandleReadLine(); break;
case "DETC": HandleDebuggerDetach(); break;
case "DPNG": HandleDisplayPng(); break;
case "DXAM": HandleDisplayXaml(); break;
case "EXIT":
// REPL has exited
_stream.Write(ExitCommandBytes);
Expand Down Expand Up @@ -439,6 +442,40 @@ private void HandleDisplayPng() {
DisplayImage(buffer);
}

private void HandleDisplayXaml() {
Debug.Assert(Monitor.IsEntered(_streamLock));

int len = _stream.ReadInt32();
byte[] buffer = new byte[len];
if (len != 0) {
int bytesRead = 0;
do {
bytesRead += _stream.Read(buffer, bytesRead, len - bytesRead);
} while (bytesRead != len);
}

using (new StreamUnlock(this)) {
((System.Windows.UIElement)Window.TextView).Dispatcher.BeginInvoke((Action)(() => {
DisplayXaml(buffer);
}));
}
}

private void DisplayXaml(byte[] buffer) {
try {
var fe = (FrameworkElement)XamlReader.Load(new MemoryStream(buffer));
if (fe != null) {
WriteFrameworkElement(fe, fe.DesiredSize);
}
} catch (Exception ex) {
if (ex.IsCriticalException()) {
throw;
}
Window.WriteError(ex.ToString());
return;
}
}

internal string DoDebugAttach() {
if (_eval._attached) {
return "Cannot attach to debugger when already attached.";
Expand Down Expand Up @@ -560,21 +597,40 @@ private void DisplayImage(byte[] bytes) {
using (new StreamUnlock(this)) {
((System.Windows.UIElement)Window.TextView).Dispatcher.BeginInvoke((Action)(() => {
try {
var imageSrc = new BitmapImage();
imageSrc.BeginInit();
imageSrc.StreamSource = new MemoryStream(bytes);
imageSrc.EndInit();
#if DEV14_OR_LATER
Window.Write(new Image() { Source = imageSrc });
#else
Window.WriteOutput(new Image() { Source = imageSrc });
#endif
WriteImage(bytes);
} catch (IOException) {
}
}));
}
}

private void WriteImage(byte[] bytes) {
var imageSrc = new BitmapImage();
imageSrc.BeginInit();
imageSrc.StreamSource = new MemoryStream(bytes);
imageSrc.EndInit();

var img = new Image {
Source = imageSrc,
Stretch = Stretch.Uniform,
StretchDirection = StretchDirection.Both
};
var control = new Border {
Child = img,
Background = Brushes.White
};

WriteFrameworkElement(control, new Size(imageSrc.PixelWidth, imageSrc.PixelHeight));
}

private void WriteFrameworkElement(UIElement control, Size desiredSize) {
Window.FlushOutput();

var caretPos = Window.TextView.Caret.Position.BufferPosition;
var manager = InlineReplAdornmentProvider.GetManager(Window.TextView);
manager.AddAdornment(new ZoomableInlineAdornment(control, Window.TextView, desiredSize), caretPos);
}

private void HandleModuleList() {
Debug.Assert(Monitor.IsEntered(_streamLock));

Expand Down Expand Up @@ -1992,6 +2048,12 @@ public static void UseInterpreterPrompts(this IReplWindow window) {
public static void SetSmartUpDown(this IReplWindow window, bool setting) {
window.SetOptionValue(ReplOptions.UseSmartUpDown, setting);
}

public static void FlushOutput(this IReplWindow window) {
// hacky way to force flushing of the output buffer as there is no API for it.
window.SetOptionValue(ReplOptions.SupportAnsiColors, window.GetOptionValue(ReplOptions.SupportAnsiColors));

}
#endif

}
Expand Down
55 changes: 55 additions & 0 deletions Python/Product/PythonTools/PythonTools/Repl/InlineReplAdornment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, please send an email to
* [email protected]. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/

using System.ComponentModel.Composition;
using System.Windows;
#if DEV14_OR_LATER
using Microsoft.VisualStudio.InteractiveWindow;
#else
using Microsoft.VisualStudio.Repl;
#endif
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;

namespace Microsoft.PythonTools.Repl {
[Export(typeof(IViewTaggerProvider))]
[TagType(typeof(IntraTextAdornmentTag))]
#if DEV14_OR_LATER
[ContentType(PredefinedInteractiveContentTypes.InteractiveContentTypeName)]
#else
[ContentType(ReplConstants.ReplContentTypeName)]
#endif
internal class InlineReplAdornmentProvider : IViewTaggerProvider {
public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag {
if (buffer == null || textView == null || typeof(T) != typeof(IntraTextAdornmentTag)) {
return null;
}

return (ITagger<T>)textView.Properties.GetOrCreateSingletonProperty<InlineReplAdornmentManager>(
typeof(InlineReplAdornmentManager),
() => new InlineReplAdornmentManager(textView)
);
}

internal static InlineReplAdornmentManager GetManager(ITextView view) {
InlineReplAdornmentManager result;
if (!view.Properties.TryGetProperty<InlineReplAdornmentManager>(typeof(InlineReplAdornmentManager), out result)) {
return null;
}
return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, please send an email to
* [email protected]. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;

namespace Microsoft.PythonTools.Repl {
class InlineReplAdornmentManager : ITagger<IntraTextAdornmentTag> {
private readonly ITextView _textView;
private readonly List<Tuple<SnapshotPoint, UIElement>> _tags;
private readonly Dispatcher _dispatcher;

internal InlineReplAdornmentManager(ITextView textView) {
_textView = textView;
_tags = new List<Tuple<SnapshotPoint, UIElement>>();
_dispatcher = Dispatcher.CurrentDispatcher;
textView.TextBuffer.Changed += TextBuffer_Changed;
}

void TextBuffer_Changed(object sender, TextContentChangedEventArgs e) {
if (e.After.Length == 0) {
// screen was cleared...
RemoveAll();
}
}

public IEnumerable<ITagSpan<IntraTextAdornmentTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
var result = new List<TagSpan<IntraTextAdornmentTag>>();
for (int i = 0; i < _tags.Count; i++) {
if (_tags[i].Item1.Snapshot != _textView.TextSnapshot) {
// update to the latest snapshot
_tags[i] = new Tuple<SnapshotPoint, UIElement>(
_tags[i].Item1.TranslateTo(_textView.TextSnapshot, PointTrackingMode.Negative),
_tags[i].Item2
);
}

var span = new SnapshotSpan(_textView.TextSnapshot, _tags[i].Item1, 0);
bool intersects = false;
foreach (var applicableSpan in spans) {
if (applicableSpan.TranslateTo(_textView.TextSnapshot, SpanTrackingMode.EdgeInclusive).IntersectsWith(span)) {
intersects = true;
break;
}
}
if (!intersects) {
continue;
}
var tag = new IntraTextAdornmentTag(_tags[i].Item2, null);
result.Add(new TagSpan<IntraTextAdornmentTag>(span, tag));
}
return result;
}

public void AddAdornment(UIElement uiElement, SnapshotPoint targetLoc) {
if (Dispatcher.CurrentDispatcher != _dispatcher) {
_dispatcher.BeginInvoke(new Action(() => AddAdornment(uiElement, targetLoc)));
return;
}
var targetLine = targetLoc.GetContainingLine();
_tags.Add(new Tuple<SnapshotPoint, UIElement>(targetLoc, uiElement));
var handler = TagsChanged;
if (handler != null) {
var span = new SnapshotSpan(_textView.TextSnapshot, targetLine.Start, targetLine.LengthIncludingLineBreak);
var args = new SnapshotSpanEventArgs(span);
handler(this, args);
}
}

public IList<Tuple<SnapshotPoint, UIElement>> Adornments {
get { return _tags; }
}

public void RemoveAll() {
_tags.Clear();
}

public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
}
}
Loading

0 comments on commit 586d9ac

Please sign in to comment.