PageRenderTime 15ms CodeModel.GetById 1ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/Tools/IronStudio/IronStudioCore/IronStudioCore/Repl/ReplPrompt.cs

#
C# | 139 lines | 91 code | 16 blank | 32 comment | 5 complexity | 425ef92d0a5e6701dbe675061a48d2d8 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the Apache License, Version 2.0, please send an email to 
  8 * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 * ***************************************************************************/
 14
 15using System;
 16using System.Collections.Generic;
 17using System.ComponentModel.Composition;
 18using System.Windows;
 19using System.Windows.Controls;
 20using System.Windows.Media;
 21using Microsoft.Scripting.Utils;
 22using Microsoft.VisualStudio.Text;
 23using Microsoft.VisualStudio.Text.Editor;
 24using Microsoft.VisualStudio.Text.Formatting;
 25using Microsoft.VisualStudio.Text.Tagging;
 26using Microsoft.VisualStudio.Utilities;
 27
 28namespace Microsoft.IronStudio.Core.Repl {
 29    /// <summary>
 30    /// Any <see cref="ITextBuffer"/> with content type <see cref="CoreConstants.DlrContentTypeName"/>, role <see cref="CoreConstants.ReplTextViewRole"/> 
 31    /// and property <see cref="IReplPromptProvider"/> gets prompt glyphs in its glyph margin.
 32    /// </summary>
 33    public interface IReplPromptProvider {
 34        /// <summary>
 35        /// The prompt text to display in the margin.
 36        /// </summary>
 37        string/*!*/ Prompt { get; }
 38
 39        /// <summary>
 40        /// The control that hosts the text view.
 41        /// </summary>
 42        Control/*!*/ HostControl { get; }
 43
 44        /// <summary>
 45        /// Should we draw a prompt glyph for given line.
 46        /// </summary>
 47        bool HasPromptForLine(ITextSnapshot/*!*/ snapshot, int lineNumber);
 48
 49        /// <summary>
 50        /// Notifies glyph margin that prompt glyph(s) need to be updated.
 51        /// </summary>
 52        event Action<SnapshotSpan> PromptChanged;
 53    }
 54
 55    /// <summary>
 56    /// Implements prompt glyphs in a GlyphMargin. 
 57    /// </summary>
 58    internal static class ReplPrompt {
 59        internal const string GlyphName = "ReplPromptGlyph";
 60
 61        internal sealed class ReplGlyphTag : IGlyphTag {
 62            internal static readonly ReplGlyphTag Instance = new ReplGlyphTag();
 63        }
 64
 65        internal sealed class Tagger : ITagger<ReplGlyphTag> {
 66            private readonly IReplPromptProvider/*!*/ _promptProvider;
 67
 68            public Tagger(IReplPromptProvider/*!*/ promptProvider) {
 69                Assert.NotNull(promptProvider);
 70                _promptProvider = promptProvider;
 71                _promptProvider.PromptChanged += new Action<SnapshotSpan>((span) => {
 72                    var tagsChanged = TagsChanged;
 73                    if (tagsChanged != null) {
 74                        tagsChanged(this, new SnapshotSpanEventArgs(span));
 75                    }
 76                });
 77            }
 78
 79            public IEnumerable<ITagSpan<ReplGlyphTag>>/*!*/ GetTags(NormalizedSnapshotSpanCollection/*!*/ spans) {
 80                foreach (SnapshotSpan span in spans) {
 81                    if (_promptProvider.HasPromptForLine(span.Snapshot, span.Start.GetContainingLine().LineNumber)) {
 82                        yield return new TagSpan<ReplGlyphTag>(span, ReplGlyphTag.Instance);
 83                    }
 84                }
 85            }
 86
 87            public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
 88        }
 89
 90        [Export(typeof(ITaggerProvider))]
 91        [TagType(typeof(ReplGlyphTag))]
 92        [ContentType(CoreConstants.DlrContentTypeName)]
 93        [TextViewRole(CoreConstants.ReplTextViewRole)]
 94        internal sealed class TaggerProvider : ITaggerProvider {
 95            public ITagger<T> CreateTagger<T>(ITextBuffer/*!*/ buffer) where T : ITag {
 96                IReplPromptProvider promptProvider;
 97                if (buffer.Properties.TryGetProperty(typeof(IReplPromptProvider), out promptProvider)) {
 98                    return (ITagger<T>)(object)new Tagger(promptProvider);
 99                }
100                return null;
101            }
102        }
103
104        internal sealed class GlyphFactory : IGlyphFactory {
105            private readonly IReplPromptProvider/*!*/ _promptProvider;
106            private static readonly FontFamily _Consolas = new FontFamily("Consolas");
107
108            public GlyphFactory(IReplPromptProvider/*!*/ promptProvider) {
109                Assert.NotNull(promptProvider);
110                _promptProvider = promptProvider;
111            }
112
113            public UIElement/*!*/ GenerateGlyph(IWpfTextViewLine/*!*/ line, IGlyphTag tag) {
114                TextBlock block = new TextBlock();
115                block.Text = _promptProvider.Prompt;
116                block.Foreground = _promptProvider.HostControl.Foreground;
117                block.FontSize = _promptProvider.HostControl.FontSize;
118                block.FontFamily = _Consolas; // TODO: get the font family from the editor?
119                return block;
120            }
121        }
122
123        [Export(typeof(IGlyphFactoryProvider))]
124        [Name(GlyphName)]
125        [Order(After = "VsTextMarker")]
126        [TagType(typeof(ReplGlyphTag))]
127        [ContentType(CoreConstants.DlrContentTypeName)]
128        [TextViewRole(CoreConstants.ReplTextViewRole)]
129        internal sealed class GlyphFactoryProvider : IGlyphFactoryProvider {
130            public IGlyphFactory GetGlyphFactory(IWpfTextView/*!*/ view, IWpfTextViewMargin/*!*/ margin) {
131                IReplPromptProvider promptProvider;
132                if (view.TextBuffer.Properties.TryGetProperty(typeof(IReplPromptProvider), out promptProvider)) {
133                    return new GlyphFactory(promptProvider);
134                }
135                return null;
136            }
137        }
138    }
139}