PageRenderTime 16ms CodeModel.GetById 2ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/EditorExtensions/Markdown/Classify/CodeLanguageEmbedders.cs

https://github.com/deltaLambda/WebEssentials2013
C# | 200 lines | 155 code | 13 blank | 32 comment | 8 complexity | 4bc92149f43d8784a4cbc75ac97fcc1c MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.ComponentModel.Composition;
  4using System.Diagnostics.CodeAnalysis;
  5using System.Linq;
  6using Microsoft.Html.Editor;
  7using Microsoft.Html.Editor.Projection;
  8using Microsoft.VisualStudio.Shell;
  9using Microsoft.VisualStudio.Shell.Interop;
 10using Microsoft.VisualStudio.Text;
 11using Microsoft.VisualStudio.Utilities;
 12using Microsoft.Web.Editor;
 13
 14namespace MadsKristensen.EditorExtensions.Markdown
 15{
 16    ///<summary>Preprocesses embedded code Markdown blocks before creating projection buffers.</summary>
 17    ///<remarks>
 18    /// Implement this interface to initialize language services for
 19    /// your language, or to add custom wrapping text around blocks.
 20    /// Implementations should be state-less; only one instance will
 21    /// be created.
 22    ///</remarks>
 23    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Embedder")]
 24    public interface ICodeLanguageEmbedder
 25    {
 26        ///<summary>Gets a string to insert at the top of the generated ProjectionBuffr for this language.</summary>
 27        ///<remarks>Each Markdown file will have exactly one copy of this string in its code buffer.</remarks>
 28        string GlobalPrefix { get; }
 29        ///<summary>Gets a string to insert at the bottom of the generated ProjectionBuffr for this language.</summary>
 30        ///<remarks>Each Markdown file will have exactly one copy of this string in its code buffer.</remarks>
 31        string GlobalSuffix { get; }
 32
 33        ///<summary>Gets text to insert around each embedded code block for this language.</summary>
 34        ///<param name="code">The lines of code in the block.  Enumerating this may be expensive.</param>
 35        ///<returns>
 36        /// One of the following:
 37        ///  - Null or an empty sequence to surround with \r\n.
 38        ///  - A single string to put on both ends of the code.
 39        ///  - Two strings; one for each end of the code block.
 40        /// The buffer generator will always add newlines.
 41        ///</returns>
 42        ///<remarks>
 43        /// These strings will be wrapped around every embedded
 44        /// code block separately.
 45        ///</remarks>
 46        IReadOnlyCollection<string> GetBlockWrapper(IEnumerable<string> code);
 47
 48        ///<summary>Called when a block of this type is first created within a document.</summary>
 49        void OnBlockCreated(ITextBuffer editorBuffer, LanguageProjectionBuffer projectionBuffer);
 50    }
 51
 52    [Export(typeof(ICodeLanguageEmbedder))]
 53    [ContentType("CSS")]
 54    public class CssEmbedder : ICodeLanguageEmbedder
 55    {
 56
 57        public IReadOnlyCollection<string> GetBlockWrapper(IEnumerable<string> code)
 58        {
 59            // If the code doesn't have any braces, surround it in a ruleset so that properties are valid.
 60            if (code.All(t => t.IndexOfAny(new[] { '{', '}' }) == -1))
 61                return new[] { ".GeneratedClass-" + Guid.NewGuid() + " {", "}" };
 62            return null;
 63        }
 64
 65        public void OnBlockCreated(ITextBuffer editorBuffer, LanguageProjectionBuffer projectionBuffer) { }
 66        public string GlobalPrefix { get { return ""; } }
 67        public string GlobalSuffix { get { return ""; } }
 68    }
 69    [Export(typeof(ICodeLanguageEmbedder))]
 70    [ContentType("Javascript")]
 71    [ContentType("node.js")]
 72    public class JavaScriptEmbedder : ICodeLanguageEmbedder
 73    {
 74        // Statements like return or arguments can only appear inside a function.
 75        // There are no statements that cannot appear in a function.
 76        // TODO: IntelliSense for Node.js vs. HTML.
 77        static readonly IReadOnlyCollection<string> wrapper = new[] { "function() {", "}" };
 78        public IReadOnlyCollection<string> GetBlockWrapper(IEnumerable<string> code) { return wrapper; }
 79        public void OnBlockCreated(ITextBuffer editorBuffer, LanguageProjectionBuffer projectionBuffer) { }
 80        public string GlobalPrefix { get { return ""; } }
 81        public string GlobalSuffix { get { return ""; } }
 82    }
 83
 84    public abstract class IntellisenseProjectEmbedder : ICodeLanguageEmbedder
 85    {
 86        public abstract IReadOnlyCollection<string> GetBlockWrapper(IEnumerable<string> code);
 87        public abstract string ProviderName { get; }
 88
 89        Guid FindGuid()
 90        {
 91            try
 92            {
 93                using (var settings = VSRegistry.RegistryRoot(__VsLocalRegistryType.RegType_Configuration))
 94                using (var languages = settings.OpenSubKey("Languages"))
 95                using (var intellisenseProviders = languages.OpenSubKey("IntellisenseProviders"))
 96                using (var provider = intellisenseProviders.OpenSubKey(ProviderName))
 97                    return new Guid(provider.GetValue("GUID").ToString());
 98            }
 99            catch
100            {
101                return Guid.Empty;
102            }
103        }
104
105        public void OnBlockCreated(ITextBuffer editorBuffer, LanguageProjectionBuffer projectionBuffer)
106        {
107            EventHandler<EventArgs> h = null;
108            h = delegate
109            {
110                // Make sure we don't set up ContainedLanguages until the buffer is ready
111                // When loading lots of Markdown files on solution load, we might need to
112                // wait for multiple idle cycles.
113                var doc = ServiceManager.GetService<HtmlEditorDocument>(editorBuffer);
114                if (doc == null) return;
115                if (doc.PrimaryView == null) return;
116
117                WebEditor.OnIdle -= h;
118                Guid guid = FindGuid();
119                if (guid != Guid.Empty)
120                    ContainedLanguageAdapter.ForBuffer(editorBuffer).AddIntellisenseProjectLanguage(projectionBuffer, guid);
121            };
122            WebEditor.OnIdle += h;
123        }
124
125        public virtual string GlobalPrefix { get { return ""; } }
126        public virtual string GlobalSuffix { get { return ""; } }
127    }
128
129    [Export(typeof(ICodeLanguageEmbedder))]
130    [ContentType("CSharp")]
131    public class CSharpEmbedder : IntellisenseProjectEmbedder
132    {
133        public override string ProviderName { get { return "CSharpCodeProvider"; } }
134        public override string GlobalPrefix
135        {
136            get
137            {
138                return @"using System;
139                         using System.Collections.Generic;
140                         using System.Data;
141                         using System.IO;
142                         using System.Linq;
143                         using System.Net;
144                         using System.Net.Http;
145                         using System.Net.Http.Formatting;
146                         using System.Reflection;
147                         using System.Text;
148                         using System.Threading;
149                         using System.Threading.Tasks;
150                         using System.Xml;
151                         using System.Xml.Linq;";
152            }
153        }
154        public override IReadOnlyCollection<string> GetBlockWrapper(IEnumerable<string> code)
155        {
156            return new[] { @"partial class Entry
157                            {
158                                  async Task<object> SampleMethod" + Guid.NewGuid().ToString("n") + @"() {", @"
159                                return await Task.FromResult(new object());
160                            }
161                            }" };
162        }
163    }
164
165    [Export(typeof(ICodeLanguageEmbedder))]
166    [ContentType("Basic")]
167    public class VBEmbedder : IntellisenseProjectEmbedder
168    {
169        public override string ProviderName { get { return "VBCodeProvider"; } }
170        public override string GlobalPrefix
171        {
172            get
173            {
174                return @"Imports System
175                        Imports System.Collections.Generic
176                        Imports System.Data
177                        Imports System.IO
178                        Imports System.Linq
179                        Imports System.Net
180                        Imports System.Net.Http
181                        Imports System.Net.Http.Formatting
182                        Imports System.Reflection
183                        Imports System.Text
184                        Imports System.Threading
185                        Imports System.Threading.Tasks
186                        Imports System.Xml
187                        Imports System.Xml.Linq";
188            }
189        }
190        public override IReadOnlyCollection<string> GetBlockWrapper(IEnumerable<string> code)
191        {
192            return new[] { @"
193                            Partial Class Entry
194                            Async Function SampleMethod" + Guid.NewGuid().ToString("n") + @"() As Task(Of Object)", @"
195                                Return Await Task.FromResult(New Object())
196                            End Function
197                            End Class" };
198        }
199    }
200}