Skip to content
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

Issue 406 #555

Merged
merged 7 commits into from
Jul 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1986,6 +2042,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
* vspython@microsoft.com. 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
* vspython@microsoft.com. 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