diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..412eeda78 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b9d6bd92f --- /dev/null +++ b/.gitignore @@ -0,0 +1,215 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg diff --git a/CssSorter.dll b/CssSorter.dll new file mode 100644 index 000000000..fb8ae8306 Binary files /dev/null and b/CssSorter.dll differ diff --git a/EditorExtensions/Adornments/Color/ColorAdornment.cs b/EditorExtensions/Adornments/Color/ColorAdornment.cs new file mode 100644 index 000000000..406924b46 --- /dev/null +++ b/EditorExtensions/Adornments/Color/ColorAdornment.cs @@ -0,0 +1,70 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using MadsKristensen.EditorExtensions; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.CSS.Editor.Intellisense; + +namespace IntraTextAdornmentSample +{ + internal sealed class ColorAdornment : Border + { + internal ColorAdornment(ColorTag colorTag, IWpfTextView view) + { + this.Padding = new Thickness(0); + this.BorderThickness = new Thickness(1); + this.Margin = new Thickness(0, 0, 2, 3); + this.Width = OptionHelpers.FontSize; + this.Height = this.Width; + this.Cursor = System.Windows.Input.Cursors.Arrow; + this.MouseUp += delegate { ColorAdornmentMouseUp(view); }; + + Update(colorTag); + } + + private static void ColorAdornmentMouseUp(IWpfTextView view) + { + try + { + CssCompletionController.FromView(view).OnShowMemberList(filterList: true); + } + catch + { } + } + + internal void Update(ColorTag colorTag) + { + this.Background = new SolidColorBrush(colorTag.Color); + if (!HasContrastToBackground(colorTag.Color)) + { + this.BorderThickness = new Thickness(1); + this.BorderBrush = _borderColor; + } + else + { + this.BorderThickness = new Thickness(0); + this.BorderBrush = this.Background; + } + } + + private static SolidColorBrush _borderColor = OptionHelpers.BackgroundColor.Invert().ToBrush(); + + private static bool HasContrastToBackground(Color color) + { + // The color is very transparent (alpha channel) + if (color.A < 13) + { + return false; + } + + var b = OptionHelpers.BackgroundColor; + double bBrightness = b.Red * 299 + b.Green * 587 + b.Blue * 114; + double cBrightness = color.R * 299 + color.G * 587 + color.B * 114; + double distance = Math.Abs(cBrightness - bBrightness) / 1000; + + return distance > 20; + } + } +} diff --git a/EditorExtensions/Adornments/Color/ColorAdornmentTagger.cs b/EditorExtensions/Adornments/Color/ColorAdornmentTagger.cs new file mode 100644 index 000000000..fd8c13c67 --- /dev/null +++ b/EditorExtensions/Adornments/Color/ColorAdornmentTagger.cs @@ -0,0 +1,97 @@ +//*************************************************************************** +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// This code is licensed under the Visual Studio SDK license terms. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//*************************************************************************** + +// This controls whether the adornments are positioned next to the hex values or instead of them. +#define HIDING_TEXT + +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; + +namespace IntraTextAdornmentSample +{ + /// + /// Provides color swatch adornments in place of color constants. + /// + /// + /// + /// This is a sample usage of the utility class. + /// + /// + internal sealed class ColorAdornmentTagger : IntraTextAdornmentTagger + { + internal static ITagger GetTagger(IWpfTextView view, Lazy> colorTagger) + { + return view.Properties.GetOrCreateSingletonProperty( + () => new ColorAdornmentTagger(view, colorTagger.Value)); + } + + private ITagAggregator colorTagger; + + private ColorAdornmentTagger(IWpfTextView view, ITagAggregator colorTagger) + : base(view) + { + this.colorTagger = colorTagger; + } + + public void Dispose() + { + this.colorTagger.Dispose(); + + base.view.Properties.RemoveProperty(typeof(ColorAdornmentTagger)); + } + + // To produce adornments that don't obscure the text, the adornment tags + // should have zero length spans. Overriding this method allows control + // over the tag spans. + protected override IEnumerable> GetAdornmentData(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0) + yield break; + + ITextSnapshot snapshot = spans[0].Snapshot; + + var colorTags = this.colorTagger.GetTags(spans); + + foreach (IMappingTagSpan dataTagSpan in colorTags) + { + NormalizedSnapshotSpanCollection colorTagSpans = dataTagSpan.Span.GetSpans(snapshot); + + // Ignore data tags that are split by projection. + // This is theoretically possible but unlikely in current scenarios. + if (colorTagSpans.Count != 1) + continue; + + SnapshotSpan adornmentSpan = new SnapshotSpan(colorTagSpans[0].Start, 0); + + yield return Tuple.Create(adornmentSpan, (PositionAffinity?)PositionAffinity.Successor, dataTagSpan.Tag); + } + } + + protected override ColorAdornment CreateAdornment(ColorTag dataTag, SnapshotSpan span) + { + return new ColorAdornment(dataTag, view); + } + + protected override bool UpdateAdornment(ColorAdornment adornment, ColorTag dataTag) + { + if (adornment != null) + { + adornment.Update(dataTag); + } + + return true; + } + } +} diff --git a/EditorExtensions/Adornments/Color/ColorAdornmentTaggerProvider.cs b/EditorExtensions/Adornments/Color/ColorAdornmentTaggerProvider.cs new file mode 100644 index 000000000..c14470778 --- /dev/null +++ b/EditorExtensions/Adornments/Color/ColorAdornmentTaggerProvider.cs @@ -0,0 +1,50 @@ +//*************************************************************************** +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// This code is licensed under the Visual Studio SDK license terms. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//*************************************************************************** + +using System; +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; + +namespace IntraTextAdornmentSample +{ + [Export(typeof(IViewTaggerProvider))] + [ContentType("css")] + [TagType(typeof(IntraTextAdornmentTag))] + internal sealed class ColorAdornmentTaggerProvider : IViewTaggerProvider + { + #pragma warning disable 649 // "field never assigned to" -- field is set by MEF. + [Import] + internal IBufferTagAggregatorFactoryService BufferTagAggregatorFactoryService; + #pragma warning restore 649 + + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + { + if (textView == null) + throw new ArgumentNullException("textView"); + + if (buffer == null) + throw new ArgumentNullException("buffer"); + + if (buffer != textView.TextBuffer) + return null; + + return ColorAdornmentTagger.GetTagger( + (IWpfTextView)textView, + new Lazy>( + () => BufferTagAggregatorFactoryService.CreateTagAggregator(textView.TextBuffer))) + as ITagger; + } + } +} diff --git a/EditorExtensions/Adornments/Color/ColorTag.cs b/EditorExtensions/Adornments/Color/ColorTag.cs new file mode 100644 index 000000000..e21cd83cc --- /dev/null +++ b/EditorExtensions/Adornments/Color/ColorTag.cs @@ -0,0 +1,37 @@ +//*************************************************************************** +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// This code is licensed under the Visual Studio SDK license terms. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//*************************************************************************** + +using System.Windows.Media; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; + +namespace IntraTextAdornmentSample +{ + /// + /// Data tag indicating that the tagged text represents a color. + /// + /// + /// Note that this tag has nothing directly to do with adornments or other UI. + /// This sample's adornments will be produced based on the data provided in these tags. + /// This separation provides the potential for other extensions to consume color tags + /// and provide alternative UI or other derived functionality over this data. + /// + internal class ColorTag : ITag + { + internal ColorTag(Color color) + { + this.Color = color; + } + + internal readonly Color Color; + } +} diff --git a/EditorExtensions/Adornments/Color/ColorTagger.cs b/EditorExtensions/Adornments/Color/ColorTagger.cs new file mode 100644 index 000000000..9bde2a3ca --- /dev/null +++ b/EditorExtensions/Adornments/Color/ColorTagger.cs @@ -0,0 +1,139 @@ +using MadsKristensen.EditorExtensions; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.Less.Core; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.Web.Editor; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Threading; + +namespace IntraTextAdornmentSample +{ + internal sealed class ColorTagger : ITagger + { + private ITextBuffer _buffer; + private CssTree _tree; + + internal ColorTagger(ITextBuffer buffer) + { + _buffer = buffer; + _buffer.ChangedLowPriority += BufferChanged; + } + + public event EventHandler TagsChanged; + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0 || spans[0].Length == 0 || spans[0].Length >= _buffer.CurrentSnapshot.Length || !EnsureInitialized()) + yield break; + + IEnumerable items = GetColors(spans[0]); + + foreach (var item in items.Where(i => (i.Start + i.Length) <= _buffer.CurrentSnapshot.Length)) + { + SnapshotSpan span = new SnapshotSpan(_buffer.CurrentSnapshot, item.Start, item.Length); + ColorModel colorModel = ColorParser.TryParseColor(item, ColorParser.Options.AllowAlpha | ColorParser.Options.AllowNames); + if (colorModel != null) + { + yield return new TagSpan(span, new ColorTag(colorModel.Color)); + } + } + } + + private IEnumerable GetColors(SnapshotSpan span) + { + List items = new List(); + + // TODO: Refine this so it goes directly to the individual HexColorValue, FunctionColor and TokenItem + ParseItem complexItem = _tree.StyleSheet.ItemFromRange(span.Start, span.Length); + if (complexItem == null || (!(complexItem is AtDirective) && !(complexItem is RuleBlock) && !(complexItem is LessVariableDeclaration))) + return items; + + IEnumerable declarations = new ParseItem[0]; + + var lessVar = complexItem as LessVariableDeclaration; + + if (lessVar != null) + { + declarations = new List() { lessVar.Value }; + + } + else + { + var visitorRules = new CssItemCollector(); + complexItem.Accept(visitorRules); + + declarations = from d in visitorRules.Items + where d.Values.TextAfterEnd > span.Start && d.Values.TextStart < span.End && d.Length > 2 + select d; + } + + foreach (var declaration in declarations.Where(d => d != null)) + { + var visitorHex = new CssItemCollector(); + declaration.Accept(visitorHex); + items.AddRange(visitorHex.Items); + + var visitorFunc = new CssItemCollector(); + declaration.Accept(visitorFunc); + items.AddRange(visitorFunc.Items); + + var visitorName = new CssItemCollector(); + declaration.Accept(visitorName); + items.AddRange(visitorName.Items.Where(i => (i.PreviousSibling == null || (i.PreviousSibling.Text != "@" && i.PreviousSibling.Text != "$")) && i.TokenType == CssTokenType.Identifier && Color.FromName(i.Text).IsNamedColor)); + } + + return items; + } + + public bool EnsureInitialized() + { + if (_tree == null && WebEditor.Host != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + + private void BufferChanged(object sender, TextContentChangedEventArgs e) + { + if (e.Changes.Count == 0) + return; + + var temp = TagsChanged; + if (temp == null) + return; + + // Combine all changes into a single span so that + // the ITagger<>.TagsChanged event can be raised just once for a compound edit + // with many parts. + + ITextSnapshot snapshot = e.After; + + int start = e.Changes[0].NewPosition; + int end = e.Changes[e.Changes.Count - 1].NewEnd; + + SnapshotSpan totalAffectedSpan = new SnapshotSpan( + snapshot.GetLineFromPosition(start).Start, + snapshot.GetLineFromPosition(end).End); + + //temp(this, new SnapshotSpanEventArgs(totalAffectedSpan)); + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => temp(this, new SnapshotSpanEventArgs(totalAffectedSpan))), DispatcherPriority.ApplicationIdle); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Adornments/Color/ColorTaggerProvider.cs b/EditorExtensions/Adornments/Color/ColorTaggerProvider.cs new file mode 100644 index 000000000..f1ab791fa --- /dev/null +++ b/EditorExtensions/Adornments/Color/ColorTaggerProvider.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; + +namespace IntraTextAdornmentSample +{ + [Export(typeof(ITaggerProvider))] + [ContentType("css")] + [TagType(typeof(ColorTag))] + internal sealed class ColorTaggerProvider : ITaggerProvider + { + public ITagger CreateTagger(ITextBuffer buffer) where T : ITag + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + return buffer.Properties.GetOrCreateSingletonProperty(() => new ColorTagger(buffer)) as ITagger; + } + } +} diff --git a/EditorExtensions/Adornments/Color/IntraTextAdornmentTagger.cs b/EditorExtensions/Adornments/Color/IntraTextAdornmentTagger.cs new file mode 100644 index 000000000..21e86c890 --- /dev/null +++ b/EditorExtensions/Adornments/Color/IntraTextAdornmentTagger.cs @@ -0,0 +1,268 @@ +//*************************************************************************** +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// This code is licensed under the Visual Studio SDK license terms. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//*************************************************************************** + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; + +namespace IntraTextAdornmentSample +{ + /// + /// Helper class for interspersing adornments into text. + /// + /// + /// To avoid an issue around intra-text adornment support and its interaction with text buffer changes, + /// this tagger reacts to text and color tag changes with a delay. It waits to send out its own TagsChanged + /// event until the WPF Dispatcher is running again and it takes care to report adornments + /// that are consistent with the latest sent TagsChanged event by storing that particular snapshot + /// and using it to query for the data tags. + /// + internal abstract class IntraTextAdornmentTagger + : ITagger + where TAdornment : UIElement + { + protected readonly IWpfTextView view; + private Dictionary adornmentCache = new Dictionary(); + protected ITextSnapshot snapshot { get; private set; } + private readonly List invalidatedSpans = new List(); + private bool _isProcessing; + + protected IntraTextAdornmentTagger(IWpfTextView view) + { + this.view = view; + this.snapshot = view.TextBuffer.CurrentSnapshot; + + //this.view.LayoutChanged += HandleLayoutChanged; + this.view.TextBuffer.Changed += HandleBufferChanged; + } + + /// The span of text that this adornment will elide. + /// Adornment corresponding to given data. May be null. + protected abstract TAdornment CreateAdornment(TData data, SnapshotSpan span); + + /// True if the adornment was updated and should be kept. False to have the adornment removed from the view. + protected abstract bool UpdateAdornment(TAdornment adornment, TData data); + + /// Spans to provide adornment data for. These spans do not necessarily correspond to text lines. + /// + /// If adornments need to be updated, call or . + /// This will, indirectly, cause to be called. + /// + /// + /// A sequence of: + /// * adornment data for each adornment to be displayed + /// * the span of text that should be elided for that adornment (zero length spans are acceptable) + /// * and affinity of the adornment (this should be null if and only if the elided span has a length greater than zero) + /// + protected abstract IEnumerable> GetAdornmentData(NormalizedSnapshotSpanCollection spans); + + private void HandleBufferChanged(object sender, TextContentChangedEventArgs args) + { + if (!_isProcessing) + { + _isProcessing = true; + var editedSpans = args.Changes.Select(change => new SnapshotSpan(args.After, change.NewSpan)).ToList(); + InvalidateSpans(editedSpans); + } + + _isProcessing = false; + } + + /// + /// Causes intra-text adornments to be updated asynchronously. + /// + protected void InvalidateSpans(IList spans) + { + lock (this.invalidatedSpans) + { + bool wasEmpty = this.invalidatedSpans.Count == 0; + this.invalidatedSpans.AddRange(spans); + + if (wasEmpty && this.invalidatedSpans.Count > 0) + this.view.VisualElement.Dispatcher.BeginInvoke(new Action(AsyncUpdate)); + } + } + + private void AsyncUpdate() + { + // Store the snapshot that we're now current with and send an event + // for the text that has changed. + if (this.snapshot != this.view.TextBuffer.CurrentSnapshot) + { + this.snapshot = this.view.TextBuffer.CurrentSnapshot; + + Dictionary translatedAdornmentCache = new Dictionary(); + + foreach (var keyValuePair in this.adornmentCache) + { + var key = keyValuePair.Key.TranslateTo(this.snapshot, SpanTrackingMode.EdgeExclusive); + if (!translatedAdornmentCache.ContainsKey(key)) + translatedAdornmentCache.Add(key, keyValuePair.Value); + } + + this.adornmentCache = translatedAdornmentCache; + } + + List translatedSpans; + lock (this.invalidatedSpans) + { + translatedSpans = this.invalidatedSpans.Select(s => s.TranslateTo(this.snapshot, SpanTrackingMode.EdgeInclusive)).ToList(); + this.invalidatedSpans.Clear(); + } + + if (translatedSpans.Count == 0) + return; + + var start = translatedSpans.Select(span => span.Start).Min(); + var end = translatedSpans.Select(span => span.End).Max(); + + RaiseTagsChanged(new SnapshotSpan(start, end)); + } + + /// + /// Causes intra-text adornments to be updated synchronously. + /// + protected void RaiseTagsChanged(SnapshotSpan span) + { + var handler = this.TagsChanged; + if (handler != null) + handler(this, new SnapshotSpanEventArgs(span)); + } + + private void HandleLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) + { + if (!_isProcessing) + { + _isProcessing = true; + SnapshotSpan visibleSpan = this.view.TextViewLines.FormattedSpan; + + // Filter out the adornments that are no longer visible. + HashSet toRemove = new HashSet( + from keyValuePair + in this.adornmentCache + where !keyValuePair.Key.TranslateTo(visibleSpan.Snapshot, SpanTrackingMode.EdgeExclusive).IntersectsWith(visibleSpan) + select keyValuePair.Key); + + foreach (var span in toRemove) + this.adornmentCache.Remove(span); + } + + _isProcessing = false; + } + + + // Produces tags on the snapshot that the tag consumer asked for. + public virtual IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans == null || spans.Count == 0) + yield break; + + // Translate the request to the snapshot that this tagger is current with. + + ITextSnapshot requestedSnapshot = spans[0].Snapshot; + + var translatedSpans = new NormalizedSnapshotSpanCollection(spans.Select(span => span.TranslateTo(this.snapshot, SpanTrackingMode.EdgeExclusive))); + + // Grab the adornments. + var tags = GetAdornmentTagsOnSnapshot(translatedSpans).GetEnumerator(); + while (tags.MoveNext()) + { + var current = tags.Current; + SnapshotSpan span = current.Span.TranslateTo(requestedSnapshot, SpanTrackingMode.EdgeExclusive); + + IntraTextAdornmentTag tag = new IntraTextAdornmentTag(current.Tag.Adornment, current.Tag.RemovalCallback, current.Tag.Affinity); + yield return new TagSpan(span, tag); + } + } + + // Produces tags on the snapshot that this tagger is current with. + private IEnumerable> GetAdornmentTagsOnSnapshot(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0) + yield break; + + ITextSnapshot snapshot = spans[0].Snapshot; + + // Since WPF UI objects have state (like mouse hover or animation) and are relatively expensive to create and lay out, + // this code tries to reuse controls as much as possible. + // The controls are stored in this.adornmentCache between the calls. + + // Mark which adornments fall inside the requested spans with Keep=false + // so that they can be removed from the cache if they no longer correspond to data tags. + HashSet toRemove = new HashSet(); + foreach (var ar in this.adornmentCache) + if (spans.IntersectsWith(new NormalizedSnapshotSpanCollection(ar.Key))) + toRemove.Add(ar.Key); + + foreach (var spanDataPair in GetAdornmentData(spans).Distinct(new Comparer())) + { + // Look up the corresponding adornment or create one if it's new. + TAdornment adornment; + SnapshotSpan snapshotSpan = spanDataPair.Item1; + PositionAffinity? affinity = spanDataPair.Item2; + TData adornmentData = spanDataPair.Item3; + if (this.adornmentCache.TryGetValue(snapshotSpan, out adornment)) + { + if (UpdateAdornment(adornment, adornmentData)) + toRemove.Remove(snapshotSpan); + } + else + { + adornment = CreateAdornment(adornmentData, snapshotSpan); + + if (adornment == null) + continue; + + // Get the adornment to measure itself. Its DesiredSize property is used to determine + // how much space to leave between text for this adornment. + // Note: If the size of the adornment changes, the line will be reformatted to accommodate it. + // Note: Some adornments may change size when added to the view's visual tree due to inherited + // dependency properties that affect layout. Such options can include SnapsToDevicePixels, + // UseLayoutRounding, TextRenderingMode, TextHintingMode, and TextFormattingMode. Making sure + // that these properties on the adornment match the view's values before calling Measure here + // can help avoid the size change and the resulting unnecessary re-format. + adornment.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + this.adornmentCache.Add(snapshotSpan, adornment); + } + + yield return new TagSpan(snapshotSpan, new IntraTextAdornmentTag(adornment, null, affinity)); + } + + foreach (var snapshotSpan in toRemove) + this.adornmentCache.Remove(snapshotSpan); + } + + public event EventHandler TagsChanged; + + private class Comparer : IEqualityComparer> + { + public bool Equals(Tuple x, Tuple y) + { + if (x == null && y == null) + return true; + if (x == null || y == null) + return false; + return x.Item1.Equals(y.Item1); + } + + public int GetHashCode(Tuple obj) + { + return obj.Item1.GetHashCode(); + } + } + + } +} diff --git a/EditorExtensions/Classifications/Base64TaggerProvider.cs b/EditorExtensions/Classifications/Base64TaggerProvider.cs new file mode 100644 index 000000000..c848726a5 --- /dev/null +++ b/EditorExtensions/Classifications/Base64TaggerProvider.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System.Text.RegularExpressions; +using MadsKristensen.EditorExtensions.QuickInfo; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.Web.Editor; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ITaggerProvider))] + [TagType(typeof(IOutliningRegionTag))] + [ContentType("CSS")] + internal sealed class Base64TaggerProvider : ITaggerProvider + { + public ITagger CreateTagger(ITextBuffer buffer) where T : ITag + { + return buffer.Properties.GetOrCreateSingletonProperty(() => new Base64Tagger(buffer)) as ITagger; + //return new Base64Tagger(buffer) as ITagger; + } + } + + internal sealed class Base64Tagger : ITagger + { + private ITextBuffer buffer; + private ITextSnapshot snapshot; + private string text; + private CssTree _tree; + + public Base64Tagger(ITextBuffer buffer) + { + this.buffer = buffer; + this.snapshot = buffer.CurrentSnapshot; + this.text = snapshot.GetText(); + this.buffer.Changed += BufferChanged; + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0 || !EnsureInitialized()) + yield break; + + var visitor = new CssItemCollector(); + _tree.StyleSheet.Accept(visitor); + + foreach (UrlItem url in visitor.Items.Where(u => u.UrlString != null && u.Start >= spans[0].Start)) + { + if (url.UrlString.Text.IndexOf("base64,") > -1 && buffer.CurrentSnapshot.Length >= url.UrlString.AfterEnd) + { + var image = ImageQuickInfo.CreateImage(url.UrlString.Text.Trim('"', '\'')); + var span = new SnapshotSpan(new SnapshotPoint(buffer.CurrentSnapshot, url.UrlString.Start), url.UrlString.Length); + var tag = new OutliningRegionTag(true, true, url.UrlString.Length + " characters", image); + yield return new TagSpan(span, tag); + } + } + } + + public bool EnsureInitialized() + { + if (_tree == null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(buffer); + _tree = document.Tree; + } + catch (Exception) + { + } + } + + return _tree != null; + } + + public event EventHandler TagsChanged; + + void BufferChanged(object sender, TextContentChangedEventArgs e) + { + // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). + if (e.After != buffer.CurrentSnapshot) + return; + //this.ReParse(); + } + } +} diff --git a/EditorExtensions/Classifications/BraceMatching.cs b/EditorExtensions/Classifications/BraceMatching.cs new file mode 100644 index 000000000..cec029711 --- /dev/null +++ b/EditorExtensions/Classifications/BraceMatching.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.WebEssentials.Css.BraceMatching +{ + [Export(typeof(IViewTaggerProvider))] + [ContentType("CSS")] + [ContentType("LESS")] + [TagType(typeof(TextMarkerTag))] + internal class BraceMatchingTaggerProvider : IViewTaggerProvider + { + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + { + if (textView == null) + return null; + + //provide highlighting only on the top-level buffer + if (textView.TextBuffer != buffer) + return null; + + return new BraceMatchingTagger(textView, buffer) as ITagger; + } + } + + public class BraceMatchingTagger : ITagger + { + internal BraceMatchingTagger(ITextView view, ITextBuffer sourceBuffer) + { + //here the keys are the open braces, and the values are the close braces + m_braceList = new Dictionary(); + m_braceList.Add('{', '}'); + m_braceList.Add('[', ']'); + m_braceList.Add('(', ')'); + this.View = view; + this.SourceBuffer = sourceBuffer; + this.CurrentChar = null; + + this.View.Caret.PositionChanged += CaretPositionChanged; + this.View.LayoutChanged += ViewLayoutChanged; + } + + + ITextView View { get; set; } + ITextBuffer SourceBuffer { get; set; } + SnapshotPoint? CurrentChar { get; set; } + private Dictionary m_braceList; + + public event EventHandler TagsChanged; + + void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) + { + if (e.NewSnapshot != e.OldSnapshot) //make sure that there has really been a change + { + UpdateAtCaretPosition(View.Caret.Position); + } + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0) //there is no content in the buffer + yield break; + + //don't do anything if the current SnapshotPoint is not initialized or at the end of the buffer + if (!CurrentChar.HasValue || CurrentChar.Value.Position >= CurrentChar.Value.Snapshot.Length) + yield break; + + //hold on to a snapshot of the current character + SnapshotPoint currentChar = CurrentChar.Value; + + //if the requested snapshot isn't the same as the one the brace is on, translate our spans to the expected snapshot + if (spans[0].Snapshot != currentChar.Snapshot) + { + currentChar = currentChar.TranslateTo(spans[0].Snapshot, PointTrackingMode.Positive); + } + + //get the current char and the previous char + char currentText = currentChar.GetChar(); + SnapshotPoint lastChar = currentChar == 0 ? currentChar : currentChar - 1; //if currentChar is 0 (beginning of buffer), don't move it back + char lastText = lastChar.GetChar(); + SnapshotSpan pairSpan = new SnapshotSpan(); + + if (m_braceList.ContainsKey(currentText)) //the key is the open brace + { + char closeChar; + m_braceList.TryGetValue(currentText, out closeChar); + if (BraceMatchingTagger.FindMatchingCloseChar(currentChar, currentText, closeChar, View.TextViewLines.Count, out pairSpan) == true) + { + yield return new TagSpan(new SnapshotSpan(currentChar, 1), new TextMarkerTag("MarkerFormatDefinition/HighlightWordFormatDefinition")); + yield return new TagSpan(pairSpan, new TextMarkerTag("MarkerFormatDefinition/HighlightWordFormatDefinition")); + } + } + else if (m_braceList.ContainsValue(lastText)) //the value is the close brace, which is the *previous* character + { + var open = from n in m_braceList + where n.Value.Equals(lastText) + select n.Key; + if (BraceMatchingTagger.FindMatchingOpenChar(lastChar, (char)open.ElementAt(0), lastText, View.TextViewLines.Count, out pairSpan) == true) + { + yield return new TagSpan(new SnapshotSpan(lastChar, 1), new TextMarkerTag("MarkerFormatDefinition/HighlightWordFormatDefinition")); + yield return new TagSpan(pairSpan, new TextMarkerTag("MarkerFormatDefinition/HighlightWordFormatDefinition")); + } + } + } + + private static bool FindMatchingCloseChar(SnapshotPoint startPoint, char open, char close, int maxLines, out SnapshotSpan pairSpan) + { + pairSpan = new SnapshotSpan(startPoint.Snapshot, 1, 1); + ITextSnapshotLine line = startPoint.GetContainingLine(); + string lineText = line.GetText(); + int lineNumber = line.LineNumber; + int offset = startPoint.Position - line.Start.Position + 1; + + int stopLineNumber = startPoint.Snapshot.LineCount - 1; + if (maxLines > 0) + stopLineNumber = Math.Min(stopLineNumber, lineNumber + maxLines); + + int openCount = 0; + while (true) + { + //walk the entire line + while (offset < line.Length) + { + char currentChar = lineText[offset]; + if (currentChar == close) //found the close character + { + if (openCount > 0) + { + openCount--; + } + else //found the matching close + { + pairSpan = new SnapshotSpan(startPoint.Snapshot, line.Start + offset, 1); + return true; + } + } + else if (currentChar == open) // this is another open + { + openCount++; + } + offset++; + } + + //move on to the next line + if (++lineNumber > stopLineNumber) + break; + + line = line.Snapshot.GetLineFromLineNumber(lineNumber); + lineText = line.GetText(); + offset = 0; + } + + return false; + } + + private static bool FindMatchingOpenChar(SnapshotPoint startPoint, char open, char close, int maxLines, out SnapshotSpan pairSpan) + { + pairSpan = new SnapshotSpan(startPoint, startPoint); + + ITextSnapshotLine line = startPoint.GetContainingLine(); + + int lineNumber = line.LineNumber; + int offset = startPoint - line.Start - 1; //move the offset to the character before this one + + //if the offset is negative, move to the previous line + if (offset < 0 && lineNumber > 0) + { + line = line.Snapshot.GetLineFromLineNumber(--lineNumber); + offset = line.Length - 1; + } + + string lineText = line.GetText(); + + int stopLineNumber = 0; + if (maxLines > 0) + stopLineNumber = Math.Max(stopLineNumber, lineNumber - maxLines); + + int closeCount = 0; + + while (true) + { + // Walk the entire line + while (offset >= 0) + { + char currentChar = lineText[offset]; + + if (currentChar == open) + { + if (closeCount > 0) + { + closeCount--; + } + else // We've found the open character + { + pairSpan = new SnapshotSpan(line.Start + offset, 1); //we just want the character itself + return true; + } + } + else if (currentChar == close) + { + closeCount++; + } + offset--; + } + + // Move to the previous line + if (--lineNumber < stopLineNumber) + break; + + line = line.Snapshot.GetLineFromLineNumber(lineNumber); + lineText = line.GetText(); + offset = line.Length - 1; + } + return false; + } + + void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e) + { + UpdateAtCaretPosition(e.NewPosition); + } + + void UpdateAtCaretPosition(CaretPosition caretPosition) + { + CurrentChar = caretPosition.Point.GetPoint(SourceBuffer, caretPosition.Affinity); + + if (!CurrentChar.HasValue) + return; + + var tempEvent = TagsChanged; + if (tempEvent != null) + tempEvent(this, new SnapshotSpanEventArgs(new SnapshotSpan(SourceBuffer.CurrentSnapshot, 0, + SourceBuffer.CurrentSnapshot.Length))); + } + + } + +} diff --git a/EditorExtensions/Classifications/CssHighlightWordTagger.cs b/EditorExtensions/Classifications/CssHighlightWordTagger.cs new file mode 100644 index 000000000..75a427a91 --- /dev/null +++ b/EditorExtensions/Classifications/CssHighlightWordTagger.cs @@ -0,0 +1,225 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IViewTaggerProvider))] + [ContentType("CSS")] + [TagType(typeof(TextMarkerTag))] + internal class CssHighlightWordTaggerProvider : IViewTaggerProvider + { + [Import] + internal ITextSearchService TextSearchService { get; set; } + + [Import] + internal ITextStructureNavigatorSelectorService TextStructureNavigatorSelector { get; set; } + + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + { + if (textView.TextBuffer != buffer) + return null; + + ITextStructureNavigator textStructureNavigator = TextStructureNavigatorSelector.GetTextStructureNavigator(buffer); + //return new HighlightWordTagger(textView, buffer, TextSearchService, textStructureNavigator) as ITagger; + return buffer.Properties.GetOrCreateSingletonProperty(() => new CssHighlightWordTagger(textView, buffer, TextSearchService, textStructureNavigator)) as ITagger; + } + } + + internal class HighlightWordTag : TextMarkerTag + { + public HighlightWordTag() : base("MarkerFormatDefinition/HighlightWordFormatDefinition") { } + } + + internal class CssHighlightWordTagger : ITagger + { + ITextView _view { get; set; } + ITextBuffer _buffer { get; set; } + ITextSearchService _textSearchService { get; set; } + ITextStructureNavigator _textStructureNavigator { get; set; } + NormalizedSnapshotSpanCollection _wordSpans { get; set; } + SnapshotSpan? _currentWord { get; set; } + SnapshotPoint _requestedPoint { get; set; } + object _syncLock = new object(); + private CssTree _tree; + + public CssHighlightWordTagger(ITextView view, ITextBuffer sourceBuffer, ITextSearchService textSearchService, ITextStructureNavigator textStructureNavigator) + { + this._view = view; + this._buffer = sourceBuffer; + this._textSearchService = textSearchService; + this._textStructureNavigator = textStructureNavigator; + this._wordSpans = new NormalizedSnapshotSpanCollection(); + this._currentWord = null; + this._view.Caret.PositionChanged += CaretPositionChanged; + this._view.LayoutChanged += ViewLayoutChanged; + } + + private void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) + { + if (e.NewSnapshot != e.OldSnapshot) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => UpdateAtCaretPosition(_view.Caret.Position)), DispatcherPriority.ApplicationIdle, null); + } + } + + private void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => UpdateAtCaretPosition(e.NewPosition)), DispatcherPriority.ApplicationIdle, null); + } + + public event EventHandler TagsChanged; + + private void UpdateAtCaretPosition(CaretPosition caretPosition) + { + if (!WESettings.GetBoolean(WESettings.Keys.EnableCssSelectorHighligting)) + return; + + SnapshotPoint? point = caretPosition.Point.GetPoint(_buffer, caretPosition.Affinity); + + if (!point.HasValue || !EnsureInitialized()) + return; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(point.Value.Position); + if (item == null) + return; + + ParseItem validItem = item.FindType(); + + if (validItem == null) + validItem = item.FindType(); + + if (validItem == null) + validItem = item.FindType(); + + // If the new caret position is still within the current word (and on the same snapshot), we don't need to check it + if (_currentWord.HasValue + && _currentWord.Value.Snapshot == _view.TextSnapshot + && point.Value >= _currentWord.Value.Start + && point.Value <= _currentWord.Value.End) + { + return; + } + + _requestedPoint = point.Value; + Task.Run(new Action(() => UpdateWordAdornments(validItem))); + //UpdateWordAdornments(validItem); + } + + void UpdateWordAdornments(ParseItem item) + { + SnapshotPoint currentRequest = _requestedPoint; + List wordSpans = new List(); + SnapshotSpan currentWord; + + if (item != null) + { + currentWord = new SnapshotSpan(new SnapshotPoint(_buffer.CurrentSnapshot, item.Start), item.Length);// word.Span; + //If this is the current word, and the caret moved within a word, we're done. + if (_currentWord.HasValue && currentWord == _currentWord) + return; + + //Find the new spans + FindData findData = new FindData(item.Text, currentWord.Snapshot); + findData.FindOptions = FindOptions.WholeWord | FindOptions.MatchCase; + + wordSpans.AddRange(_textSearchService.FindAll(findData)); + + if (wordSpans.Count == 1) + wordSpans.Clear(); + } + else + { + TextExtent word = _textStructureNavigator.GetExtentOfWord(currentRequest); + currentWord = word.Span; + } + + //If another change hasn't happened, do a real update + if (currentRequest == _requestedPoint) + { + //Task.Run(new Action(() => SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(wordSpans), currentWord))); + SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(wordSpans), currentWord); + } + } + + private void SynchronousUpdate(SnapshotPoint currentRequest, NormalizedSnapshotSpanCollection newSpans, SnapshotSpan? newCurrentWord) + { + lock (_syncLock) + { + if (currentRequest != _requestedPoint) + return; + + _wordSpans = newSpans; + _currentWord = newCurrentWord; + + var tempEvent = TagsChanged; + if (tempEvent != null) + tempEvent(this, new SnapshotSpanEventArgs(new SnapshotSpan(_buffer.CurrentSnapshot, 0, _buffer.CurrentSnapshot.Length))); + } + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (_currentWord == null) + yield break; + + // Hold on to a "snapshot" of the word spans and current word, so that we maintain the same + // collection throughout + SnapshotSpan currentWord = _currentWord.Value; + NormalizedSnapshotSpanCollection wordSpans = _wordSpans; + + if (spans.Count == 0 || _wordSpans.Count == 0) + yield break; + + // If the requested snapshot isn't the same as the one our words are on, translate our spans to the expected snapshot + if (spans[0].Snapshot != wordSpans[0].Snapshot) + { + wordSpans = new NormalizedSnapshotSpanCollection( + wordSpans.Select(span => span.TranslateTo(spans[0].Snapshot, SpanTrackingMode.EdgeExclusive))); + + currentWord = currentWord.TranslateTo(spans[0].Snapshot, SpanTrackingMode.EdgeExclusive); + } + + // First, yield back the word the cursor is under (if it overlaps) + // Note that we'll yield back the same word again in the wordspans collection; + // the duplication here is expected. + if (spans.OverlapsWith(new NormalizedSnapshotSpanCollection(currentWord))) + yield return new TagSpan(currentWord, new HighlightWordTag()); + + // Second, yield all the other words in the file + foreach (SnapshotSpan span in NormalizedSnapshotSpanCollection.Overlap(spans, wordSpans)) + { + yield return new TagSpan(span, new HighlightWordTag()); + } + } + + private bool EnsureInitialized() + { + if (_tree == null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + } +} diff --git a/EditorExtensions/Classifications/JavaScriptArrayOutlining.cs b/EditorExtensions/Classifications/JavaScriptArrayOutlining.cs new file mode 100644 index 000000000..3e4866eb1 --- /dev/null +++ b/EditorExtensions/Classifications/JavaScriptArrayOutlining.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ITaggerProvider))] + [TagType(typeof(IOutliningRegionTag))] + [ContentType("JavaScript")] + internal sealed class ArrayOutliningTaggerProvider : ITaggerProvider + { + public ITagger CreateTagger(ITextBuffer buffer) where T : ITag + { + if (WESettings.GetBoolean(WESettings.Keys.JavaScriptOutlining)) + { + return buffer.Properties.GetOrCreateSingletonProperty(() => new JavaScriptArrayOutliningTagger(buffer)) as ITagger; + } + + return null; + } + } + + internal sealed class JavaScriptArrayOutliningTagger : ITagger + { + string startHide = "["; //the characters that start the outlining region + string endHide = "]"; //the characters that end the outlining region + string ellipsis = "..."; //the characters that are displayed when the region is collapsed + ITextBuffer buffer; + ITextSnapshot snapshot; + List regions; + + public JavaScriptArrayOutliningTagger(ITextBuffer buffer) + { + this.buffer = buffer; + this.snapshot = buffer.CurrentSnapshot; + this.regions = new List(); + this.buffer.ChangedLowPriority += BufferChanged; + + Task.Run(() => this.ReParse()); + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0) + yield break; + + List currentRegions = this.regions; + ITextSnapshot currentSnapshot = this.snapshot; + SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive); + int startLineNumber = entire.Start.GetContainingLine().LineNumber; + int endLineNumber = entire.End.GetContainingLine().LineNumber; + + foreach (var region in currentRegions) + { + if (region.StartLine <= endLineNumber && region.EndLine >= startLineNumber) + { + var startLine = currentSnapshot.GetLineFromLineNumber(region.StartLine); + string lineText = startLine.GetText().Trim(); + + if (!lineText.Contains("function")) + { + var endLine = currentSnapshot.GetLineFromLineNumber(region.EndLine); + var contentSpan = new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); + //the region starts at the beginning of the "[", and goes until the *end* of the line that contains the "]". + yield return new TagSpan(contentSpan, new OutliningRegionTag(false, true, ellipsis, contentSpan.GetText())); + } + } + } + } + + public event EventHandler TagsChanged; + + void BufferChanged(object sender, TextContentChangedEventArgs e) + { + // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). + if (e.After != buffer.CurrentSnapshot) + return; + + Task.Run(() => this.ReParse()); + } + + void ReParse() + { + ITextSnapshot newSnapshot = buffer.CurrentSnapshot; + List newRegions = new List(); + + //keep the current (deepest) partial region, which will have + // references to any parent partial regions. + PartialRegion currentRegion = null; + + foreach (var line in newSnapshot.Lines) + { + int regionStart = -1; + string text = line.GetText(); + + //lines that contain a "[" denote the start of a new region. + if ((regionStart = text.IndexOf(startHide, StringComparison.Ordinal)) != -1) + { + int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; + int newLevel; + if (!TryGetLevel(text, regionStart, out newLevel)) + newLevel = currentLevel + 1; + + //levels are the same and we have an existing region; + //end the current region and start the next + if (currentLevel == newLevel && currentRegion != null) + { + newRegions.Add(new Region() + { + Level = currentRegion.Level, + StartLine = currentRegion.StartLine, + StartOffset = currentRegion.StartOffset, + EndLine = line.LineNumber + }); + + currentRegion = new PartialRegion() + { + Level = newLevel, + StartLine = line.LineNumber, + StartOffset = regionStart, + PartialParent = currentRegion.PartialParent + }; + } + //this is a new (sub)region + else + { + currentRegion = new PartialRegion() + { + Level = newLevel, + StartLine = line.LineNumber, + StartOffset = regionStart, + PartialParent = currentRegion + }; + } + } + //lines that contain "]" denote the end of a region + else if ((regionStart = text.IndexOf(endHide, StringComparison.Ordinal)) != -1) + { + int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; + int closingLevel; + if (!TryGetLevel(text, regionStart, out closingLevel)) + closingLevel = currentLevel; + + //the regions match + if (currentRegion != null && + currentLevel == closingLevel) + { + newRegions.Add(new Region() + { + Level = currentLevel, + StartLine = currentRegion.StartLine, + StartOffset = currentRegion.StartOffset, + EndLine = line.LineNumber + }); + + currentRegion = currentRegion.PartialParent; + } + } + } + + //determine the changed span, and send a changed event with the new spans + List oldSpans = + new List(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot) + .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive) + .Span)); + List newSpans = + new List(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span)); + + NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans); + NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans); + + //the changed regions are regions that appear in one set or the other, but not both. + NormalizedSpanCollection removed = + NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection); + + int changeStart = int.MaxValue; + int changeEnd = -1; + + if (removed.Count > 0) + { + changeStart = removed[0].Start; + changeEnd = removed[removed.Count - 1].End; + } + + if (newSpans.Count > 0) + { + changeStart = Math.Min(changeStart, newSpans[0].Start); + changeEnd = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End); + } + + this.snapshot = newSnapshot; + this.regions = newRegions; + + if (changeStart <= changeEnd) + { + ITextSnapshot snap = this.snapshot; + if (this.TagsChanged != null) + this.TagsChanged(this, new SnapshotSpanEventArgs( + new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd)))); + } + } + + static bool TryGetLevel(string text, int startIndex, out int level) + { + level = -1; + if (text.Length > startIndex + 3) + { + if (int.TryParse(text.Substring(startIndex + 1), out level)) + return true; + } + + return false; + } + + static SnapshotSpan AsSnapshotSpan(Region region, ITextSnapshot snapshot) + { + var startLine = snapshot.GetLineFromLineNumber(region.StartLine); + var endLine = (region.StartLine == region.EndLine) ? startLine + : snapshot.GetLineFromLineNumber(region.EndLine); + return new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); + } + + } + + //class PartialRegion + //{ + // public int StartLine { get; set; } + // public int StartOffset { get; set; } + // public int Level { get; set; } + // public PartialRegion PartialParent { get; set; } + //} + + //class Region : PartialRegion + //{ + // public int EndLine { get; set; } + //} + +} diff --git a/EditorExtensions/Classifications/JavaScriptHighlightWordTagger.cs b/EditorExtensions/Classifications/JavaScriptHighlightWordTagger.cs new file mode 100644 index 000000000..16fcc6b85 --- /dev/null +++ b/EditorExtensions/Classifications/JavaScriptHighlightWordTagger.cs @@ -0,0 +1,213 @@ +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Threading.Tasks; + +namespace MadsKristensen.WebEssentials.Structures.Js +{ + [Export(typeof(IViewTaggerProvider))] + [ContentType("JavaScript")] + [TagType(typeof(TextMarkerTag))] + internal class HighlightWordTaggerProvider : IViewTaggerProvider + { + [Import] + internal ITextSearchService TextSearchService { get; set; } + + [Import] + internal ITextStructureNavigatorSelectorService TextStructureNavigatorSelector { get; set; } + + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + { + if (textView.TextBuffer != buffer) + return null; + + ITextStructureNavigator textStructureNavigator = TextStructureNavigatorSelector.GetTextStructureNavigator(buffer); + return buffer.Properties.GetOrCreateSingletonProperty(() => new JavaScriptHighlightWordTagger(textView, buffer, TextSearchService, textStructureNavigator)) as ITagger; + } + } + + internal class HighlightWordTag : TextMarkerTag + { + public HighlightWordTag() : base("MarkerFormatDefinition/HighlightWordFormatDefinition") { } + } + + internal class JavaScriptHighlightWordTagger : ITagger + { + ITextView _view { get; set; } + ITextBuffer _buffer { get; set; } + ITextSearchService _textSearchService { get; set; } + ITextStructureNavigator _textStructureNavigator { get; set; } + NormalizedSnapshotSpanCollection _wordSpans { get; set; } + SnapshotSpan? _currentWord { get; set; } + SnapshotPoint _requestedPoint { get; set; } + object _updateLock = new object(); + private bool _inProgress; + + public JavaScriptHighlightWordTagger(ITextView view, ITextBuffer sourceBuffer, ITextSearchService textSearchService, ITextStructureNavigator textStructureNavigator) + { + this._view = view; + this._buffer = sourceBuffer; + this._textSearchService = textSearchService; + this._textStructureNavigator = textStructureNavigator; + this._wordSpans = new NormalizedSnapshotSpanCollection(); + this._currentWord = null; + this._view.Caret.PositionChanged += CaretPositionChanged; + } + + void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e) + { + if (!_inProgress) + { + _inProgress = true; + + Task.Run(() => + { + UpdateAtCaretPosition(e.NewPosition); + _inProgress = false; + }); + } + } + + public event EventHandler TagsChanged; + + void UpdateAtCaretPosition(CaretPosition caretPosition) + { + SnapshotPoint? point = caretPosition.Point.GetPoint(_buffer, caretPosition.Affinity); + + if (!point.HasValue) + return; + + // If the new caret position is still within the current word (and on the same snapshot), we don't need to check it + if (_currentWord.HasValue + && _currentWord.Value.Snapshot == _view.TextSnapshot + && point.Value >= _currentWord.Value.Start + && point.Value <= _currentWord.Value.End) + { + return; + } + + _requestedPoint = point.Value; + + UpdateWordAdornments(); + } + + void UpdateWordAdornments() + { + SnapshotPoint currentRequest = _requestedPoint; + List wordSpans = new List(); + //Find all words in the buffer like the one the caret is on + TextExtent word = _textStructureNavigator.GetExtentOfWord(currentRequest); + bool foundWord = true; + //If we've selected something not worth highlighting, we might have missed a "word" by a little bit + if (!WordExtentIsValid(currentRequest, word)) + { + //Before we retry, make sure it is worthwhile + if (word.Span.Start != currentRequest + || currentRequest == currentRequest.GetContainingLine().Start + || char.IsWhiteSpace((currentRequest - 1).GetChar())) + { + foundWord = false; + } + else + { + // Try again, one character previous. + //If the caret is at the end of a word, pick up the word. + word = _textStructureNavigator.GetExtentOfWord(currentRequest - 1); + + //If the word still isn't valid, we're done + if (!WordExtentIsValid(currentRequest, word)) + foundWord = false; + } + } + + if (!foundWord) + { + //If we couldn't find a word, clear out the existing markers + SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); + return; + } + + SnapshotSpan currentWord = word.Span; + //If this is the current word, and the caret moved within a word, we're done. + if (_currentWord.HasValue && currentWord == _currentWord) + return; + + //Find the new spans + FindData findData = new FindData(currentWord.GetText(), currentWord.Snapshot); + findData.FindOptions = FindOptions.WholeWord | FindOptions.MatchCase; + + wordSpans.AddRange(_textSearchService.FindAll(findData)); + + //If another change hasn't happened, do a real update + if (currentRequest == _requestedPoint) + SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(wordSpans), currentWord); + } + static bool WordExtentIsValid(SnapshotPoint currentRequest, TextExtent word) + { + return word.IsSignificant + && currentRequest.Snapshot.GetText(word.Span).Any(c => char.IsLetter(c)); + } + + void SynchronousUpdate(SnapshotPoint currentRequest, NormalizedSnapshotSpanCollection newSpans, SnapshotSpan? newCurrentWord) + { + lock (_updateLock) + { + if (currentRequest != _requestedPoint) + return; + + _wordSpans = newSpans; + _currentWord = newCurrentWord; + + var tempEvent = TagsChanged; + if (tempEvent != null) + tempEvent(this, new SnapshotSpanEventArgs(new SnapshotSpan(_buffer.CurrentSnapshot, 0, _buffer.CurrentSnapshot.Length))); + } + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (_currentWord == null) + yield break; + + // Hold on to a "snapshot" of the word spans and current word, so that we maintain the same + // collection throughout + SnapshotSpan currentWord = _currentWord.Value; + NormalizedSnapshotSpanCollection wordSpans = _wordSpans; + + if (spans.Count == 0 || _wordSpans.Count == 0) + yield break; + + // If the requested snapshot isn't the same as the one our words are on, translate our spans to the expected snapshot + if (spans[0].Snapshot != wordSpans[0].Snapshot) + { + wordSpans = new NormalizedSnapshotSpanCollection( + wordSpans.Select(span => span.TranslateTo(spans[0].Snapshot, SpanTrackingMode.EdgeExclusive))); + + currentWord = currentWord.TranslateTo(spans[0].Snapshot, SpanTrackingMode.EdgeExclusive); + } + + NormalizedSnapshotSpanCollection words = NormalizedSnapshotSpanCollection.Overlap(spans, wordSpans); + + if (words.Count == 1) + yield break; + + // First, yield back the word the cursor is under (if it overlaps) + // Note that we'll yield back the same word again in the wordspans collection; + // the duplication here is expected. + if (spans.OverlapsWith(new NormalizedSnapshotSpanCollection(currentWord))) + yield return new TagSpan(currentWord, new HighlightWordTag()); + + // Second, yield all the other words in the file + foreach (SnapshotSpan span in words) + { + yield return new TagSpan(span, new HighlightWordTag()); + } + } + } +} diff --git a/EditorExtensions/Classifications/JavaScriptOutlining.cs b/EditorExtensions/Classifications/JavaScriptOutlining.cs new file mode 100644 index 000000000..c5ad13bd4 --- /dev/null +++ b/EditorExtensions/Classifications/JavaScriptOutlining.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ITaggerProvider))] + [TagType(typeof(IOutliningRegionTag))] + [ContentType("JavaScript")] + internal sealed class OutliningTaggerProvider : ITaggerProvider + { + public ITagger CreateTagger(ITextBuffer buffer) where T : ITag + { + if (WESettings.GetBoolean(WESettings.Keys.JavaScriptOutlining)) + { + return buffer.Properties.GetOrCreateSingletonProperty(() => new JavaScriptOutliningTagger(buffer)) as ITagger; + } + + return null; + } + } + + internal sealed class JavaScriptOutliningTagger : ITagger + { + string startHide = "{"; //the characters that start the outlining region + string endHide = "}"; //the characters that end the outlining region + string ellipsis = "..."; //the characters that are displayed when the region is collapsed + ITextBuffer buffer; + ITextSnapshot snapshot; + List regions; + + public JavaScriptOutliningTagger(ITextBuffer buffer) + { + this.buffer = buffer; + this.snapshot = buffer.CurrentSnapshot; + this.regions = new List(); + this.buffer.ChangedLowPriority += BufferChanged; + + Task.Run(() => this.ReParse()); + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0) + yield break; + + List currentRegions = this.regions; + ITextSnapshot currentSnapshot = this.snapshot; + SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive); + int startLineNumber = entire.Start.GetContainingLine().LineNumber; + int endLineNumber = entire.End.GetContainingLine().LineNumber; + + foreach (var region in currentRegions) + { + if (region.StartLine <= endLineNumber && region.EndLine >= startLineNumber) + { + var startLine = currentSnapshot.GetLineFromLineNumber(region.StartLine); + string lineText = startLine.GetText().Trim(); + + if (!lineText.Contains("function")) + { + var endLine = currentSnapshot.GetLineFromLineNumber(region.EndLine); + var contentSpan = new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); + //the region starts at the beginning of the "[", and goes until the *end* of the line that contains the "]". + yield return new TagSpan(contentSpan, new OutliningRegionTag(false, false, ellipsis, contentSpan.GetText())); + } + } + } + } + + public event EventHandler TagsChanged; + + void BufferChanged(object sender, TextContentChangedEventArgs e) + { + // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). + if (e.After != buffer.CurrentSnapshot) + return; + + Task.Run(() => this.ReParse()); + } + + void ReParse() + { + ITextSnapshot newSnapshot = buffer.CurrentSnapshot; + List newRegions = new List(); + + //keep the current (deepest) partial region, which will have + // references to any parent partial regions. + PartialRegion currentRegion = null; + + foreach (var line in newSnapshot.Lines) + { + int regionStart = -1; + string text = line.GetText(); + + if (text.IndexOf(startHide) > -1 && text.IndexOf(endHide) > -1) + continue; + + //lines that contain a "[" denote the start of a new region. + if ((regionStart = text.IndexOf(startHide, StringComparison.Ordinal)) != -1) + { + int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; + int newLevel; + if (!TryGetLevel(text, regionStart, out newLevel)) + newLevel = currentLevel + 1; + + //levels are the same and we have an existing region; + //end the current region and start the next + if (currentLevel == newLevel && currentRegion != null) + { + newRegions.Add(new Region() + { + Level = currentRegion.Level, + StartLine = currentRegion.StartLine, + StartOffset = currentRegion.StartOffset, + EndLine = line.LineNumber + }); + + currentRegion = new PartialRegion() + { + Level = newLevel, + StartLine = line.LineNumber, + StartOffset = regionStart, + PartialParent = currentRegion.PartialParent + }; + } + //this is a new (sub)region + else + { + currentRegion = new PartialRegion() + { + Level = newLevel, + StartLine = line.LineNumber, + StartOffset = regionStart, + PartialParent = currentRegion + }; + } + } + //lines that contain "]" denote the end of a region + else if ((regionStart = text.IndexOf(endHide, StringComparison.Ordinal)) != -1) + { + int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; + int closingLevel; + if (!TryGetLevel(text, regionStart, out closingLevel)) + closingLevel = currentLevel; + + //the regions match + if (currentRegion != null && + currentLevel == closingLevel) + { + newRegions.Add(new Region() + { + Level = currentLevel, + StartLine = currentRegion.StartLine, + StartOffset = currentRegion.StartOffset, + EndLine = line.LineNumber + }); + + currentRegion = currentRegion.PartialParent; + } + } + } + + //determine the changed span, and send a changed event with the new spans + List oldSpans = + new List(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot) + .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive) + .Span)); + List newSpans = + new List(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span)); + + NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans); + NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans); + + //the changed regions are regions that appear in one set or the other, but not both. + NormalizedSpanCollection removed = + NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection); + + int changeStart = int.MaxValue; + int changeEnd = -1; + + if (removed.Count > 0) + { + changeStart = removed[0].Start; + changeEnd = removed[removed.Count - 1].End; + } + + if (newSpans.Count > 0) + { + changeStart = Math.Min(changeStart, newSpans[0].Start); + changeEnd = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End); + } + + this.snapshot = newSnapshot; + this.regions = newRegions; + + if (changeStart <= changeEnd) + { + ITextSnapshot snap = this.snapshot; + if (this.TagsChanged != null) + this.TagsChanged(this, new SnapshotSpanEventArgs( + new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd)))); + } + } + + static bool TryGetLevel(string text, int startIndex, out int level) + { + level = -1; + if (text.Length > startIndex + 3) + { + if (int.TryParse(text.Substring(startIndex + 1), out level)) + return true; + } + + return false; + } + + static SnapshotSpan AsSnapshotSpan(Region region, ITextSnapshot snapshot) + { + var startLine = snapshot.GetLineFromLineNumber(region.StartLine); + var endLine = (region.StartLine == region.EndLine) ? startLine + : snapshot.GetLineFromLineNumber(region.EndLine); + return new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); + } + + } + + //class PartialRegion + //{ + // public int StartLine { get; set; } + // public int StartOffset { get; set; } + // public int Level { get; set; } + // public PartialRegion PartialParent { get; set; } + //} + + //class Region : PartialRegion + //{ + // public int EndLine { get; set; } + //} + +} diff --git a/EditorExtensions/Classifications/JavaScriptRegionTagger.cs b/EditorExtensions/Classifications/JavaScriptRegionTagger.cs new file mode 100644 index 000000000..47f828953 --- /dev/null +++ b/EditorExtensions/Classifications/JavaScriptRegionTagger.cs @@ -0,0 +1,244 @@ +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text.RegularExpressions; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ITaggerProvider))] + [TagType(typeof(IOutliningRegionTag))] + [ContentType("javascript")] + //[ContentType("TypeScript")] + [ContentType("LESS")] + internal sealed class RegionTaggerProvider : ITaggerProvider + { + public ITagger CreateTagger(ITextBuffer buffer) where T : ITag + { + return buffer.Properties.GetOrCreateSingletonProperty(() => new RegionTagger(buffer)) as ITagger; + } + } + + internal sealed class RegionTagger : ITagger + { + string startHide = "//#region"; //the characters that start the outlining region + string endHide = "//#endregion"; //the characters that end the outlining region + string hoverText = "Collapsed content"; //the contents of the tooltip for the collapsed span + ITextBuffer buffer; + ITextSnapshot snapshot; + List regions; + private static Regex regex = new Regex(@"\/\/\#region(.*)?", RegexOptions.Compiled); + + public RegionTagger(ITextBuffer buffer) + { + this.buffer = buffer; + this.snapshot = buffer.CurrentSnapshot; + this.regions = new List(); + this.buffer.Changed += BufferChanged; + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => ReParse()), DispatcherPriority.ApplicationIdle, null); + + this.buffer.Changed += BufferChanged; + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0 || !WESettings.GetBoolean(WESettings.Keys.EnableJavascriptRegions)) + yield break; + + List currentRegions = this.regions; + ITextSnapshot currentSnapshot = this.snapshot; + + SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive); + int startLineNumber = entire.Start.GetContainingLine().LineNumber; + int endLineNumber = entire.End.GetContainingLine().LineNumber; + foreach (var region in currentRegions) + { + if (region.StartLine <= endLineNumber && region.EndLine >= startLineNumber) + { + var startLine = currentSnapshot.GetLineFromLineNumber(region.StartLine); + var endLine = currentSnapshot.GetLineFromLineNumber(region.EndLine); + + var snapshot = new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); + Match match = regex.Match(snapshot.GetText()); + + //the region starts at the beginning of the "[", and goes until the *end* of the line that contains the "]". + yield return new TagSpan( + snapshot, + new OutliningRegionTag(false, true, " " + match.Groups[1].Value.Trim() + " ", hoverText)); + } + } + } + + public event EventHandler TagsChanged; + + void BufferChanged(object sender, TextContentChangedEventArgs e) + { + // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). + if (e.After != buffer.CurrentSnapshot) + return; + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => ReParse()), DispatcherPriority.ApplicationIdle, null); + } + + void ReParse() + { + ITextSnapshot newSnapshot = buffer.CurrentSnapshot; + List newRegions = new List(); + + //keep the current (deepest) partial region, which will have + // references to any parent partial regions. + PartialRegion currentRegion = null; + + foreach (var line in newSnapshot.Lines) + { + int regionStart = -1; + string text = line.GetText(); + + //lines that contain a "[" denote the start of a new region. + if ((regionStart = text.IndexOf(startHide, StringComparison.Ordinal)) != -1) + { + int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; + int newLevel; + if (!TryGetLevel(text, regionStart, out newLevel)) + newLevel = currentLevel + 1; + + //levels are the same and we have an existing region; + //end the current region and start the next + if (currentLevel == newLevel && currentRegion != null) + { + newRegions.Add(new Region() + { + Level = currentRegion.Level, + StartLine = currentRegion.StartLine, + StartOffset = currentRegion.StartOffset, + EndLine = line.LineNumber + }); + + currentRegion = new PartialRegion() + { + Level = newLevel, + StartLine = line.LineNumber, + StartOffset = regionStart, + PartialParent = currentRegion.PartialParent + }; + } + //this is a new (sub)region + else + { + currentRegion = new PartialRegion() + { + Level = newLevel, + StartLine = line.LineNumber, + StartOffset = regionStart, + PartialParent = currentRegion + }; + } + } + //lines that contain "]" denote the end of a region + else if ((regionStart = text.IndexOf(endHide, StringComparison.Ordinal)) != -1) + { + int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; + int closingLevel; + if (!TryGetLevel(text, regionStart, out closingLevel)) + closingLevel = currentLevel; + + //the regions match + if (currentRegion != null && + currentLevel == closingLevel) + { + newRegions.Add(new Region() + { + Level = currentLevel, + StartLine = currentRegion.StartLine, + StartOffset = currentRegion.StartOffset, + EndLine = line.LineNumber + }); + + currentRegion = currentRegion.PartialParent; + } + } + } + + //determine the changed span, and send a changed event with the new spans + List oldSpans = + new List(this.regions.Select(r => AsSnapshotSpan(r, this.snapshot) + .TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive) + .Span)); + List newSpans = + new List(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span)); + + NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans); + NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans); + + //the changed regions are regions that appear in one set or the other, but not both. + NormalizedSpanCollection removed = + NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection); + + int changeStart = int.MaxValue; + int changeEnd = -1; + + if (removed.Count > 0) + { + changeStart = removed[0].Start; + changeEnd = removed[removed.Count - 1].End; + } + + if (newSpans.Count > 0) + { + changeStart = Math.Min(changeStart, newSpans[0].Start); + changeEnd = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End); + } + + this.snapshot = newSnapshot; + this.regions = newRegions; + + if (changeStart <= changeEnd) + { + ITextSnapshot snap = this.snapshot; + if (this.TagsChanged != null) + this.TagsChanged(this, new SnapshotSpanEventArgs( + new SnapshotSpan(this.snapshot, Span.FromBounds(changeStart, changeEnd)))); + } + } + + static bool TryGetLevel(string text, int startIndex, out int level) + { + level = -1; + if (text.Length > startIndex + 3) + { + if (int.TryParse(text.Substring(startIndex + 1), out level)) + return true; + } + + return false; + } + + static SnapshotSpan AsSnapshotSpan(Region region, ITextSnapshot snapshot) + { + var startLine = snapshot.GetLineFromLineNumber(region.StartLine); + var endLine = (region.StartLine == region.EndLine) ? startLine + : snapshot.GetLineFromLineNumber(region.EndLine); + return new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); + } + } + + class PartialRegion + { + public int StartLine { get; set; } + public int StartOffset { get; set; } + public int Level { get; set; } + public PartialRegion PartialParent { get; set; } + } + + class Region : PartialRegion + { + public int EndLine { get; set; } + } +} diff --git a/EditorExtensions/Classifications/Markdown/MarkdownClassificationTypes.cs b/EditorExtensions/Classifications/Markdown/MarkdownClassificationTypes.cs new file mode 100644 index 000000000..af93c3bdb --- /dev/null +++ b/EditorExtensions/Classifications/Markdown/MarkdownClassificationTypes.cs @@ -0,0 +1,77 @@ +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; +using System.Windows; + +namespace MadsKristensen.EditorExtensions +{ + class MarkdownClassificationTypes + { + public const string MarkdownBold = "md_bold"; + public const string MarkdownItalic = "md_italic"; + public const string MarkdownHeader = "md_header"; + public const string MarkdownCode = "md_code"; + + [Export, Name(MarkdownClassificationTypes.MarkdownBold), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition MarkdownClassificationBold = null; + + [Export, Name(MarkdownClassificationTypes.MarkdownItalic), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition MarkdownClassificationItalic = null; + + [Export, Name(MarkdownClassificationTypes.MarkdownHeader), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition MarkdownClassificationHeader = null; + + [Export, Name(MarkdownClassificationTypes.MarkdownCode), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition MarkdownClassificationCode = null; + } + + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = MarkdownClassificationTypes.MarkdownBold)] + [Name(MarkdownClassificationTypes.MarkdownBold)] + [Order(After = Priority.Default)] + internal sealed class MarkdownBoldFormatDefinition : ClassificationFormatDefinition + { + public MarkdownBoldFormatDefinition() + { + IsBold = true; + } + } + + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = MarkdownClassificationTypes.MarkdownItalic)] + [Name(MarkdownClassificationTypes.MarkdownItalic)] + [Order(After = Priority.Default)] + internal sealed class MarkdownItalicFormatDefinition : ClassificationFormatDefinition + { + public MarkdownItalicFormatDefinition() + { + IsItalic = true; + } + } + + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = MarkdownClassificationTypes.MarkdownHeader)] + [Name(MarkdownClassificationTypes.MarkdownHeader)] + [Order(After = Priority.Default)] + internal sealed class MarkdownHeaderFormatDefinition : ClassificationFormatDefinition + { + public MarkdownHeaderFormatDefinition() + { + IsBold = true; + TextDecorations = new TextDecorationCollection(); + TextDecorations.Add(new TextDecoration()); + } + } + + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = MarkdownClassificationTypes.MarkdownCode)] + [Name(MarkdownClassificationTypes.MarkdownCode)] + [Order(After = Priority.Default)] + internal sealed class MarkdownCodeFormatDefinition : ClassificationFormatDefinition + { + public MarkdownCodeFormatDefinition() + { + ForegroundColor = System.Windows.Media.Colors.Green; + } + } +} diff --git a/EditorExtensions/Classifications/Markdown/MarkdownClassifier.cs b/EditorExtensions/Classifications/Markdown/MarkdownClassifier.cs new file mode 100644 index 000000000..4df5d7a61 --- /dev/null +++ b/EditorExtensions/Classifications/Markdown/MarkdownClassifier.cs @@ -0,0 +1,70 @@ +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text.RegularExpressions; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IClassifierProvider))] + [ContentType(MarkdownContentTypeDefinition.MarkdownContentType)] + public class MarkdownClassifierProvider : IClassifierProvider + { + [Import] + internal IClassificationTypeRegistryService Registry { get; set; } + + public IClassifier GetClassifier(ITextBuffer textBuffer) + { + return textBuffer.Properties.GetOrCreateSingletonProperty(() => new MarkdownClassifier(Registry)); + } + } + + public class MarkdownClassifier : IClassifier + { + private static readonly Regex _reItalic = new Regex(@"(? GetClassificationSpans(SnapshotSpan span) + { + string text = span.GetText(); + + var bolds = FindMatches(span, text, _reBold, _bold); + var italics = FindMatches(span, text, _reItalic, _italic); + var headers = FindMatches(span, text, _reHeader, _header); + var codes = FindMatches(span, text, _reCode, _code); + + return bolds.Concat(italics).Concat(headers).Concat(codes).ToList(); + } + + private IEnumerable FindMatches(SnapshotSpan span, string text, Regex regex, IClassificationType type) + { + Match match = regex.Match(text); + + while (match.Success) + { + var result = new SnapshotSpan(span.Snapshot, span.Start + match.Index, match.Length); + yield return new ClassificationSpan(result, type); + + match = regex.Match(text, match.Index + match.Length); + } + } + + public event EventHandler ClassificationChanged; + } + +} diff --git a/EditorExtensions/Classifications/Markdown/MarkdownContentTypeDefinition.cs b/EditorExtensions/Classifications/Markdown/MarkdownContentTypeDefinition.cs new file mode 100644 index 000000000..9d46e7229 --- /dev/null +++ b/EditorExtensions/Classifications/Markdown/MarkdownContentTypeDefinition.cs @@ -0,0 +1,39 @@ +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + /// + /// Exports the ScSS content type and file extension + /// + public class MarkdownContentTypeDefinition + { + public const string MarkdownContentType = "markdown"; + + /// + /// Exports the Markdown HTML content type + /// + [Export(typeof(ContentTypeDefinition))] + [Name(MarkdownContentType)] + [BaseDefinition("html")] + public ContentTypeDefinition IMarkdownContentType { get; set; } + + /// + /// Exports the markdown file extension + /// + [Export(typeof(FileExtensionToContentTypeDefinition))] + [ContentType(MarkdownContentType)] + [FileExtension(".md")] + public FileExtensionToContentTypeDefinition IMDFileExtension { get; set; } + + [Export(typeof(FileExtensionToContentTypeDefinition))] + [ContentType(MarkdownContentType)] + [FileExtension(".mdown")] + public FileExtensionToContentTypeDefinition IMDownFileExtension { get; set; } + + [Export(typeof(FileExtensionToContentTypeDefinition))] + [ContentType(MarkdownContentType)] + [FileExtension(".markdown")] + public FileExtensionToContentTypeDefinition IMarkDownFileExtension { get; set; } + } +} diff --git a/EditorExtensions/Classifications/ModernizrClassifier.cs b/EditorExtensions/Classifications/ModernizrClassifier.cs new file mode 100644 index 000000000..0f8b3ed86 --- /dev/null +++ b/EditorExtensions/Classifications/ModernizrClassifier.cs @@ -0,0 +1,160 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal static class ModernizrClassificationTypes + { + internal const string _modernizr = "modernizr"; + + [Export, Name(ModernizrClassificationTypes._modernizr), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition ModernizrClassificationType = null; + } + + [Export(typeof(IClassifierProvider))] + [ContentType("css")] + internal sealed class ModernizrClassifierProvider : IClassifierProvider + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IClassificationTypeRegistryService Registry { get; set; } + + public IClassifier GetClassifier(ITextBuffer buffer) + { + return buffer.Properties.GetOrCreateSingletonProperty(() => { return new ModernizrClassifier(Registry, buffer); }); + } + } + + internal sealed class ModernizrClassifier : IClassifier + { + private IClassificationTypeRegistryService _registry; + private ITextBuffer _buffer; + private CssTree _tree; + internal SortedRangeList Cache = new SortedRangeList(); + private IClassificationType _modernizrClassification; + + internal ModernizrClassifier(IClassificationTypeRegistryService registry, ITextBuffer buffer) + { + _registry = registry; + _buffer = buffer; + _modernizrClassification = _registry.GetClassificationType(ModernizrClassificationTypes._modernizr); + } + + public IList GetClassificationSpans(SnapshotSpan span) + { + List spans = new List(); + + if (!EnsureInitialized()) + return spans; + + foreach (SimpleSelector selector in Cache) + { + int start = span.Start.Position; + int end = span.End.Position; + + if (selector.Start >= start && selector.AfterEnd <= end) + { + var snapShotSpan = new SnapshotSpan(span.Snapshot, selector.Start, selector.Length); + var classSpan = new ClassificationSpan(snapShotSpan, _modernizrClassification); + spans.Add(classSpan); + } + } + + return spans; + } + + public bool EnsureInitialized() + { + if (_tree == null && WebEditor.Host != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + _tree.TreeUpdated += TreeUpdated; + _tree.ItemsChanged += TreeItemsChanged; + UpdateCache(_tree.StyleSheet); + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + + private void UpdateCache(ParseItem item) + { + var visitor = new CssItemCollector(true); + item.Accept(visitor); + + foreach (SimpleSelector ss in visitor.Items) + { + string text = ss.Text; + + if (ModernizrProvider.IsModernizr(text)) + { + if (!Cache.Contains(ss)) + Cache.Add(ss); + } + } + } + + private void TreeUpdated(object sender, CssTreeUpdateEventArgs e) + { + Cache.Clear(); + UpdateCache(e.Tree.StyleSheet); + } + + private void TreeItemsChanged(object sender, CssItemsChangedEventArgs e) + { + foreach (ParseItem item in e.DeletedItems) + { + var matches = Cache.Where(s => s.Start >= item.Start && s.AfterEnd <= item.AfterEnd); + foreach (var match in matches.Reverse()) + { + Cache.Remove(match); + } + } + + foreach (ParseItem item in e.InsertedItems) + { + UpdateCache(item); + } + } + + public event EventHandler ClassificationChanged; + + public void RaiseClassificationChanged(SnapshotSpan span) + { + var handler = this.ClassificationChanged; + if (handler != null) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => handler(this, new ClassificationChangedEventArgs(span))), DispatcherPriority.ApplicationIdle); + } + } + } + + [Export(typeof(EditorFormatDefinition))] + [UserVisible(true)] + [ClassificationType(ClassificationTypeNames = ModernizrClassificationTypes._modernizr)] + [Name(ModernizrClassificationTypes._modernizr)] + [Order(After = Priority.Default)] + internal sealed class ModernizrFormatDefinition : ClassificationFormatDefinition + { + public ModernizrFormatDefinition() + { + IsBold = true; + DisplayName = "CSS Modernizr selector"; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Classifications/SCSS/ScssClassifierProvider.cs b/EditorExtensions/Classifications/SCSS/ScssClassifierProvider.cs new file mode 100644 index 000000000..960db0504 --- /dev/null +++ b/EditorExtensions/Classifications/SCSS/ScssClassifierProvider.cs @@ -0,0 +1,27 @@ +//using System.ComponentModel.Composition; +//using Microsoft.CSS.Editor; +//using Microsoft.VisualStudio.Text; +//using Microsoft.VisualStudio.Text.Classification; +//using Microsoft.VisualStudio.Utilities; +//using Microsoft.Web.Editor; + +//namespace MadsKristensen.EditorExtensions +//{ +// [Export(typeof(IClassifierProvider))] +// [ContentType(ScssContentTypeDefinition.ScssContentType)] +// internal sealed class ScssClassificationProvider : IClassifierProvider +// { +// [Import] +// public IClassificationTypeRegistryService ClassificationRegistryService { get; set; } + +// public IClassifier GetClassifier(ITextBuffer textBuffer) +// { +// var classifier = ServiceManager.GetService(textBuffer); + +// if (classifier == null) +// classifier = new CssClassifier(textBuffer, new CssClassificationNameProvider(), ClassificationRegistryService); + +// return classifier; +// } +// } +//} diff --git a/EditorExtensions/Classifications/SCSS/ScssContentTypeDefinition.cs b/EditorExtensions/Classifications/SCSS/ScssContentTypeDefinition.cs new file mode 100644 index 000000000..5a5ca43ce --- /dev/null +++ b/EditorExtensions/Classifications/SCSS/ScssContentTypeDefinition.cs @@ -0,0 +1,31 @@ +//using Microsoft.VisualStudio.Utilities; +//using System.ComponentModel.Composition; + +//namespace MadsKristensen.EditorExtensions +//{ +// /// +// /// Exports the ScSS content type and file extension +// /// +// public class ScssContentTypeDefinition +// { +// public const string ScssLanguageName = "scss"; +// public const string ScssContentType = "scss"; +// public const string ScssFileExtension = ".scss"; + +// /// +// /// Exports the SaSS CSS content type +// /// +// [Export(typeof(ContentTypeDefinition))] +// [Name(ScssContentType)] +// [BaseDefinition("LESS")] +// public ContentTypeDefinition IScssContentType { get; set; } + +// /// +// /// Exports the SaSS file extension +// /// +// [Export(typeof(FileExtensionToContentTypeDefinition))] +// [ContentType(ScssContentType)] +// [FileExtension(ScssFileExtension)] +// public FileExtensionToContentTypeDefinition IScssFileExtension { get; set; } +// } +//} diff --git a/EditorExtensions/Classifications/ValueTaggerProvider.cs b/EditorExtensions/Classifications/ValueTaggerProvider.cs new file mode 100644 index 000000000..f8223f802 --- /dev/null +++ b/EditorExtensions/Classifications/ValueTaggerProvider.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Windows.Threading; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IViewTaggerProvider))] + [ContentType("css")] + [TagType(typeof(TextMarkerTag))] + internal class VendorTaggerProvider : IViewTaggerProvider + { + [Import] + internal IClassifierAggregatorService AggregatorFactory = null; + + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + { + if (textView == null || !WESettings.GetBoolean(WESettings.Keys.SyncVendorValues)) + { + return null; + } + + if (textView.TextBuffer != buffer) + { + return null; + } + + Func> sc = delegate() { return new VendorTagger(textView, buffer, this) as ITagger; }; + return buffer.Properties.GetOrCreateSingletonProperty>(sc); + } + } + + internal class VendorTagger : ITagger + { + ITextView View { get; set; } + ITextBuffer Buffer { get; set; } + SnapshotPoint? CurrentChar { get; set; } + VendorTaggerProvider Provider { get; set; } + readonly IClassifier _classifier; + private VendorClassifier _vendorClassifier; + private bool _pendingUpdate = false; + + internal VendorTagger(ITextView view, ITextBuffer buffer, VendorTaggerProvider provider) + { + View = view; + Buffer = buffer; + CurrentChar = null; + Provider = provider; + _classifier = provider.AggregatorFactory.GetClassifier(buffer); + buffer.Properties.TryGetProperty(typeof(VendorClassifier), out _vendorClassifier); + + View.Caret.PositionChanged += CaretPositionChanged; + View.LayoutChanged += ViewLayoutChanged; + } + + public event EventHandler TagsChanged; + + void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) + { + if (e.NewSnapshot != e.OldSnapshot) + { + UpdateAtCaretPosition(View.Caret.Position); + } + } + + void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e) + { + UpdateAtCaretPosition(e.NewPosition); + } + + void UpdateAtCaretPosition(CaretPosition caretPosition) + { + if (!_pendingUpdate) + { + _pendingUpdate = true; + CurrentChar = caretPosition.Point.GetPoint(this.Buffer, caretPosition.Affinity); + if (!CurrentChar.HasValue) + { + return; + } + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => Update()), DispatcherPriority.ContextIdle); + } + } + + private void Update() + { + var tempEvent = TagsChanged; + if (tempEvent != null) + { + SnapshotSpan span = new SnapshotSpan(this.Buffer.CurrentSnapshot, 0, this.Buffer.CurrentSnapshot.Length); + tempEvent(this, new SnapshotSpanEventArgs(span)); + _pendingUpdate = false; + } + } + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (spans.Count == 0 || Buffer.CurrentSnapshot.Length == 0) + yield break; + + if (!CurrentChar.HasValue || CurrentChar.Value.Position >= CurrentChar.Value.Snapshot.Length) + yield break; + + SnapshotPoint currentChar = CurrentChar.Value; + if (spans[0].Snapshot != currentChar.Snapshot) + { + currentChar = currentChar.TranslateTo(spans[0].Snapshot, PointTrackingMode.Positive); + } + + var allTags = _vendorClassifier.GetClassificationSpans(spans[0]).Where(s => s.ClassificationType.Classification == ClassificationTypes._value); + foreach (var tagSpan in allTags) + { + if (tagSpan.Span.Contains(currentChar)) + { + Declaration dec = _vendorClassifier.Cache.FirstOrDefault(e => currentChar.Position > e.Start && currentChar.Position < e.AfterEnd); + if (dec != null && dec.PropertyName.Text.Length > 0 && !dec.IsVendorSpecific()) + { + foreach (Declaration vendor in _vendorClassifier.Cache.Where(d => d.Parent == dec.Parent && _vendorClassifier.GetStandardName(d) == dec.PropertyName.Text)) + { + // Manage quotes for -ms-filter + string value = Buffer.CurrentSnapshot.GetText(vendor.Colon.AfterEnd, vendor.AfterEnd - vendor.Colon.AfterEnd); + int quotes = value.StartsWith("'") || value.StartsWith("\"") ? 1 : 0; + SnapshotSpan vendorSpan = new SnapshotSpan(Buffer.CurrentSnapshot, vendor.Colon.AfterEnd + quotes, vendor.AfterEnd - vendor.Colon.AfterEnd - (quotes * 2)); + yield return new TagSpan(vendorSpan, new TextMarkerTag("vendorhighlight")); + } + + SnapshotSpan s = tagSpan.Span; + yield return new TagSpan(s, new TextMarkerTag("vendorhighlight")); + yield break; + } + } + } + } + } + + [Export(typeof(EditorFormatDefinition))] + [Name("vendorhighlight")] + [UserVisible(true)] + internal class HighlightWordFormatDefinition : MarkerFormatDefinition + { + public HighlightWordFormatDefinition() + { + this.DisplayName = "CSS Property Value Highlight"; + } + + } +} \ No newline at end of file diff --git a/EditorExtensions/Classifications/VendorClassifier.cs b/EditorExtensions/Classifications/VendorClassifier.cs new file mode 100644 index 000000000..2532e1fb8 --- /dev/null +++ b/EditorExtensions/Classifications/VendorClassifier.cs @@ -0,0 +1,235 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal static class ClassificationTypes + { + internal const string _declaration = "vendor.declaration"; + internal const string _value = "vendor.value"; + + [Export, Name(ClassificationTypes._declaration), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition VendorDeclarationClassificationType = null; + + [Export, Name(ClassificationTypes._value), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + internal static ClassificationTypeDefinition VendorValueClassificationType = null; + } + + [Export(typeof(IClassifierProvider))] + [ContentType("css")] + internal sealed class VendorClassifierProvider : IClassifierProvider + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IClassificationTypeRegistryService Registry { get; set; } + + public IClassifier GetClassifier(ITextBuffer buffer) + { + return buffer.Properties.GetOrCreateSingletonProperty(() => { return new VendorClassifier(Registry, buffer); }); + } + } + + internal sealed class VendorClassifier : IClassifier + { + private IClassificationTypeRegistryService _registry; + private ITextBuffer _buffer; + private CssTree _tree; + internal SortedRangeList Cache = new SortedRangeList(); + private IClassificationType _decClassification; + private IClassificationType _valClassification; + + internal VendorClassifier(IClassificationTypeRegistryService registry, ITextBuffer buffer) + { + _registry = registry; + _buffer = buffer; + _decClassification = _registry.GetClassificationType(ClassificationTypes._declaration); + _valClassification = _registry.GetClassificationType(ClassificationTypes._value); + } + + public IList GetClassificationSpans(SnapshotSpan span) + { + List spans = new List(); + if (!WESettings.GetBoolean(WESettings.Keys.SyncVendorValues) || !EnsureInitialized()) + return spans; + + var declarations = Cache.Where(d => span.End <= d.AfterEnd && d.Start >= span.Start); + foreach (Declaration dec in Cache.Where(d => d.PropertyName.Text.Length > 0 && span.Snapshot.Length >= d.AfterEnd)) + { + if (dec.IsVendorSpecific()) + { + var ss = new SnapshotSpan(span.Snapshot, dec.Start, dec.Length); + var s = new ClassificationSpan(ss, _decClassification); + spans.Add(s); + } + + int start = dec.Colon.AfterEnd; + int length = dec.AfterEnd - start; + if (span.Snapshot.Length > start + length) + { + var ss2 = new SnapshotSpan(span.Snapshot, start, length); + var s2 = new ClassificationSpan(ss2, _valClassification); + spans.Add(s2); + } + } + + return spans; + } + + public string GetStandardName(Declaration dec) + { + string name = dec.PropertyName.Text; + if (name.Length > 0 && name[0] == '-') + { + int index = name.IndexOf('-', 1) + 1; + name = index > -1 ? name.Substring(index) : name; + } + + return name; + } + + public bool EnsureInitialized() + { + if (_tree == null && WebEditor.Host != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + _tree.TreeUpdated += TreeUpdated; + _tree.ItemsChanged += TreeItemsChanged; + UpdateDeclarationCache(_tree.StyleSheet); + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + + private void UpdateDeclarationCache(ParseItem item) + { + var visitor = new CssItemCollector(true); + item.Accept(visitor); + + HashSet rules = new HashSet(); + + foreach (Declaration dec in visitor.Items) + { + RuleBlock rule = dec.Parent as RuleBlock; + if (rule == null || rules.Contains(rule)) + continue; + + var vendors = rule.Declarations.Where(d => d.IsValid && d.IsVendorSpecific()); + foreach (Declaration vendor in vendors) + { + string name = GetStandardName(vendor); + Declaration standard = rule.Declarations.FirstOrDefault(d => d.IsValid && d.PropertyName.Text == name); + + if (standard != null) + { + if (!Cache.Contains(standard)) + Cache.Add(standard); + + if (GetValueText(standard) == GetValueText(vendor) && !Cache.Contains(vendor)) + Cache.Add(vendor); + } + } + + rules.Add(rule); + } + } + + private void TreeUpdated(object sender, CssTreeUpdateEventArgs e) + { + Cache.Clear(); + UpdateDeclarationCache(e.Tree.StyleSheet); + } + + private void TreeItemsChanged(object sender, CssItemsChangedEventArgs e) + { + foreach (ParseItem item in e.DeletedItems) + { + if (Cache.Contains(item)) + Cache.Remove((Declaration)item); + } + + foreach (ParseItem item in e.InsertedItems) + { + UpdateDeclarationCache(item); + UpdateVendorValues(item); + } + } + + private void UpdateVendorValues(ParseItem item) + { + if (!WESettings.GetBoolean(WESettings.Keys.SyncVendorValues)) + return; + + Declaration dec = item.FindType(); + if (dec != null && Cache.Contains(dec) && !dec.IsVendorSpecific()) + { + // Find all vendor specifics that isn't the standard property. + var matches = Cache.Where(d => d.IsValid && d != dec && d.Parent == dec.Parent && GetStandardName(d) == dec.PropertyName.Text && d.PropertyName.Text != dec.PropertyName.Text); + + // Undo sometimes messes with the positions, so we have to make this check before proceeding. + if (!matches.Any() || dec.Text.Length < dec.Colon.AfterEnd - dec.Start || dec.Colon.AfterEnd < dec.Start) + return; + + string text = dec.Text.Substring(dec.Colon.AfterEnd - dec.Start, dec.AfterEnd - dec.Colon.AfterEnd); + using (ITextEdit edit = _buffer.CreateEdit()) + { + foreach (Declaration match in matches.Reverse()) + { + SnapshotSpan span = new SnapshotSpan(_buffer.CurrentSnapshot, match.Colon.AfterEnd, match.AfterEnd - match.Colon.AfterEnd); + if (span.GetText() != text) + edit.Replace(span, text); + } + + edit.Apply(); + } + } + } + + private string GetValueText(Declaration dec) + { + int start = dec.Colon.AfterEnd; + int length = dec.AfterEnd - start; + return _buffer.CurrentSnapshot.GetText(start, length); + } + + public event EventHandler ClassificationChanged; + + public void RaiseClassificationChanged(SnapshotSpan span) + { + var handler = this.ClassificationChanged; + if (handler != null) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => handler(this, new ClassificationChangedEventArgs(span))), DispatcherPriority.ApplicationIdle); + } + } + } + + [Export(typeof(EditorFormatDefinition))] + [UserVisible(true)] + [ClassificationType(ClassificationTypeNames = ClassificationTypes._declaration)] + [Name(ClassificationTypes._declaration)] + [Order(After = Priority.Default)] + internal sealed class VendorDeclarationFormatDefinition : ClassificationFormatDefinition + { + public VendorDeclarationFormatDefinition() + { + ForegroundOpacity = 0.5; + DisplayName = "CSS Vendor Property"; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/ArrowsCommandTarget.cs b/EditorExtensions/Commands/ArrowsCommandTarget.cs new file mode 100644 index 000000000..4b741d5ef --- /dev/null +++ b/EditorExtensions/Commands/ArrowsCommandTarget.cs @@ -0,0 +1,273 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System; +using System.ComponentModel.Composition; +using System.Globalization; +using Editor = Microsoft.Web.Editor; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType(Microsoft.Web.Editor.CssContentTypeDefinition.CssContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + class NumberTextViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + textView.Properties.GetOrCreateSingletonProperty(() => new NumberTarget(textViewAdapter, textView)); + } + } + + class NumberTarget : IOleCommandTarget + { + private ITextView _textView; + private IOleCommandTarget _nextCommandTarget; + private CssTree _tree; + + public NumberTarget(IVsTextView adapter, ITextView textView) + { + this._textView = textView; + adapter.AddCommandFilter(this, out _nextCommandTarget); + } + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + switch (nCmdID) + { + case 2400: + if (Move(Direction.Down)) + return VSConstants.S_OK; + break; + + case 2401: + if (Move(Direction.Up)) + return VSConstants.S_OK; + break; + } + } + + return _nextCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + } + + private enum Direction + { + Up, + Down + } + + private bool Move(Direction direction) + { + if (!EnsureInitialized()) + return false; + + int position = _textView.Caret.Position.BufferPosition.Position; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(position); + if (item == null) + return false; + + NumericalValue unit = item.FindType(); + if (unit != null) + { + return HandleUnits(direction, unit); + } + + HexColorValue hex = item.FindType(); + if (hex != null) + { + return HandleHex(direction, hex); + } + + return false; + } + + private bool HandleUnits(Direction direction, NumericalValue item) + { + float value; + if (!float.TryParse(item.Number.Text, out value)) + return false; + + if (!AreWithinLimits(direction, value, item)) + return true; + + var span = new SnapshotSpan(_textView.Selection.SelectedSpans[0].Snapshot, item.Number.Start, item.Number.Length); + float delta = GetDelta(item.Number.Text); + string format = item.Number.Text.Contains(".") ? "#.#0" : string.Empty; + if (NumberDecimalPlaces(item.Number.Text) == 1) + format = "F1"; + + if (direction == Direction.Down) + UpdateSpan(span, (value - delta).ToString(format, CultureInfo.InvariantCulture), "Decrease value"); + else + UpdateSpan(span, (value + delta).ToString(format, CultureInfo.InvariantCulture), "Increase value"); + + return true; + } + + private static int NumberDecimalPlaces(string value) + { + if (value.IndexOf('.') == -1) + return 0; + + int s = value.IndexOf(".") + 1; // the first numbers plus decimal point + return value.Length - s; //total length minus beginning numbers and decimal = number of decimal points + } + + private static bool AreWithinLimits(Direction direction, float number, NumericalValue item) + { + UnitType type = GetUnitType(item); + switch (type) + { + case UnitType.Angle: + return (direction == Direction.Up) ? number < 360 : number > -360; + + //case UnitType.Percentage: + // return (direction == Direction.Up) ? number < 100 : number > 0; + + // Larger than zero + case UnitType.Grid: + case UnitType.Frequency: + case UnitType.Resolution: + case UnitType.Time: + return (direction == Direction.Down) ? number > 0 : true; + + case UnitType.Percentage: + case UnitType.Length: + case UnitType.Viewport: + return true; + } + + FunctionColor func = item.FindType(); + if (func != null) + { + if (func.FunctionName.Text.StartsWith("rgb", StringComparison.Ordinal)) + { + if (direction == Direction.Up) + return number < 255; + else + return number > 0; + } + + if (func.FunctionName.Text.StartsWith("hsl", StringComparison.Ordinal)) + { + if (direction == Direction.Up) + return number < 360; + else + return number > 0; + } + } + + return true; + } + + private static UnitType GetUnitType(ParseItem valueItem) + { + UnitValue unitValue = valueItem as UnitValue; + + return (unitValue != null) ? unitValue.UnitType : UnitType.Unknown; + } + + private bool HandleHex(Direction direction, HexColorValue item) + { + var model = ColorParser.TryParseColor(item.Text, ColorParser.Options.None); + + if (model != null) + { + var span = new SnapshotSpan(_textView.Selection.SelectedSpans[0].Snapshot, item.Start, item.Length); + + if (direction == Direction.Down && model.HslLightness > 0) + { + model.Format = Editor.ColorFormat.RgbHex3; + UpdateSpan(span, Editor.ColorFormatter.FormatColor(model.Darken()), "Darken color"); + } + else if (direction == Direction.Up && model.HslLightness < 1) + { + model.Format = Editor.ColorFormat.RgbHex3; + UpdateSpan(span, Editor.ColorFormatter.FormatColor(model.Brighten()), "Brighten color"); + } + + return true; + } + + return false; + } + + private static float GetDelta(string value) + { + int decimals = NumberDecimalPlaces(value); + if (decimals > 0) + { + if (decimals > 1) + return 0.01F; + else + return 0.1F; + } + + return 1F; + } + + private void UpdateSpan(SnapshotSpan span, string result, string undoTitle) + { + if (result.Length > 1) + result = result.TrimStart('0'); + + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + EditorExtensionsPackage.DTE.UndoContext.Open(undoTitle); + edit.Replace(span, result); + edit.Apply(); + EditorExtensionsPackage.DTE.UndoContext.Close(); + } + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + for (int i = 0; i < cCmds; i++) + { + switch (prgCmds[i].cmdID) + { + case 2401: // Up + case 2400: // Down + prgCmds[i].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); + return VSConstants.S_OK; + } + } + } + + return _nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } + + public bool EnsureInitialized() + { + if (_tree == null && Microsoft.Web.Editor.WebEditor.Host != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_textView.TextBuffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/CommandTargetBase.cs b/EditorExtensions/Commands/CommandTargetBase.cs new file mode 100644 index 000000000..4d2c7dcb5 --- /dev/null +++ b/EditorExtensions/Commands/CommandTargetBase.cs @@ -0,0 +1,67 @@ +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal abstract class CommandTargetBase : IOleCommandTarget + { + private IOleCommandTarget _nextCommandTarget; + protected IWpfTextView TextView; + + public Guid CommandGroup { get; set; } + public uint[] CommandIds { get; set; } + + public CommandTargetBase(IVsTextView adapter, IWpfTextView textView, Guid commandGroup, params uint[] commandIds) + { + this.CommandGroup = commandGroup; + this.CommandIds = commandIds; + this.TextView = textView; + adapter.AddCommandFilter(this, out _nextCommandTarget); + } + + protected abstract bool IsEnabled(); + protected abstract bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == this.CommandGroup && this.CommandIds.Contains(nCmdID)) + { + bool result = Execute(nCmdID, nCmdexecopt, pvaIn, pvaOut); + + if (result) + { + return VSConstants.S_OK; + } + } + + return _nextCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + if (pguidCmdGroup == CommandGroup) + { + for (int i = 0; i < cCmds; i++) + { + if (CommandIds.Contains(prgCmds[i].cmdID)) + { + if (IsEnabled()) + { + prgCmds[i].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); + return VSConstants.S_OK; + } + + prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED;// | (uint)OLECMDF.OLECMDF_INVISIBLE; + //return VSConstants.S_OK; + } + } + } + + return _nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } + } +} diff --git a/EditorExtensions/Commands/Css/CssAddMissingStandardCommandTarget.cs b/EditorExtensions/Commands/Css/CssAddMissingStandardCommandTarget.cs new file mode 100644 index 000000000..cb822fa46 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssAddMissingStandardCommandTarget.cs @@ -0,0 +1,105 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssAddMissingStandard : CommandTargetBase + { + private DTE2 _dte; + private readonly string[] _supported = new[] { "CSS", "LESS" }; + + public CssAddMissingStandard(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidCssCmdSet, PkgCmdIDList.addMissingStandard) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + ITextBuffer buffer = TextView.TextBuffer; + CssEditorDocument doc = new CssEditorDocument(buffer); + ICssSchemaInstance rootSchema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + + StringBuilder sb = new StringBuilder(buffer.CurrentSnapshot.Length); + sb.Append(buffer.CurrentSnapshot.GetText()); + + EditorExtensionsPackage.DTE.UndoContext.Open("Add Missing Standard Property"); + + string result = AddMissingStandardDeclaration(sb, doc, rootSchema); + Span span = new Span(0, buffer.CurrentSnapshot.Length); + buffer.Replace(span, result); + + var selection = EditorExtensionsPackage.DTE.ActiveDocument.Selection as TextSelection; + selection.GotoLine(1); + + EditorExtensionsPackage.DTE.ExecuteCommand("Edit.FormatDocument"); + EditorExtensionsPackage.DTE.UndoContext.Close(); + + return true; + } + + private string AddMissingStandardDeclaration(StringBuilder sb, CssEditorDocument doc, ICssSchemaInstance rootSchema) + { + var visitor = new CssItemCollector(true); + doc.Tree.StyleSheet.Accept(visitor); + + //var items = visitor.Items.Where(d => d.IsValid && d.IsVendorSpecific()); + foreach (RuleBlock rule in visitor.Items.Reverse()) + { + HashSet list = new HashSet(); + foreach (Declaration dec in rule.Declarations.Where(d => d.IsValid && d.IsVendorSpecific()).Reverse()) + { + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, dec); + ICssCompletionListEntry entry = VendorHelpers.GetMatchingStandardEntry(dec, schema); + + if (entry != null && !list.Contains(entry.DisplayText) && !rule.Declarations.Any(d => d.PropertyName != null && d.PropertyName.Text == entry.DisplayText)) + { + int index = dec.Text.IndexOf(":", StringComparison.Ordinal); + string standard = entry.DisplayText + dec.Text.Substring(index); + + sb.Insert(dec.AfterEnd, standard); + list.Add(entry.DisplayText); + } + } + } + + return sb.ToString(); + } + + private string GetVendorDeclarations(IEnumerable prefixes, Declaration declaration) + { + StringBuilder sb = new StringBuilder(); + string separator = true ? Environment.NewLine : " "; + + foreach (var entry in prefixes) + { + sb.Append(entry + declaration.Text + separator); + } + + return sb.ToString(); + } + + protected override bool IsEnabled() + { + var buffer = ProjectHelpers.GetCurentTextBuffer(); + + if (buffer != null && _supported.Contains(buffer.ContentType.DisplayName.ToUpperInvariant())) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssAddVendorStandardCommandTarget.cs b/EditorExtensions/Commands/Css/CssAddVendorStandardCommandTarget.cs new file mode 100644 index 000000000..3fb975d34 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssAddVendorStandardCommandTarget.cs @@ -0,0 +1,100 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssAddMissingVendor : CommandTargetBase + { + private DTE2 _dte; + private readonly string[] _supported = new[] { "CSS", "LESS" }; + + public CssAddMissingVendor(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidCssCmdSet, PkgCmdIDList.addMissingVendor) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + ITextBuffer buffer = ProjectHelpers.GetCurentTextBuffer(); + CssEditorDocument doc = new CssEditorDocument(buffer); + ICssSchemaInstance rootSchema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + + StringBuilder sb = new StringBuilder(buffer.CurrentSnapshot.Length); + sb.Append(buffer.CurrentSnapshot.GetText()); + + EditorExtensionsPackage.DTE.UndoContext.Open("Add Missing Vendor Specifics"); + + string result = AddMissingVendorDeclarations(sb, doc, rootSchema); + Span span = new Span(0, buffer.CurrentSnapshot.Length); + buffer.Replace(span, result); + + var selection = EditorExtensionsPackage.DTE.ActiveDocument.Selection as TextSelection; + selection.GotoLine(1); + + EditorExtensionsPackage.DTE.ExecuteCommand("Edit.FormatDocument"); + EditorExtensionsPackage.DTE.UndoContext.Close(); + + return true; + } + + private string AddMissingVendorDeclarations(StringBuilder sb, CssEditorDocument doc, ICssSchemaInstance rootSchema) + { + var visitor = new CssItemCollector(true); + doc.Tree.StyleSheet.Accept(visitor); + + var items = visitor.Items.Where(d => d.IsValid && !d.IsVendorSpecific() && d.PropertyName.Text != "filter"); + + foreach (Declaration dec in items.Reverse()) + { + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, dec); + var missingEntries = dec.GetMissingVendorSpecifics(schema); + + if (missingEntries.Any()) + { + var missingPrefixes = missingEntries.Select(e => e.Substring(0, e.IndexOf('-', 1) + 1)); + string vendors = GetVendorDeclarations(missingPrefixes, dec); + + sb.Insert(dec.Start, vendors); + } + } + + return sb.ToString(); + } + + private string GetVendorDeclarations(IEnumerable prefixes, Declaration declaration) + { + StringBuilder sb = new StringBuilder(); + string separator = true ? Environment.NewLine : " "; + + foreach (var entry in prefixes) + { + sb.Append(entry + declaration.Text + separator); + } + + return sb.ToString(); + } + + protected override bool IsEnabled() + { + var buffer = ProjectHelpers.GetCurentTextBuffer(); + + if (buffer != null && _supported.Contains(buffer.ContentType.DisplayName.ToUpperInvariant())) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssCreationListener.cs b/EditorExtensions/Commands/Css/CssCreationListener.cs new file mode 100644 index 000000000..f4c5f2b00 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssCreationListener.cs @@ -0,0 +1,53 @@ +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType(CssContentTypeDefinition.CssContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + class CssSortPropertiesViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + [Import] + internal IClassifierAggregatorService AggregatorService { get; set; } + + [Import] + internal ICompletionBroker CompletionBroker { get; set; } + + [Import] + internal IQuickInfoBroker QuickInfoBroker { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + + textView.Properties.GetOrCreateSingletonProperty(() => new CssSortProperties(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssExtractToFile(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssAddMissingStandard(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssAddMissingVendor(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssRemoveDuplicates(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new MinifySelection(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssFindReferences(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new F1Help(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssSelectBrowsers(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new RetriggerTarget(textViewAdapter, textView, CompletionBroker)); + + uint cssFormatProperties; + EditorExtensionsPackage.PriorityCommandTarget.RegisterPriorityCommandTarget(0, new CssFormatProperties(textView), out cssFormatProperties); + textView.Closed += delegate { EditorExtensionsPackage.PriorityCommandTarget.UnregisterPriorityCommandTarget(cssFormatProperties); }; + + uint cssSpeedTyping; + EditorExtensionsPackage.PriorityCommandTarget.RegisterPriorityCommandTarget(0, new SpeedTypingTarget(this, textViewAdapter, textView), out cssSpeedTyping); + textView.Closed += delegate { EditorExtensionsPackage.PriorityCommandTarget.UnregisterPriorityCommandTarget(cssSpeedTyping); }; + } + } +} diff --git a/EditorExtensions/Commands/Css/CssExtractToFileCommandTarget.cs b/EditorExtensions/Commands/Css/CssExtractToFileCommandTarget.cs new file mode 100644 index 000000000..62979a973 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssExtractToFileCommandTarget.cs @@ -0,0 +1,118 @@ +using EnvDTE80; +using Microsoft.VisualBasic; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Projection; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssExtractToFile : CommandTargetBase + { + private DTE2 _dte; + private List _possible = new List() { ".CSS", ".LESS", ".JS", ".TS" }; + + public CssExtractToFile(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidExtractCmdSet, PkgCmdIDList.ExtractSelection) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (TextView == null) + return false; + + string content = TextView.Selection.SelectedSpans[0].GetText(); + string extension = Path.GetExtension(_dte.ActiveDocument.FullName).ToLowerInvariant(); + + if (!_possible.Contains(extension.ToUpperInvariant())) + { + extension = ".css"; + } + + string name = Interaction.InputBox("Specify the name of the file", "Web Essentials", "file1" + extension).Trim(); + + if (!string.IsNullOrEmpty(name)) + { + + if (string.IsNullOrEmpty(Path.GetExtension(name))) + { + name = name + extension; + } + + string fileName = Path.Combine(Path.GetDirectoryName(_dte.ActiveDocument.FullName), name); + + if (!File.Exists(fileName)) + { + _dte.UndoContext.Open("Extract to file..."); + + using (StreamWriter writer = new StreamWriter(fileName, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + + ProjectHelpers.AddFileToActiveProject(fileName); + TextView.TextBuffer.Delete(TextView.Selection.SelectedSpans[0].Span); + _dte.ItemOperations.OpenFile(fileName); + + _dte.UndoContext.Close(); + } + else + { + MessageBox.Show("The file already exist", "Web Essentials", MessageBoxButton.OK, MessageBoxImage.Warning); + } + } + + return true; + } + + private bool IsValidTextBuffer(IWpfTextView view) + { + var projection = view.TextBuffer as IProjectionBuffer; + + if (projection != null) + { + int position = view.Caret.Position.BufferPosition.Position; + var snapshotPoint = view.Caret.Position.BufferPosition; + + var buffers = projection.SourceBuffers.Where(s => + s.ContentType.IsOfType("css") || + s.ContentType.IsOfType("javascript")); + + foreach (ITextBuffer buffer in buffers) + { + SnapshotPoint? point = view.BufferGraph.MapDownToBuffer(snapshotPoint, PointTrackingMode.Negative, buffer, PositionAffinity.Predecessor); + + if (point.HasValue) + { + return true; + } + } + + return false; + } + + return true; + } + + protected override bool IsEnabled() + { + var item = _dte.Solution.FindProjectItem(_dte.ActiveDocument.FullName); + bool hasProject = item != null && item.ContainingProject != null && !string.IsNullOrEmpty(item.ContainingProject.FullName); + + if (hasProject && TextView != null && IsValidTextBuffer(TextView) && TextView.Selection.SelectedSpans.Count > 0) + { + return TextView.Selection.SelectedSpans[0].Length > 0; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssFindReferencesCommandTarget.cs b/EditorExtensions/Commands/Css/CssFindReferencesCommandTarget.cs new file mode 100644 index 000000000..7bb93b0b5 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssFindReferencesCommandTarget.cs @@ -0,0 +1,98 @@ +using CssSorter; +using EnvDTE; +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.IO; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssFindReferences : CommandTargetBase + { + private DTE2 _dte; + private CssTree _tree; + + public CssFindReferences(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, typeof(VSConstants.VSStd97CmdID).GUID, (uint)VSConstants.VSStd97CmdID.FindReferences) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (!EnsureInitialized()) + return false; + + int position = TextView.Caret.Position.BufferPosition.Position; + ParseItem item = _tree.StyleSheet.ItemBeforePosition(position); + + if (item != null && item.Parent != null) + { + Find2 find = (Find2)EditorExtensionsPackage.DTE.Find; + string types = find.FilesOfType; + bool matchCase = find.MatchCase; + bool matchWord = find.MatchWholeWord; + + find.WaitForFindToComplete = false; + find.Action = EnvDTE.vsFindAction.vsFindActionFindAll; + find.Backwards = false; + find.MatchInHiddenText = true; + find.MatchWholeWord = true; + find.MatchCase = true; + find.PatternSyntax = EnvDTE.vsFindPatternSyntax.vsFindPatternSyntaxLiteral; + find.ResultsLocation = EnvDTE.vsFindResultsLocation.vsFindResults1; + find.SearchSubfolders = true; + find.FilesOfType = "*.css;*.less;*.scss;*.sass"; + find.Target = EnvDTE.vsFindTarget.vsFindTargetSolution; + find.FindWhat = SearchText(item); + find.Execute(); + + find.FilesOfType = types; + find.MatchCase = matchCase; + find.MatchWholeWord = matchWord; + } + + return true; + } + + private string SearchText(ParseItem item) + { + if (item.Parent is Declaration) + { + return item.Text; + } + else if (item.Parent is AtDirective) + { + return "@" + item.Text; + } + + return item.Parent.Text; + } + + public bool EnsureInitialized() + { + if (_tree == null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(TextView.TextBuffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { } + } + + return _tree != null; + } + + protected override bool IsEnabled() + { + return true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssFormatCommandTarget.cs b/EditorExtensions/Commands/Css/CssFormatCommandTarget.cs new file mode 100644 index 000000000..793165d62 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssFormatCommandTarget.cs @@ -0,0 +1,56 @@ +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text.Editor; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssFormatProperties : IOleCommandTarget + { + private ITextView _textView; + + public CssFormatProperties(ITextView textView) + { + this._textView = textView; + } + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + switch (nCmdID) + { + case (uint)VSConstants.VSStd2KCmdID.FORMATSELECTION: + case (uint)VSConstants.VSStd2KCmdID.FORMATDOCUMENT: + if (_textView.TextBuffer.ContentType.IsOfType("SCSS")) + { + return VSConstants.S_OK; + } + + break; + } + } + + return (int)(Constants.MSOCMDERR_E_FIRST); + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + for (int i = 0; i < cCmds; i++) + { + switch (prgCmds[i].cmdID) + { + case (uint)VSConstants.VSStd2KCmdID.FORMATSELECTION: + case (uint)VSConstants.VSStd2KCmdID.FORMATDOCUMENT: + prgCmds[i].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); + return VSConstants.S_OK; + } + } + } + + return (int)(Constants.OLECMDERR_E_NOTSUPPORTED); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssRemoveDuplicatesCommandTarget.cs b/EditorExtensions/Commands/Css/CssRemoveDuplicatesCommandTarget.cs new file mode 100644 index 000000000..35204db17 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssRemoveDuplicatesCommandTarget.cs @@ -0,0 +1,98 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssRemoveDuplicates : CommandTargetBase + { + private DTE2 _dte; + private readonly string[] _supported = new[] { "CSS", "LESS" }; + + public CssRemoveDuplicates(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidCssCmdSet, PkgCmdIDList.cssRemoveDuplicates) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + ITextBuffer buffer = ProjectHelpers.GetCurentTextBuffer(); + CssEditorDocument doc = new CssEditorDocument(buffer); + + StringBuilder sb = new StringBuilder(buffer.CurrentSnapshot.Length); + sb.Append(buffer.CurrentSnapshot.GetText()); + + EditorExtensionsPackage.DTE.UndoContext.Open("Remove Duplicate Properties"); + + string result = RemoveDuplicateProperties(sb, doc); + Span span = new Span(0, buffer.CurrentSnapshot.Length); + buffer.Replace(span, result); + + var selection = EditorExtensionsPackage.DTE.ActiveDocument.Selection as TextSelection; + selection.GotoLine(1); + + EditorExtensionsPackage.DTE.ExecuteCommand("Edit.FormatDocument"); + EditorExtensionsPackage.DTE.UndoContext.Close(); + + return true; + } + + private string RemoveDuplicateProperties(StringBuilder sb, CssEditorDocument doc) + { + var visitor = new CssItemCollector(true); + doc.Tree.StyleSheet.Accept(visitor); + + foreach (RuleBlock rule in visitor.Items.Reverse()) + { + HashSet list = new HashSet(); + + foreach (Declaration dec in rule.Declarations.Reverse()) + { + if (list.Contains(dec.Text)) + { + sb.Remove(dec.Start, dec.Length); + continue; + } + + list.Add(dec.Text); + } + } + + return sb.ToString(); + } + + private string GetVendorDeclarations(IEnumerable prefixes, Declaration declaration) + { + StringBuilder sb = new StringBuilder(); + string separator = true ? Environment.NewLine : " "; + + foreach (var entry in prefixes) + { + sb.Append(entry + declaration.Text + separator); + } + + return sb.ToString(); + } + + protected override bool IsEnabled() + { + var buffer = ProjectHelpers.GetCurentTextBuffer(); + + if (buffer != null && _supported.Contains(buffer.ContentType.DisplayName.ToUpperInvariant())) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssSaveListener.cs b/EditorExtensions/Commands/Css/CssSaveListener.cs new file mode 100644 index 000000000..1c2081d89 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssSaveListener.cs @@ -0,0 +1,70 @@ +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IWpfTextViewCreationListener))] + [ContentType(Microsoft.Web.Editor.CssContentTypeDefinition.CssContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + public class CssSaveListener : IWpfTextViewCreationListener + { + private ITextDocument _document; + + public void TextViewCreated(IWpfTextView textView) + { + textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out _document); + + if (_document != null) + { + _document.FileActionOccurred += document_FileActionOccurred; + } + } + + void document_FileActionOccurred(object sender, TextDocumentFileActionEventArgs e) + { + if (!WESettings.GetBoolean(WESettings.Keys.EnableCssMinification)) + return; + + if (e.FileActionType == FileActionTypes.ContentSavedToDisk && e.FilePath.EndsWith(".css")) + { + string minFile = e.FilePath.Insert(e.FilePath.Length - 3, "min."); + + if (File.Exists(minFile) && EditorExtensionsPackage.DTE.Solution.FindProjectItem(minFile) != null) + { + Task.Run(() => + { + Minify(e.FilePath, minFile); + }); + } + } + } + + public static void Minify(string file, string minFile) + { + if (file.EndsWith(".min.css")) + return; + + try + { + string content = MinifyFileMenu.MinifyString(".css", File.ReadAllText(file)); + //Minifier minifier = new Minifier(); + //string content = minifier.MinifyStyleSheet(File.ReadAllText(file)); + + ProjectHelpers.CheckOutFileFromSourceControl(minFile); + using (StreamWriter writer = new StreamWriter(minFile, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + } + catch + { + Logger.Log("Error minifying: " + file); + } + } + } +} diff --git a/EditorExtensions/Commands/Css/CssSelectBrowsers.cs b/EditorExtensions/Commands/Css/CssSelectBrowsers.cs new file mode 100644 index 000000000..a0493b1a9 --- /dev/null +++ b/EditorExtensions/Commands/Css/CssSelectBrowsers.cs @@ -0,0 +1,71 @@ +using EnvDTE80; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Projection; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssSelectBrowsers : CommandTargetBase + { + private DTE2 _dte; + private List _possible = new List() { ".CSS", ".LESS", ".SCSS" }; + + public CssSelectBrowsers(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidMinifyCmdSet, PkgCmdIDList.SelectBrowsers) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + BrowserSelector selector = new BrowserSelector(); + selector.ShowDialog(); + + return true; + } + + private bool IsValidTextBuffer(IWpfTextView view) + { + var projection = view.TextBuffer as IProjectionBuffer; + + if (projection != null) + { + int position = view.Caret.Position.BufferPosition.Position; + var snapshotPoint = view.Caret.Position.BufferPosition; + + var buffers = projection.SourceBuffers.Where(s => s.ContentType.IsOfType("css")); + + foreach (ITextBuffer buffer in buffers) + { + SnapshotPoint? point = view.BufferGraph.MapDownToBuffer(snapshotPoint, PointTrackingMode.Negative, buffer, PositionAffinity.Predecessor); + + if (point.HasValue) + { + return true; + } + } + + return false; + } + + return true; + } + + protected override bool IsEnabled() + { + var item = _dte.Solution.FindProjectItem(_dte.ActiveDocument.FullName); + bool hasProject = item != null && item.ContainingProject != null && !string.IsNullOrEmpty(item.ContainingProject.FullName); + + if (hasProject && TextView != null && IsValidTextBuffer(TextView)) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/CssSortPropertiesCommandTarget.cs b/EditorExtensions/Commands/Css/CssSortPropertiesCommandTarget.cs new file mode 100644 index 000000000..b88a4bd6b --- /dev/null +++ b/EditorExtensions/Commands/Css/CssSortPropertiesCommandTarget.cs @@ -0,0 +1,69 @@ +using CssSorter; +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.IO; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class CssSortProperties : CommandTargetBase + { + private DTE2 _dte; + private readonly string[] _supported = new[] { "CSS", "LESS" }; + //private static uint[] _commandIds = new uint[] { PkgCmdIDList.sortCssProperties }; + + public CssSortProperties(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidCssCmdSet, PkgCmdIDList.sortCssProperties) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + TextDocument doc = _dte.ActiveDocument.Object("TextDocument") as TextDocument; + EditPoint edit = doc.StartPoint.CreateEditPoint(); + string text = SortProperties(edit.GetText(doc.EndPoint)); + + _dte.UndoContext.Open("Sort All Properties"); + + edit.ReplaceText(doc.EndPoint, text, (int)vsFindOptions.vsFindOptionsNone); + EditorExtensionsPackage.DTE.ExecuteCommand("Edit.FormatDocument"); + doc.Selection.MoveToPoint(doc.StartPoint); + + _dte.UndoContext.Close(); + + return true; + } + + private string SortProperties(string text) + { + Sorter sorter = new Sorter(); + + if (Path.GetExtension(_dte.ActiveDocument.FullName) == ".css") + { + return sorter.SortStyleSheet(text); + } + else if (Path.GetExtension(_dte.ActiveDocument.FullName) == ".less") + { + return sorter.SortLess(text); + } + + return text; + } + + protected override bool IsEnabled() + { + var buffer = ProjectHelpers.GetCurentTextBuffer(); + + if (buffer != null && _supported.Contains(buffer.ContentType.DisplayName.ToUpperInvariant())) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/F1HelpCommandTarget.cs b/EditorExtensions/Commands/Css/F1HelpCommandTarget.cs new file mode 100644 index 000000000..36e02cc7b --- /dev/null +++ b/EditorExtensions/Commands/Css/F1HelpCommandTarget.cs @@ -0,0 +1,111 @@ +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class F1Help : CommandTargetBase + { + private CssTree _tree; + + public F1Help(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, typeof(VSConstants.VSStd97CmdID).GUID, (uint)VSConstants.VSStd97CmdID.F1Help) + { } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (!EnsureInitialized()) + return false; + + int position = TextView.Caret.Position.BufferPosition.Position; + ParseItem item = _tree.StyleSheet.ItemBeforePosition(position); + + if (item == null) + return false; + + return SchemaLookup(item); + } + + private delegate ICssCompletionListEntry Reference(string name); + + private bool SchemaLookup(ParseItem item) + { + if (item is ClassSelector || item is IdSelector || item is ItemName || item.Parent is RuleBlock || item.Parent is StyleSheet) + return false; + + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaRootForBuffer(TextView.TextBuffer); + + Declaration dec = item.FindType(); + if (dec != null && dec.PropertyName != null) + return OpenReferenceUrl(schema.GetProperty, dec.PropertyName.Text, "http://realworldvalidator.com/css/properties/"); + + PseudoClassFunctionSelector pseudoClassFunction = item.FindType(); + if (pseudoClassFunction != null) + return OpenReferenceUrl(schema.GetPseudo, pseudoClassFunction.Colon.Text + pseudoClassFunction.Function.FunctionName.Text + ")", "http://realworldvalidator.com/css/pseudoclasses/"); + + PseudoElementFunctionSelector pseudoElementFunction = item.FindType(); + if (pseudoElementFunction != null) + return OpenReferenceUrl(schema.GetPseudo, pseudoElementFunction.DoubleColon.Text + pseudoElementFunction.Function.FunctionName.Text + ")", "http://realworldvalidator.com/css/pseudoelements/"); + + PseudoElementSelector pseudoElement = item.FindType(); + if (pseudoElement != null && pseudoElement.PseudoElement != null) + return OpenReferenceUrl(schema.GetPseudo, pseudoElement.DoubleColon.Text + pseudoElement.PseudoElement.Text, "http://realworldvalidator.com/css/pseudoelements/"); + + PseudoClassSelector pseudoClass = item.FindType(); + if (pseudoClass != null && pseudoClass.PseudoClass != null) + return OpenReferenceUrl(schema.GetPseudo, pseudoClass.Colon.Text + pseudoClass.PseudoClass.Text, "http://realworldvalidator.com/css/pseudoclasses/"); + + AtDirective directive = item.FindType(); + if (directive != null) + return OpenReferenceUrl(schema.GetAtDirective, directive.At.Text + directive.Keyword.Text, "http://realworldvalidator.com/css/atdirectives/"); + + return false; + } + + private bool OpenReferenceUrl(Reference reference, string name, string baseUrl) + { + ICssCompletionListEntry entry = reference.Invoke(name); + if (entry != null) + { + string standardsReference = entry.GetAttribute("standard-reference"); + string text = entry.DisplayText; + Uri url; + + if (Uri.TryCreate(baseUrl + text, UriKind.Absolute, out url)) + { + System.Diagnostics.Process.Start(url.ToString()); + return true; + } + } + + return false; + } + + public bool EnsureInitialized() + { + if (_tree == null && Microsoft.Web.Editor.WebEditor.Host != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(TextView.TextBuffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { } + } + + return _tree != null; + } + + protected override bool IsEnabled() + { + return true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/RetriggerCommandTarget.cs b/EditorExtensions/Commands/Css/RetriggerCommandTarget.cs new file mode 100644 index 000000000..f99d9156d --- /dev/null +++ b/EditorExtensions/Commands/Css/RetriggerCommandTarget.cs @@ -0,0 +1,62 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System; +using System.ComponentModel.Composition; +using System.Runtime.InteropServices; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal class RetriggerTarget : IOleCommandTarget + { + private ITextView _textView; + private IOleCommandTarget _nextCommandTarget; + private ICompletionBroker _broker; + + public RetriggerTarget(IVsTextView adapter, ITextView textView, ICompletionBroker broker) + { + _textView = textView; + _broker = broker; + adapter.AddCommandFilter(this, out _nextCommandTarget); + } + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) + { + char typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); + + switch (typedChar) + { + case '!': + case '(': + case '/': + Retrigger(); + break; + } + } + + return _nextCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + } + + private void Retrigger() + { + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => + { + CssCompletionController.FromView(_textView).OnShowMemberList(true); + }), DispatcherPriority.Normal, null); + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + return _nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Css/SpeedTyping.cs b/EditorExtensions/Commands/Css/SpeedTyping.cs new file mode 100644 index 000000000..6cf01315c --- /dev/null +++ b/EditorExtensions/Commands/Css/SpeedTyping.cs @@ -0,0 +1,389 @@ +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Windows.Forms; +using System.Windows.Input; + +namespace MadsKristensen.EditorExtensions +{ + internal class SpeedTypingTarget : IOleCommandTarget + { + private IWpfTextView _textView; + private ICompletionBroker _broker; + private IQuickInfoBroker _QuickInfobroker; + private IClassifierAggregatorService _aggregator; + private DTE2 _dte; + private CssTree _tree; + + public SpeedTypingTarget(CssSortPropertiesViewCreationListener componentContext, IVsTextView adapter, IWpfTextView textView) + { + this._dte = EditorExtensionsPackage.DTE; + this._textView = textView; + this._aggregator = componentContext.AggregatorService; + this._broker = componentContext.CompletionBroker; + this._QuickInfobroker = componentContext.QuickInfoBroker; + } + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + //foreach (OutputWindowPane item in WebEssentialsPackage.dte.ToolWindows.OutputWindow.OutputWindowPanes) + //{ + // item.OutputString(nCmdID.ToString() + Environment.NewLine); + //} + + if (pguidCmdGroup == VSConstants.VSStd2K && WESettings.GetBoolean(WESettings.Keys.EnableSpeedTyping)) + { + switch ((VSConstants.VSStd2KCmdID)nCmdID) + { + case VSConstants.VSStd2KCmdID.RETURN: + if (Keyboard.IsKeyDown(Key.RightShift) || Keyboard.IsKeyDown(Key.LeftShift)) + { + if (Jump()) return + VSConstants.S_OK; + } + else + { + CommitStatementCompletion(); + if (Process(true, true, true) == VSConstants.S_OK) return VSConstants.S_OK; + } + break; + + case VSConstants.VSStd2KCmdID.TAB: + var completion = CommitStatementCompletion(); + if (Process(false, true, false) == VSConstants.S_OK || completion) return VSConstants.S_OK; + break; + } + } + + return (int)(Constants.MSOCMDERR_E_FIRST); + } + + private bool Jump() + { + if (!EnsureInitialized()) + return false; + + int position = _textView.Caret.Position.BufferPosition.Position; + ParseItem item = _tree.StyleSheet.ItemBeforePosition(position); + + if (item != null) + { + RuleBlock rule = item.FindType(); + Declaration dec = item.FindType(); + + if (rule != null && dec != null) + { + CommitStatementCompletion(); + + var line = _textView.TextSnapshot.GetLineFromPosition(position); + string text = line.Extent.GetText().TrimEnd(); + + if (!string.IsNullOrWhiteSpace(text) && !text.EndsWith(";")) + { + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + edit.Replace(line.Extent, text + ";"); + edit.Apply(); + } + } + + EditorExtensionsPackage.ExecuteCommand("Edit.FormatSelection"); + + SnapshotPoint point = new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, rule.AfterEnd); + _textView.Caret.MoveTo(point); + _textView.ViewScroller.EnsureSpanVisible(new SnapshotSpan(point, 0)); + return true; + } + } + + return false; + } + + //private int JumpOut() + //{ + // int result = VSConstants.S_FALSE; + // var span = _textView.Selection.SelectedSpans[0]; + // var position = span.Start.Position; + // var line = span.Start.GetContainingLine(); + // var classifications = _aggregator.GetClassifier(_textView.TextBuffer).GetClassificationSpans(line.Extent); + + // _dte.UndoContext.Open("Jump out of brace"); + // try + // { + // foreach (var classification in classifications) + // { + // if (IsPropertyValue(classification) && IsPropertyValueEligible(line, position)) + // { + // CommitStatementCompletion(); + // line = _textView.TextSnapshot.GetLineFromPosition(position); + // using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + // { + // edit.Replace(line.Extent, line.Extent.GetText().TrimEnd() + ";"); + // edit.Apply(); + // } + // } + // else if (IsSelector(classification) || (IsPropertyName(classification) && !line.Extent.GetText().Contains(":"))) + // { + // return VSConstants.S_FALSE; + // } + // } + + // var text = _textView.TextSnapshot.GetText(); + // int start = text.LastIndexOf('{', position - 1); + // int middle = text.IndexOf('{', position - 1); + // int end = text.IndexOf('}', position - 1); + // int emptyLines = ResolveEmptyLines(end); + + // string blanks = string.Empty; + // if (emptyLines < 3) + // { + // for (int i = 0; i < (3 - emptyLines); i++) + // { + // blanks += "\n"; + // } + // } + + // if ((end < middle || middle == -1) && start < position && end > position) + // { + // using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + // { + // edit.Replace(_textView.TextSnapshot.GetLineFromPosition(end).Extent, "}" + blanks); + + // if (string.IsNullOrWhiteSpace(line.GetText())) + // { + // edit.Delete(line.ExtentIncludingLineBreak); + // end = end - line.ExtentIncludingLineBreak.Length; + // } + + // edit.Apply(); + // result = VSConstants.S_OK; + // } + + // _textView.Caret.MoveTo(new SnapshotPoint(_textView.TextSnapshot, end + 3)); + // _broker.DismissAllSessions(_textView); + // DismissQuickInfo(); + // } + // } + // finally + // { + // _dte.UndoContext.Close(); + // } + + // return result; + //} + + //private int ResolveEmptyLines(int end) + //{ + // if (end == -1 || _textView.TextSnapshot.GetLineNumberFromPosition(end) == _textView.TextSnapshot.LineCount) + // return 0; + + // int emptyLines = 0; + // int currentLine = _textView.TextSnapshot.GetLineFromPosition(end).LineNumber + 1; + // while ((currentLine + emptyLines) < _textView.TextSnapshot.LineCount) + // { + // if (string.IsNullOrWhiteSpace(_textView.TextSnapshot.GetLineFromLineNumber(currentLine + emptyLines).GetText())) + // { + // emptyLines++; + // } + // else + // { + // break; + // } + // } + // return emptyLines; + //} + + private int Process(bool selector, bool name, bool value) + { + if (!EnsureInitialized()) + return VSConstants.S_FALSE; + + var span = _textView.Selection.SelectedSpans[0]; + var line = span.Start.GetContainingLine(); + var position = span.Start.Position;// -(line.Length - line.GetText().TrimEnd().Length); + var classifications = _aggregator.GetClassifier(_textView.TextBuffer).GetClassificationSpans(line.Extent); + + foreach (var classification in classifications) + { + if (selector && IsSelector(classification) && IsSelectorEligible(line, position)) + { + return InsertBraces(line); + } + else if (name && IsPropertyName(classification) && IsPropertyNameEligible(line)) + { + DismissQuickInfo(); + return InsertColon(position); + } + else if (value && IsPropertyValue(classification) && IsPropertyValueEligible(line, position)) + { + DismissQuickInfo(); + return InsertSemiColon(line); + } + } + + return VSConstants.S_FALSE; + } + + private static bool IsSelector(ClassificationSpan classification) + { + return classification.ClassificationType.Classification == "CSS Selector"; + } + + private static bool IsPropertyName(ClassificationSpan classification) + { + return classification.ClassificationType.Classification == "CSS Property Name"; + } + + private static bool IsPropertyValue(ClassificationSpan classification) + { + return classification.ClassificationType.Classification == "CSS Property Value"; + } + + private bool IsSelectorEligible(ITextSnapshotLine line, int position) + { + string text = line.GetText(); + if (text.IndexOf('{') > -1) + return false; + + if (text.Trim().EndsWith(",", StringComparison.Ordinal)) + return false; + + if (line.LineNumber + 1 < line.Snapshot.LineCount) + { + var next = line.Snapshot.GetLineFromLineNumber(line.LineNumber + 1); + if (next.GetText().Trim().StartsWith("{", StringComparison.Ordinal)) + return false; + } + + return true; + } + + private bool IsPropertyValueEligible(ITextSnapshotLine line, int position) + { + string text = line.GetText(); + int diff = text.Length - text.TrimEnd().Length; + + if (line.End.Position - diff > position) + return false; + + if (text.IndexOf(';') > -1) + return false; + + return true; + } + + private bool IsPropertyNameEligible(ITextSnapshotLine line) + { + return !line.GetText().Contains(":"); + } + + private bool CommitStatementCompletion() + { + bool value = _broker.IsCompletionActive(_textView); + + if (_broker.IsCompletionActive(_textView)) + { + _broker.GetSessions(_textView)[0].Commit(); + } + + return value; + } + + private void DismissQuickInfo() + { + if (_QuickInfobroker.IsQuickInfoActive(_textView)) + _QuickInfobroker.GetSessions(_textView)[0].Dismiss(); + } + + private int InsertBraces(ITextSnapshotLine line) + { + string text = line.GetText(); + + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + _dte.UndoContext.Open("Insert braces"); + edit.Replace(line.Extent, text.TrimEnd() + " {\n\t\n}"); + edit.Apply(); + _dte.UndoContext.Close(); + } + + SendKeys.Send("{LEFT}{LEFT}^( )"); + return VSConstants.S_OK; + } + + private int InsertColon(int position) + { + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + _dte.UndoContext.Open("Insert braces"); + edit.Insert(position, ":"); + edit.Apply(); + _dte.UndoContext.Close(); + } + + SendKeys.Send(" "); + + return VSConstants.S_OK; + } + + private int InsertSemiColon(ITextSnapshotLine line) + { + string text = line.GetText(); + + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + _dte.UndoContext.Open("Insert braces"); + edit.Replace(line.Extent, text.TrimEnd() + ";\n\t"); + edit.Apply(); + _dte.UndoContext.Close(); + } + + //SendKeys.Send("^( )"); + return VSConstants.S_OK; + } + + public bool EnsureInitialized() + { + if (_tree == null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_textView.TextBuffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + //if (WESettings.GetBoolean(WESettings.Keys.EnableSpeedTyping)) + //{ + // for (int i = 0; i < cCmds; i++) + // { + // switch ((VSConstants.VSStd2KCmdID)prgCmds[i].cmdID) + // { + // case VSConstants.VSStd2KCmdID.RETURN: + // prgCmds[i].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); + // return VSConstants.S_OK; + // } + // } + //} + + //return _nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + return (int)(Constants.OLECMDERR_E_NOTSUPPORTED); + } + } +} diff --git a/EditorExtensions/Commands/FeatureEnabler.cs b/EditorExtensions/Commands/FeatureEnabler.cs new file mode 100644 index 000000000..4124c49f3 --- /dev/null +++ b/EditorExtensions/Commands/FeatureEnabler.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Microsoft.VisualStudio.JavaScript.Web.Extensions.Shared; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IFeatureEnabler))] + internal class FeatureEnabler : IFeatureEnabler + { + private static string[] _enabledFeatures = + { + FeatureManager.Features.DocCommentExtension, + FeatureManager.Features.DocCommentScaffolding + }; + + public IEnumerable EnabledFeatures + { + get + { + return _enabledFeatures; + } + } + } +} diff --git a/EditorExtensions/Commands/HTML/ContractSelectionTarget.cs b/EditorExtensions/Commands/HTML/ContractSelectionTarget.cs new file mode 100644 index 000000000..97c2e06ac --- /dev/null +++ b/EditorExtensions/Commands/HTML/ContractSelectionTarget.cs @@ -0,0 +1,91 @@ +using Microsoft.Html.Core; +using Microsoft.Html.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class ContactSelection : CommandTargetBase + { + private IWpfTextView _view; + private ITextBuffer _buffer; + + public ContactSelection(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidFormattingCmdSet, PkgCmdIDList.ContractSelection) + { + _view = textView; + _buffer = textView.TextBuffer; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + HtmlEditorDocument document = HtmlEditorDocument.FromTextView(_view); + var tree = document.HtmlEditorTree; + + int start = _view.Selection.Start.Position.Position; + int end = _view.Selection.End.Position.Position; + + ElementNode tag = null; + AttributeNode attr = null; + + tree.GetPositionElement(start + 1, out tag, out attr); + + if (tag == null) + return false; + + if (tag.EndTag != null && tag.StartTag.Start == start && tag.EndTag.End == end) + { + Select(tag.InnerRange.Start, tag.InnerRange.Length); + } + else if (tag.Children.Count > 0) + { + var current = NodeAtCaret(tree); + var child = ChildNode(current, tag); + + if (tag.Children.Contains(child)) + Select(child.Start, child.OuterRange.Length); + else + Select(tag.Children[0].Start, tag.Children[0].End - tag.Children[0].Start); + } + + return true; + } + + private ElementNode ChildNode(ElementNode deepChild, ElementNode parent) + { + if (deepChild.Parent != parent) + { + return ChildNode(deepChild.Parent, parent); + } + + return deepChild; + } + + private ElementNode NodeAtCaret(HtmlEditorTree tree) + { + int start = _view.Caret.Position.BufferPosition.Position; + + ElementNode tag = null; + AttributeNode attr = null; + + tree.GetPositionElement(start, out tag, out attr); + + return tag; + } + + private void Select(int start, int length) + { + var span = new SnapshotSpan(_buffer.CurrentSnapshot, start, length); + _view.Selection.Select(span, false); + } + + protected override bool IsEnabled() + { + return true; + } + + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/HTML/ExpandSelectionTarget.cs b/EditorExtensions/Commands/HTML/ExpandSelectionTarget.cs new file mode 100644 index 000000000..816342793 --- /dev/null +++ b/EditorExtensions/Commands/HTML/ExpandSelectionTarget.cs @@ -0,0 +1,70 @@ +using Microsoft.Html.Core; +using Microsoft.Html.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class ExpandSelection : CommandTargetBase + { + private IWpfTextView _view; + private ITextBuffer _buffer; + + public ExpandSelection(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidFormattingCmdSet, PkgCmdIDList.ExpandSelection) + { + _view = textView; + _buffer = textView.TextBuffer; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + HtmlEditorDocument document = HtmlEditorDocument.FromTextView(_view); + var tree = document.HtmlEditorTree; + + int start = _view.Selection.Start.Position.Position; + int end = _view.Selection.End.Position.Position; + + ElementNode tag = null; + AttributeNode attr = null; + + tree.GetPositionElement(start, out tag, out attr); + + if (tag == null) + return false; + + if (tag.EndTag != null && tag.StartTag.End == start && tag.EndTag.Start == end) + { + Select(tag.Start, tag.OuterRange.Length); + } + else if (tag.EndTag != null && tag.StartTag.Start < start && tag.EndTag.End > end) + { + Select(tag.InnerRange.Start, tag.InnerRange.Length); + } + else if (tag.IsSelfClosing() && tag.Start < start && tag.End > end) + { + Select(tag.Start, tag.OuterRange.Length); + } + else if (tag.Parent != null) + { + Select(tag.Parent.Start, tag.Parent.OuterRange.Length); + } + + return true; + } + + private void Select(int start, int length) + { + var span = new SnapshotSpan(_buffer.CurrentSnapshot, start, length); + _view.Selection.Select(span, false); + } + + protected override bool IsEnabled() + { + return true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/HTML/HtmlCreationListener.cs b/EditorExtensions/Commands/HTML/HtmlCreationListener.cs new file mode 100644 index 000000000..4b728d98f --- /dev/null +++ b/EditorExtensions/Commands/HTML/HtmlCreationListener.cs @@ -0,0 +1,54 @@ +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType("HTML")] + [ContentType("HTMLX")] + [TextViewRole(PredefinedTextViewRoles.Document)] + class HtmlViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + [Import] + internal ICompletionBroker CompletionBroker { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + + textView.Properties.GetOrCreateSingletonProperty(() => new ZenCoding(textViewAdapter, textView, CompletionBroker)); + + //uint zenCoding; + //EditorExtensionsPackage.PriorityCommandTarget.RegisterPriorityCommandTarget(0, new ZenCoding(textViewAdapter, textView, CompletionBroker), out zenCoding); + //textView.Closed += delegate { EditorExtensionsPackage.PriorityCommandTarget.UnregisterPriorityCommandTarget(zenCoding); }; + } + } + + [Export(typeof(IVsTextViewCreationListener))] + [ContentType("HTMLX")] + [TextViewRole(PredefinedTextViewRoles.Document)] + class HtmlxViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + [Import] + internal ICompletionBroker CompletionBroker { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + + textView.Properties.GetOrCreateSingletonProperty(() => new SurroundWith(textViewAdapter, textView, CompletionBroker)); + textView.Properties.GetOrCreateSingletonProperty(() => new ExpandSelection(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new ContactSelection(textViewAdapter, textView)); + } + } +} diff --git a/EditorExtensions/Commands/HTML/SurroundWithTarget.cs b/EditorExtensions/Commands/HTML/SurroundWithTarget.cs new file mode 100644 index 000000000..9eb449c4d --- /dev/null +++ b/EditorExtensions/Commands/HTML/SurroundWithTarget.cs @@ -0,0 +1,90 @@ +using Microsoft.Html.Core; +using Microsoft.Html.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class SurroundWith : CommandTargetBase + { + private ICompletionBroker _broker; + private IWpfTextView _view; + private ITextBuffer _buffer; + + public SurroundWith(IVsTextView adapter, IWpfTextView textView, ICompletionBroker broker) + : base(adapter, textView, GuidList.guidFormattingCmdSet, PkgCmdIDList.SurroundWith) + { + _broker = broker; + _view = textView; + _buffer = textView.TextBuffer; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (_view.Selection.IsEmpty) + { + return HandleElement(); + } + else + { + int start = _view.Selection.Start.Position.Position; + int end = _view.Selection.End.Position.Position; + Update(start, end); + return true; + } + + return false; + } + + private bool HandleElement() + { + HtmlEditorDocument document = HtmlEditorDocument.FromTextView(_view); + var tree = document.HtmlEditorTree; + + int position = _view.Caret.Position.BufferPosition.Position; + + ElementNode tag = null; + AttributeNode attr = null; + + tree.GetPositionElement(position, out tag, out attr); + + if (tag != null && (tag.EndTag != null || tag.IsSelfClosing())) + { + int start = tag.Start; + int end = tag.End; + + Update(start, end); + return true; + } + + return false; + } + + private void Update(int start, int end) + { + EditorExtensionsPackage.DTE.UndoContext.Open("Surround with..."); + + using (var edit = _buffer.CreateEdit()) + { + edit.Insert(end, "

"); + edit.Insert(start, "

"); + edit.Apply(); + } + + SnapshotPoint point = new SnapshotPoint(_buffer.CurrentSnapshot, start + 1); + + _view.Caret.MoveTo(point); + _view.Selection.Select(new SnapshotSpan(_buffer.CurrentSnapshot, point, 1), false); + + EditorExtensionsPackage.DTE.UndoContext.Close(); + } + + protected override bool IsEnabled() + { + return true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/HTML/ZenCodingCommandTarget.cs b/EditorExtensions/Commands/HTML/ZenCodingCommandTarget.cs new file mode 100644 index 000000000..2831334f1 --- /dev/null +++ b/EditorExtensions/Commands/HTML/ZenCodingCommandTarget.cs @@ -0,0 +1,301 @@ +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Projection; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Linq; +using System.Text.RegularExpressions; +using System.Windows.Threading; +using ZenCoding; + +namespace MadsKristensen.EditorExtensions +{ + internal class ZenCoding : CommandTargetBase + { + private ICompletionBroker _broker; + private ITrackingSpan _trackingSpan; + + private static Regex _bracket = new Regex(@"<([a-z0-9]*)\b[^>]*>([^<]*)", RegexOptions.IgnoreCase); + private static Regex _quotes = new Regex("(=\"()\")", RegexOptions.IgnoreCase); + + public ZenCoding(IVsTextView adapter, IWpfTextView textView, ICompletionBroker broker) + : base(adapter, textView, typeof(VSConstants.VSStd2KCmdID).GUID, 4, 5) + { + _broker = broker; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (commandId == 4 && !_broker.IsCompletionActive(TextView)) + { + if (WESettings.GetBoolean(WESettings.Keys.EnableHtmlZenCoding)) + { + if (InvokeZenCoding()) + { + return true; + } + else if (MoveToNextEmptySlot()) + { + return true; + } + } + } + else if (commandId == 5 && !_broker.IsCompletionActive(TextView)) + { + if (WESettings.GetBoolean(WESettings.Keys.EnableHtmlZenCoding) && MoveToPrevEmptySlot()) + { + return true; + } + } + + return false; + } + + private bool MoveToNextEmptySlot() + { + if (_trackingSpan == null) + return false; + + int position = TextView.Caret.Position.BufferPosition.Position + 1; + Span ts = _trackingSpan.GetSpan(TextView.TextBuffer.CurrentSnapshot); + + if (ts.Contains(position)) + { + Span span = new Span(position, ts.End - position); + SetCaret(span, false); + return true; + } + + return false; + } + + private bool MoveToPrevEmptySlot() + { + if (_trackingSpan == null) + return false; + + int position = TextView.Caret.Position.BufferPosition.Position; + + if (position > 0) + { + Span ts = _trackingSpan.GetSpan(TextView.TextBuffer.CurrentSnapshot); + + if (ts.Contains(position - 1)) + { + Span span = new Span(ts.Start, position - ts.Start - 1); + SetCaret(span, true); + return true; + } + } + + return false; + } + + private bool InvokeZenCoding() + { + Span zenSpan = GetText(); + + if (zenSpan.Length == 0 || TextView.Selection.SelectedSpans[0].Length > 0 || !IsValidTextBuffer()) + return false; + + string zenSyntax = TextView.TextBuffer.CurrentSnapshot.GetText(zenSpan); + + Parser parser = new Parser(); + string result = parser.Parse(zenSyntax, ZenType.HTML); + + if (!string.IsNullOrEmpty(result)) + { + EditorExtensionsPackage.DTE.UndoContext.Open("ZenCoding"); + + ITextSelection selection = UpdateTextBuffer(zenSpan, result); + Span newSpan = new Span(zenSpan.Start, selection.SelectedSpans[0].Length); + + if (result.Count(c => c == '>') > 2) + { + _trackingSpan = TextView.TextBuffer.CurrentSnapshot.CreateTrackingSpan(newSpan, SpanTrackingMode.EdgeExclusive); + } + + selection.Clear(); + + EditorExtensionsPackage.DTE.UndoContext.Close(); + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => SetCaret(newSpan, false)), DispatcherPriority.Normal, null); + + return true; + } + + return false; + } + + private bool IsValidTextBuffer() + { + var projection = TextView.TextBuffer as IProjectionBuffer; + + if (projection != null) + { + int position = TextView.Caret.Position.BufferPosition.Position; + var snapshotPoint = TextView.Caret.Position.BufferPosition; + + var buffers = projection.SourceBuffers.Where( + s => + !s.ContentType.IsOfType("html") + && !s.ContentType.IsOfType("htmlx") + && !s.ContentType.IsOfType("inert") + && !s.ContentType.IsOfType("CSharp") + && !s.ContentType.IsOfType("VisualBasic") + && !s.ContentType.IsOfType("RoslynCSharp") + && !s.ContentType.IsOfType("RoslynVisualBasic")); + + + foreach (ITextBuffer buffer in buffers) + { + SnapshotPoint? point = TextView.BufferGraph.MapDownToBuffer(snapshotPoint, PointTrackingMode.Negative, buffer, PositionAffinity.Predecessor); + + if (point.HasValue) + { + return false; + } + } + } + + return true; + } + + + //private bool IsValidTextBuffer() + //{ + // IProjectionBuffer projection = _textView.TextBuffer as IProjectionBuffer; + + // if (projection != null) + // { + // int position = _textView.Caret.Position.BufferPosition.Position; + // var buffers = projection.SourceBuffers.Where(s => s.ContentType.IsOfType("css") || s.ContentType.IsOfType("javascript")); + + // foreach (ITextBuffer buffer in buffers) + // { + // IProjectionSnapshot snapshot = buffer.CurrentSnapshot as IProjectionSnapshot; + // bool containsPosition = snapshot.GetSourceSpans().Any(s => s.Contains(position)); + + // if (containsPosition) + // { + // return false; + // } + // } + // } + + // return true; + //} + + private bool SetCaret(Span zenSpan, bool isReverse) + { + string text = TextView.TextBuffer.CurrentSnapshot.GetText(); + Span quote = FindTabSpan(zenSpan, isReverse, text, _quotes); + Span bracket = FindTabSpan(zenSpan, isReverse, text, _bracket); + + if (!isReverse && bracket.Start > 0 && (bracket.Start < quote.Start || quote.Start == 0)) + { + quote = bracket; + } + else if (isReverse && bracket.Start > 0 && (bracket.Start > quote.Start || quote.Start == 0)) + { + quote = bracket; + } + + if (zenSpan.Contains(quote.Start)) + { + MoveTab(quote); + return true; + } + else if (!isReverse) + { + MoveTab(new Span(zenSpan.End, 0)); + return true; + } + + return false; + } + + private void MoveTab(Span quote) + { + TextView.Caret.MoveTo(new SnapshotPoint(TextView.TextBuffer.CurrentSnapshot, quote.Start)); + SnapshotSpan span = new SnapshotSpan(TextView.TextBuffer.CurrentSnapshot, quote); + TextView.Selection.Select(span, false); + } + + private static Span FindTabSpan(Span zenSpan, bool isReverse, string text, Regex regex) + { + MatchCollection matches = regex.Matches(text); + + if (!isReverse) + { + foreach (Match match in matches) + { + Group group = match.Groups[2]; + + if (group.Index >= zenSpan.Start) + { + return new Span(group.Index, group.Length); + } + } + } + else + { + for (int i = matches.Count - 1; i >= 0; i--) + { + Group group = matches[i].Groups[2]; + + if (group.Index < zenSpan.End) + { + return new Span(group.Index, group.Length); + } + } + } + + return new Span(); + } + + private ITextSelection UpdateTextBuffer(Span zenSpan, string result) + { + TextView.TextBuffer.Replace(zenSpan, result); + + SnapshotPoint point = new SnapshotPoint(TextView.TextBuffer.CurrentSnapshot, zenSpan.Start); + SnapshotSpan snapshot = new SnapshotSpan(point, result.Length); + TextView.Selection.Select(snapshot, false); + + EditorExtensionsPackage.ExecuteCommand("Edit.FormatSelection"); + + return TextView.Selection; + } + + private Span GetText() + { + int position = TextView.Caret.Position.BufferPosition.Position; + + if (position >= 0) + { + var line = TextView.TextBuffer.CurrentSnapshot.GetLineFromPosition(position); + string text = line.GetText().TrimEnd(); + + if (string.IsNullOrWhiteSpace(text) || text.Length < position - line.Start || text.Length + line.Start > position) + return new Span(); + + string result = text.Substring(0, position - line.Start).TrimStart(); + + if (result.Length > 0 && !text.Contains("<") && !char.IsWhiteSpace(result.Last())) + { + return new Span(line.Start.Position + text.IndexOf(result), result.Length); + } + } + + return new Span(); + } + + protected override bool IsEnabled() + { + return true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/JavaScript/JavaScriptCreationListener.cs b/EditorExtensions/Commands/JavaScript/JavaScriptCreationListener.cs new file mode 100644 index 000000000..d3f532bf5 --- /dev/null +++ b/EditorExtensions/Commands/JavaScript/JavaScriptCreationListener.cs @@ -0,0 +1,42 @@ +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType("JavaScript")] + [TextViewRole(PredefinedTextViewRoles.Document)] + class JavaScriptSortPropertiesViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + [Import(typeof(ITextStructureNavigatorSelectorService))] + internal ITextStructureNavigatorSelectorService Navigator { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + + textView.Properties.GetOrCreateSingletonProperty(() => new MinifySelection(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new JavaScriptFindReferences(textViewAdapter, textView, Navigator)); + textView.Properties.GetOrCreateSingletonProperty(() => new CssExtractToFile(textViewAdapter, textView)); + + ITextDocument document; + textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document); + + if (document != null) + { + JsHintProjectRunner runner = new JsHintProjectRunner(document); + textView.Closed += (s, e) => runner.Dispose(); + + textView.TextBuffer.Properties.GetOrCreateSingletonProperty(() => runner); + } + } + } +} diff --git a/EditorExtensions/Commands/JavaScript/JavaScriptFindReferencesCommandTarget.cs b/EditorExtensions/Commands/JavaScript/JavaScriptFindReferencesCommandTarget.cs new file mode 100644 index 000000000..80fcac941 --- /dev/null +++ b/EditorExtensions/Commands/JavaScript/JavaScriptFindReferencesCommandTarget.cs @@ -0,0 +1,65 @@ +using EnvDTE80; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class JavaScriptFindReferences : CommandTargetBase + { + private DTE2 _dte; + private ITextStructureNavigator _navigator; + + public JavaScriptFindReferences(IVsTextView adapter, IWpfTextView textView, ITextStructureNavigatorSelectorService navigator) + : base(adapter, textView, typeof(VSConstants.VSStd97CmdID).GUID, (uint)VSConstants.VSStd97CmdID.FindReferences) + { + _navigator = navigator.GetTextStructureNavigator(textView.TextBuffer); + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + int position = TextView.Caret.Position.BufferPosition.Position; + SnapshotPoint? point = TextView.Caret.Position.Point.GetPoint(TextView.TextBuffer, PositionAffinity.Predecessor); + + if (point.HasValue) + { + TextExtent wordExtent = _navigator.GetExtentOfWord(point.Value - 1); + string wordText = TextView.TextSnapshot.GetText(wordExtent.Span); + + Find2 find = (Find2)EditorExtensionsPackage.DTE.Find; + string types = find.FilesOfType; + bool matchCase = find.MatchCase; + bool matchWord = find.MatchWholeWord; + + find.WaitForFindToComplete = false; + find.Action = EnvDTE.vsFindAction.vsFindActionFindAll; + find.Backwards = false; + find.MatchInHiddenText = true; + find.MatchWholeWord = true; + find.MatchCase = true; + find.PatternSyntax = EnvDTE.vsFindPatternSyntax.vsFindPatternSyntaxLiteral; + find.ResultsLocation = EnvDTE.vsFindResultsLocation.vsFindResults1; + find.SearchSubfolders = true; + find.FilesOfType = "*.js"; + find.Target = EnvDTE.vsFindTarget.vsFindTargetSolution; + find.FindWhat = wordText; + find.Execute(); + + find.FilesOfType = types; + find.MatchCase = matchCase; + find.MatchWholeWord = matchWord; + } + + return true; + } + + protected override bool IsEnabled() + { + return true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/JavaScript/JavaScriptSaveListener.cs b/EditorExtensions/Commands/JavaScript/JavaScriptSaveListener.cs new file mode 100644 index 000000000..934104ddb --- /dev/null +++ b/EditorExtensions/Commands/JavaScript/JavaScriptSaveListener.cs @@ -0,0 +1,128 @@ +using Microsoft.Ajax.Utilities; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IWpfTextViewCreationListener))] + [ContentType("JavaScript")] + [TextViewRole(PredefinedTextViewRoles.Document)] + public class JavaScriptSaveListener : IWpfTextViewCreationListener + { + private ITextDocument _document; + + public void TextViewCreated(IWpfTextView textView) + { + textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out _document); + + if (_document != null) + { + _document.FileActionOccurred += document_FileActionOccurred; + } + } + + void document_FileActionOccurred(object sender, TextDocumentFileActionEventArgs e) + { + if (!WESettings.GetBoolean(WESettings.Keys.EnableJsMinification)) + return; + + ITextDocument document = (ITextDocument)sender; + + if (document.TextBuffer != null && e.FileActionType == FileActionTypes.ContentSavedToDisk && e.FilePath.EndsWith(".js", StringComparison.OrdinalIgnoreCase)) + { + string minFile = e.FilePath.Insert(e.FilePath.Length - 2, "min."); + string bundleFile = e.FilePath + ".bundle"; + + if (!File.Exists(bundleFile) && File.Exists(minFile) && EditorExtensionsPackage.DTE.Solution.FindProjectItem(minFile) != null) + { + Task.Run(() => + { + Minify(e.FilePath, minFile, false); + }); + } + } + } + + public static void Minify(string sourceFile, string minFile, bool isBundle) + { + if (sourceFile.EndsWith(".min.js")) + return; + + try + { + CodeSettings settings = new CodeSettings() + { + EvalTreatment = EvalTreatment.MakeImmediateSafe, + TermSemicolons = true, + PreserveImportantComments = WESettings.GetBoolean(WESettings.Keys.KeepImportantComments) + }; + + if (WESettings.GetBoolean(WESettings.Keys.GenerateJavaScriptSourceMaps)) + { + MinifyFileWithSourceMap(sourceFile, minFile, settings, isBundle); + } + else + { + MinifyFile(sourceFile, minFile, settings, isBundle); + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + + private static void MinifyFileWithSourceMap(string file, string minFile, CodeSettings settings, bool isBundle) + { + string mapPath = minFile + ".map"; + ProjectHelpers.CheckOutFileFromSourceControl(mapPath); + + using (TextWriter writer = new StreamWriter(mapPath, false, new UTF8Encoding(false))) + using (V3SourceMap sourceMap = new V3SourceMap(writer)) + { + settings.SymbolsMap = sourceMap; + + sourceMap.StartPackage(Path.GetFileName(minFile), Path.GetFileName(mapPath)); + + // This fails when debugger is attached. Bug raised with Ron Logan + MinifyFile(file, minFile, settings, isBundle); + + sourceMap.EndPackage(); + + if (!isBundle) + { + MarginBase.AddFileToProject(file, mapPath); + } + } + } + + private static void MinifyFile(string file, string minFile, CodeSettings settings, bool isBundle) + { + Minifier minifier = new Minifier(); + + if (!isBundle) + { + minifier.FileName = Path.GetFileName(file); + } + + string content = minifier.MinifyJavaScript(File.ReadAllText(file), settings); + + if (WESettings.GetBoolean(WESettings.Keys.GenerateJavaScriptSourceMaps)) + { + content += Environment.NewLine + "//@ sourceMappingURL=" + Path.GetFileName(minFile) + ".map"; + } + + ProjectHelpers.CheckOutFileFromSourceControl(minFile); + using (StreamWriter writer = new StreamWriter(minFile, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + } + } +} diff --git a/EditorExtensions/Commands/JavaScript/JsHintCompiler.cs b/EditorExtensions/Commands/JavaScript/JsHintCompiler.cs new file mode 100644 index 000000000..dbc488730 --- /dev/null +++ b/EditorExtensions/Commands/JavaScript/JsHintCompiler.cs @@ -0,0 +1,84 @@ +using MadsKristensen.EditorExtensions; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Threading; + +///

+/// Summary description for Lint +/// +[ComVisible(true)] +public class JsHintCompiler : ScriptRunnerBase +{ + private string _settings; + private JsHintOptions _options; + + public JsHintCompiler(Dispatcher dispatcher) + : base(dispatcher) + { } + + protected override string CreateHtml(string source, string state) + { + if (_options == null) + { + _options = new JsHintOptions(); + _options.LoadSettingsFromStorage(); + JsHintOptions.Changed += delegate { _options.LoadSettingsFromStorage(); GenerateSettings(); }; + + GenerateSettings(); + } + + source = source + .Replace("\\", "\\\\") + .Replace("\n", "\\n") + .Replace("\r", "\\r") + .Replace("'", "\\'"); + + string script = ReadResourceFile("MadsKristensen.EditorExtensions.Resources.Scripts.jshint.js") + + "JSHINT('" + source + "', {" + _settings + "});" + + "window.external.Execute(JSON.stringify(JSHINT.errors), '" + state.Replace("\\", "\\\\") + "')"; + + return ""; + } + + private void GenerateSettings() + { + Type type = _options.GetType(); + PropertyInfo[] properties = type.GetProperties(); + List list = new List(); + + foreach (PropertyInfo item in properties) + { + if (!item.Name.StartsWith("JsHint_")) + continue; + + object value = item.GetValue(_options, null); + int intValue; + bool boolValue; + + if (int.TryParse(value.ToString(), out intValue) && intValue > -1) + { + list.Add(item.Name.Replace("JsHint_", string.Empty) + ":" + intValue); + } + else if (bool.TryParse(value.ToString(), out boolValue) && boolValue == true) + { + list.Add(item.Name.Replace("JsHint_", string.Empty) + ":true"); + } + } + + _settings = string.Join(", ", list); + } +} + +public class Result +{ + public string id { get; set; } + public string raw { get; set; } + public string evidence { get; set; } + public int line { get; set; } + public int character { get; set; } + public string a { get; set; } + public string b { get; set; } + public string reason { get; set; } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/JavaScript/JsHintProjectRunner.cs b/EditorExtensions/Commands/JavaScript/JsHintProjectRunner.cs new file mode 100644 index 000000000..c542b685f --- /dev/null +++ b/EditorExtensions/Commands/JavaScript/JsHintProjectRunner.cs @@ -0,0 +1,64 @@ +using Microsoft.VisualStudio.Text; +using System; +using System.IO; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal class JsHintProjectRunner : IDisposable + { + private ITextDocument _document; + private JsHintRunner _runner; + private bool _isDisposed; + + public JsHintProjectRunner(ITextDocument document) + { + _document = document; + _document.FileActionOccurred += DocumentSavedHandler; + _runner = new JsHintRunner(_document.FilePath); + + if (WESettings.GetBoolean(WESettings.Keys.EnableJsHint)) + { + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => _runner.RunCompiler()), DispatcherPriority.ApplicationIdle, null); + } + } + + private void DocumentSavedHandler(object sender, TextDocumentFileActionEventArgs e) + { + if (!WESettings.GetBoolean(WESettings.Keys.EnableJsHint)) + return; + + ITextDocument document = (ITextDocument)sender; + + if (document.TextBuffer != null && !_isDisposed && e.FileActionType == FileActionTypes.ContentSavedToDisk) + { + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => _runner.RunCompiler()), DispatcherPriority.ApplicationIdle, null); + } + } + + public static void RunOnAllFilesInProject() + { + string dir = ProjectHelpers.GetRootFolder(); + + if (dir != null && Directory.Exists(dir)) + { + foreach (string file in Directory.GetFiles(dir, "*.js", SearchOption.AllDirectories)) + { + JsHintRunner runner = new JsHintRunner(file); + runner.RunCompiler(); + } + } + } + + public void Dispose() + { + if (!_isDisposed) + { + //_document.Dispose(); + _runner.Dispose(); + } + + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/JavaScript/JsHintRunner.cs b/EditorExtensions/Commands/JavaScript/JsHintRunner.cs new file mode 100644 index 000000000..bc1e2b9ab --- /dev/null +++ b/EditorExtensions/Commands/JavaScript/JsHintRunner.cs @@ -0,0 +1,246 @@ +using EnvDTE; +using Microsoft.VisualStudio.Shell; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web.Script.Serialization; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal class JsHintRunner : IDisposable + { + private ErrorListProvider _provider; + private static Dictionary _providers = new Dictionary(); + private string _fileName; + private bool _isDisposed; + + static JsHintRunner() + { + EditorExtensionsPackage.DTE.Events.SolutionEvents.AfterClosing += SolutionEvents_AfterClosing; + } + + static void SolutionEvents_AfterClosing() + { + Reset(); + EditorExtensionsPackage.DTE.Events.SolutionEvents.AfterClosing -= SolutionEvents_AfterClosing; + } + + public JsHintRunner(string fileName) + { + _fileName = fileName; + + if (_providers.ContainsKey(fileName)) + { + _provider = _providers[fileName]; + } + else + { + _provider = new ErrorListProvider(EditorExtensionsPackage.Instance); + _providers.Add(fileName, _provider); + } + } + + public void RunCompiler() + { + if (!_isDisposed && !ShouldIgnore(_fileName)) + { + EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: Running JSHint..."; + JsHintCompiler lint = new JsHintCompiler(Dispatcher.CurrentDispatcher); + + System.Threading.Tasks.Task.Run(() => + { + using (StreamReader reader = new StreamReader(_fileName)) + { + string content = reader.ReadToEnd(); + + lint.Completed += LintCompletedHandler; + lint.Compile(content, _fileName); + } + }); + } + } + + public static void Reset() + { + foreach (string key in _providers.Keys) + { + _providers[key].Tasks.Clear(); + _providers[key].Dispose(); + } + + _providers.Clear(); + } + + public static bool ShouldIgnore(string file) + { + if (!Path.GetExtension(file).Equals(".js", StringComparison.OrdinalIgnoreCase) || + file.EndsWith(".min.js") || + file.EndsWith(".debug.js") || + file.EndsWith(".intellisense.js") || + !File.Exists(file) || + EditorExtensionsPackage.DTE.Solution.FindProjectItem(file) == null) + { + return true; + } + + string name = Path.GetFileName(file); + + foreach (string regex in _ignoreList) + { + if (Regex.IsMatch(name, regex, RegexOptions.IgnoreCase)) + { + return true; + } + } + + return false; + } + + private static List _ignoreList = new List() + { + @"jquery-([0-9\.]+)\.js", + @"jquery-ui-([0-9\.]+)\.js", + @"knockout-([0-9\.]+)\.js", + @"modernizr-([0-9\.]+)\.js", + @"backbone\.js", + @"angular\.js", + @"amplify\.js", + @"dojo\.js", + @"ember\.js", + @"handlebars-([0-9a-z\.]+)\.js", + @"mustache\.js", + @"underscore\.js", + @"yepnope\.js", + @"ext-core\.js", + @"highlight\.js", + @"history\.js", + @"require\.js", + @"sammy\.js", + @"json2\.js", + @"_references\.js", + @"MicrosoftAjax([a-z]+)\.js", + @"scriptaculous\.js ", + @"prototype\.js ", + @"qunit-([0-9a-z\.]+)\.js", + @"swfobject\.js", + @"bootstrap\.js", + @"webfont\.js", + @"zepto\.js", + }; + + private void LintCompletedHandler(object sender, CompilerEventArgs e) + { + using (JsHintCompiler lint = (JsHintCompiler)sender) + { + if (!_isDisposed) + { + System.Threading.Tasks.Task.Run(() => + { + ReadResult(e); + }); + } + + lint.Completed -= LintCompletedHandler; + } + + EditorExtensionsPackage.DTE.StatusBar.Clear(); + } + + private void ReadResult(CompilerEventArgs e) + { + try + { + JavaScriptSerializer serializer = new JavaScriptSerializer(); + Result[] results = serializer.Deserialize(e.Result); + + _provider.SuspendRefresh(); + _provider.Tasks.Clear(); + + foreach (Result error in results.Where(r => r != null)) + { + ErrorTask task = CreateTask(e.State, error); + _provider.Tasks.Add(task); + } + + _provider.ResumeRefresh(); + } + catch + { + Logger.Log("Error reading JSHint result"); + } + } + + private ErrorTask CreateTask(string data, Result error) + { + ErrorTask task = new ErrorTask() + { + Line = error.line, + Column = error.character, + ErrorCategory = GetOutputLocation(), + Category = TaskCategory.Html, + Document = data, + Priority = TaskPriority.Low, + Text = GetErrorMessage(error), + }; + + task.AddHierarchyItem(); + + task.Navigate += task_Navigate; + return task; + } + + private static TaskErrorCategory GetOutputLocation() + { + var location = (WESettings.Keys.FullErrorLocation)WESettings.GetInt(WESettings.Keys.JsHintErrorLocation); + + if (location == WESettings.Keys.FullErrorLocation.Errors) + return TaskErrorCategory.Error; + + if (location == WESettings.Keys.FullErrorLocation.Warnings) + return TaskErrorCategory.Warning; + + return TaskErrorCategory.Message; + } + + private string GetErrorMessage(Result error) + { + string raw = error.raw; + if (raw == "Missing radix parameter.") + raw = "When using the parseInt function, remember to specify the radix parameter. Example: parseInt('3', 10)"; + + return "JSHint (r10): " + raw.Replace("{a}", error.a).Replace("{b}", error.b); + } + + private void task_Navigate(object sender, EventArgs e) + { + Task task = sender as Task; + + _provider.Navigate(task, new Guid(EnvDTE.Constants.vsViewKindPrimary)); + + if (task.Column > 0) + { + var doc = (TextDocument)EditorExtensionsPackage.DTE.ActiveDocument.Object("textdocument"); + doc.Selection.MoveToLineAndOffset(task.Line, task.Column, false); + } + } + + public void Dispose() + { + if (!_isDisposed) + { + if (_providers.ContainsKey(_fileName)) + { + _providers.Remove(_fileName); + } + + _provider.Tasks.Clear(); + _provider.Dispose(); + } + + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/JavaScriptSmartIndentCommandTarget.cs b/EditorExtensions/Commands/JavaScriptSmartIndentCommandTarget.cs new file mode 100644 index 000000000..ce51120cc --- /dev/null +++ b/EditorExtensions/Commands/JavaScriptSmartIndentCommandTarget.cs @@ -0,0 +1,113 @@ +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System; +using System.ComponentModel.Composition; +using System.Windows.Forms; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType("JavaScript")] + [TextViewRole(PredefinedTextViewRoles.Document)] + class JavaScriptSmartIndentTextViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + [Import] + internal ICompletionBroker CompletionBroker { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + textView.Properties.GetOrCreateSingletonProperty(() => new JavaScriptSmartIndent(textViewAdapter, textView, CompletionBroker)); + } + } + + class JavaScriptSmartIndent : IOleCommandTarget + { + private ITextView _textView; + private IOleCommandTarget _nextCommandTarget; + private ICompletionBroker _broker; + + public JavaScriptSmartIndent(IVsTextView adapter, ITextView textView, ICompletionBroker broker) + { + _textView = textView; + _broker = broker; + adapter.AddCommandFilter(this, out _nextCommandTarget); + } + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + if (nCmdID == 3 && !_broker.IsCompletionActive(_textView)) + { + if (Indent()) + { + return VSConstants.S_OK; + } + } + + } + + return _nextCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + } + + private bool Indent() + { + int position = _textView.Caret.Position.BufferPosition.Position; + + + if (position == 0 || position == _textView.TextBuffer.CurrentSnapshot.Length || _textView.Selection.SelectedSpans[0].Length > 0) + return false; + + char before = _textView.TextBuffer.CurrentSnapshot.GetText(position - 1, 1)[0]; + char after = _textView.TextBuffer.CurrentSnapshot.GetText(position, 1)[0]; + + if (before == '{' && after == '}') + { + EditorExtensionsPackage.DTE.UndoContext.Open("Smart indent"); + + _textView.TextBuffer.Insert(position, Environment.NewLine + '\t'); + SnapshotPoint point = new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, position); + _textView.Selection.Select(new SnapshotSpan(point, 4), true); + + EditorExtensionsPackage.ExecuteCommand("Edit.FormatSelection"); + + _textView.Selection.Clear(); + SendKeys.Send("{ENTER}"); + + EditorExtensionsPackage.DTE.UndoContext.Close(); + + return true; + } + + return false; + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + for (int i = 0; i < cCmds; i++) + { + switch (prgCmds[i].cmdID) + { + case 3: + prgCmds[i].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); + return VSConstants.S_OK; + } + } + } + + return _nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/JsDocRegistry.cs b/EditorExtensions/Commands/JsDocRegistry.cs new file mode 100644 index 000000000..4792bff06 --- /dev/null +++ b/EditorExtensions/Commands/JsDocRegistry.cs @@ -0,0 +1,86 @@ +using Microsoft.Win32; +using System; +using System.IO; +using System.Reflection; + +namespace MadsKristensen.EditorExtensions +{ + public static class JsDocComments + { + private static string _fileName = "JsDocComments.js"; + + public static void Register() + { + try + { + string userPath = GetUserFilePath(); + + if (!File.Exists(userPath)) + { + string assembly = Assembly.GetExecutingAssembly().Location; + string folder = Path.GetDirectoryName(assembly).ToLowerInvariant(); + string file = Path.Combine(folder, "resources\\scripts\\JsDocComments.js"); + + if (!File.Exists(file)) + return; + + File.Copy(file, userPath); + UpdateRegistry(userPath); + } + } + catch + { + Logger.Log("Error registering JSDoc comments with Visual Studio"); + } + } + + private static string GetUserFilePath() + { + string user = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + string folder = Path.Combine(user, "Web Essentials"); + + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + return Path.Combine(folder, _fileName); + } + + private static void UpdateRegistry(string file) + { + using (RegistryKey key = EditorExtensionsPackage.Instance.UserRegistryRoot.OpenSubKey("JavaScriptLanguageService", true)) + { + if (key != null) + { + string value = (string)key.GetValue("ReferenceGroups"); + if (value.Contains(file)) + return; + + string newValue = value; + int index = value.IndexOf(_fileName); + + if (index > -1) + { + int start = value.LastIndexOf('|', index); + int length = index - start + _fileName.Length; + string oldPath = value.Substring(start, length); + newValue = value.Replace(oldPath, "|" + file); + } + else + { + int startWeb = value.IndexOf("Implicit (Web)"); + int semicolon = value.IndexOf(';', startWeb); + + if (semicolon > -1) + { + newValue = value.Insert(semicolon, "|" + file); + } + } + + key.SetValue("ReferenceGroups", newValue); + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/LESS/LessCreationListener.cs b/EditorExtensions/Commands/LESS/LessCreationListener.cs new file mode 100644 index 000000000..91ee8dbae --- /dev/null +++ b/EditorExtensions/Commands/LESS/LessCreationListener.cs @@ -0,0 +1,27 @@ +using Microsoft.Less.Core; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType(LessContentTypeDefinition.LessContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + class LessViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + + textView.Properties.GetOrCreateSingletonProperty(() => new LessExtractVariableCommandTarget(textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new LessExtractMixinCommandTarget(textViewAdapter, textView)); + } + } +} diff --git a/EditorExtensions/Commands/LESS/LessExtractMixinCommandTarget.cs b/EditorExtensions/Commands/LESS/LessExtractMixinCommandTarget.cs new file mode 100644 index 000000000..6a789d619 --- /dev/null +++ b/EditorExtensions/Commands/LESS/LessExtractMixinCommandTarget.cs @@ -0,0 +1,61 @@ +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class LessExtractMixinCommandTarget : CommandTargetBase + { + private DTE2 _dte; + + public LessExtractMixinCommandTarget(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidExtractCmdSet, PkgCmdIDList.ExtractMixin) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (TextView == null) + return false; + + CssEditorDocument document = CssEditorDocument.FromTextBuffer(TextView.TextBuffer); + + int position = TextView.Caret.Position.BufferPosition.Position; + ParseItem item = document.Tree.StyleSheet.ItemBeforePosition(position); + + ParseItem rule = LessExtractVariableCommandTarget.FindParent(item); + int mixinStart = rule.Start; + string name = Microsoft.VisualBasic.Interaction.InputBox("Name of the Mixin", "Web Essentials"); + + if (!string.IsNullOrEmpty(name)) + { + EditorExtensionsPackage.DTE.UndoContext.Open("Extract to mixin"); + + var selection = TextView.Selection.SelectedSpans[0]; + string text = selection.GetText(); + TextView.TextBuffer.Replace(selection.Span, "." + name + "();"); + TextView.TextBuffer.Insert(rule.Start, "." + name + "() {" + Environment.NewLine + text + Environment.NewLine + "}" + Environment.NewLine + Environment.NewLine); + + TextView.Selection.Select(new SnapshotSpan(TextView.TextBuffer.CurrentSnapshot, mixinStart, 1), false); + EditorExtensionsPackage.ExecuteCommand("Edit.FormatSelection"); + TextView.Selection.Clear(); + + EditorExtensionsPackage.DTE.UndoContext.Close(); + + return true; + } + + return false; + } + + protected override bool IsEnabled() + { + return TextView.Selection.SelectedSpans[0].Length > 0; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/LESS/LessExtractVariableCommandTarget.cs b/EditorExtensions/Commands/LESS/LessExtractVariableCommandTarget.cs new file mode 100644 index 000000000..6a7ee5c38 --- /dev/null +++ b/EditorExtensions/Commands/LESS/LessExtractVariableCommandTarget.cs @@ -0,0 +1,73 @@ +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.Less.Core; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + internal class LessExtractVariableCommandTarget : CommandTargetBase + { + private DTE2 _dte; + + public LessExtractVariableCommandTarget(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidExtractCmdSet, PkgCmdIDList.ExtractVariable) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (TextView == null) + return false; + + CssEditorDocument document = CssEditorDocument.FromTextBuffer(TextView.TextBuffer); + + int position = TextView.Caret.Position.BufferPosition.Position; + ParseItem item = document.Tree.StyleSheet.ItemBeforePosition(position); + + ParseItem rule = FindParent(item); + string text = item.Text; + string name = Microsoft.VisualBasic.Interaction.InputBox("Name of the variable", "Web Essentials"); + + if (!string.IsNullOrEmpty(name)) + { + EditorExtensionsPackage.DTE.UndoContext.Open("Extract to variable"); + + Span span = TextView.Selection.SelectedSpans[0].Span; + TextView.TextBuffer.Replace(span, "@" + name); + TextView.TextBuffer.Insert(rule.Start, "@" + name + ": " + text + ";" + Environment.NewLine + Environment.NewLine); + + EditorExtensionsPackage.DTE.UndoContext.Close(); + + return true; + } + + return false; + } + + public static ParseItem FindParent(ParseItem item) + { + ParseItem parent = item.Parent; + + while (true) + { + if (parent.Parent == null || parent.Parent is LessStyleSheet || parent.Parent is AtDirective) + break; + + parent = parent.Parent; + } + + return parent; + } + + protected override bool IsEnabled() + { + var span = TextView.Selection.SelectedSpans[0]; + return span.Length > 0 && !span.GetText().Contains("\r"); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/MoveRuleCommandTarget.cs b/EditorExtensions/Commands/MoveRuleCommandTarget.cs new file mode 100644 index 000000000..981d41a40 --- /dev/null +++ b/EditorExtensions/Commands/MoveRuleCommandTarget.cs @@ -0,0 +1,382 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Xml; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType(Microsoft.Web.Editor.CssContentTypeDefinition.CssContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + class MoveRuleTextViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + textView.Properties.GetOrCreateSingletonProperty(() => new MoveRuleTarget(textViewAdapter, textView)); + } + } + + class MoveRuleTarget : IOleCommandTarget + { + private ITextView _textView; + private IOleCommandTarget _nextCommandTarget; + private CssTree _tree; + + public MoveRuleTarget(IVsTextView adapter, ITextView textView) + { + this._textView = textView; + adapter.AddCommandFilter(this, out _nextCommandTarget); + } + + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + switch (nCmdID) + { + case 2400: + if (Move(Direction.Down)) + return VSConstants.S_OK; + break; + + case 2401: + if (Move(Direction.Up)) + return VSConstants.S_OK; + break; + } + } + + return _nextCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + } + + private enum Direction + { + Up, + Down + } + + private bool Move(Direction direction) + { + if (!EnsureInitialized()) + return false; + + int position = _textView.Caret.Position.BufferPosition.Position; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(position); + + Declaration dec = item.FindType(); + if (dec != null) + { + return HandleDeclaration(direction, dec); + } + + Selector selector = item.FindType(); + if (selector != null) + { + return HandleSelector(direction, selector); + } + + return false; + } + + private bool HandleDeclaration(Direction direction, Declaration declaration) + { + RuleBlock rule = declaration.FindType(); + if (rule == null || rule.Text.IndexOfAny(new[] { '\r', '\n' }) == -1 || (direction == Direction.Up && rule.Declarations.First() == declaration) || (direction == Direction.Down && rule.Declarations.Last() == declaration)) + return false; + + Declaration sibling = null; + string text = null; + + if (direction == Direction.Up) + { + sibling = rule.Declarations.ElementAt(rule.Declarations.IndexOf(declaration) - 1); + text = declaration.Text + sibling.Text; + } + else + { + sibling = rule.Declarations.ElementAt(rule.Declarations.IndexOf(declaration) + 1); + text = sibling.Text + declaration.Text; + } + + EditorExtensionsPackage.DTE.UndoContext.Open("Move CSS declaration"); + + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + int start = Math.Min(declaration.Start, sibling.Start); + int end = Math.Max(declaration.AfterEnd, sibling.AfterEnd); + edit.Replace(start, end - start, text); + edit.Apply(); + + if (direction == Direction.Up) + _textView.Caret.MoveTo(new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, sibling.Start + 1)); + + EditorExtensionsPackage.DTE.ExecuteCommand("Edit.FormatSelection"); + EditorExtensionsPackage.DTE.UndoContext.Close(); + } + + return true; + } + + private bool HandleSelector(Direction direction, Selector selector) + { + //new WriteBrowserXml().Parse(); + RuleSet rule = selector.FindType(); + if (rule == null) + return false; + + if (direction == Direction.Up) + { + rule = rule.PreviousSibling as RuleSet; + if (rule == null) + return false; + } + + EditorExtensionsPackage.DTE.UndoContext.Open("Move CSS rule"); + + using (ITextEdit edit = _textView.TextBuffer.CreateEdit()) + { + int position = SwapItemWithNextSibling(rule, edit); + if (position > -1) + { + if (direction == Direction.Down) + _textView.Caret.MoveTo(new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, position + 1)); + else + _textView.Caret.MoveTo(new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, rule.Start + 1)); + + // TODO: Format both rules + EditorExtensionsPackage.DTE.ExecuteCommand("Edit.FormatSelection"); + } + + EditorExtensionsPackage.DTE.UndoContext.Close(); + } + + return true; + } + + private int SwapItemWithNextSibling(ParseItem item, ITextEdit edit) + { + RuleSet next = item.NextSibling as RuleSet; + if (next == null) + return -1; + + ITextSnapshot snapshot = _textView.TextBuffer.CurrentSnapshot; + string whitespace = snapshot.GetText(item.AfterEnd, next.Start - item.AfterEnd); + string text = next.Text + whitespace + item.Text; + + edit.Replace(item.Start, next.AfterEnd - item.Start, text); + edit.Apply(); + + return item.Start + next.Length + whitespace.Length; + } + + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + { + if (pguidCmdGroup == typeof(VSConstants.VSStd2KCmdID).GUID) + { + for (int i = 0; i < cCmds; i++) + { + switch (prgCmds[i].cmdID) + { + case 2401: // Up + case 2400: // Down + prgCmds[i].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); + return VSConstants.S_OK; + } + } + } + + return _nextCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } + + public bool EnsureInitialized() + { + if (_tree == null && Microsoft.Web.Editor.WebEditor.Host != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_textView.TextBuffer); + _tree = document.Tree; + } + catch (ArgumentNullException) + { + } + } + + return _tree != null; + } + } + + public class WriteBrowserXml + { + private const string _fileName = @"C:\Users\madsk\Documents\visual studio 2012\Projects\RealWorldValidator\RealWorldValidator\App_Data\browsers.xml"; + + public void Parse() + { + ICssSchemaInstance root = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + IEnumerable schemas = GetAllSchemas(root); + using (XmlWriter writer = XmlWriter.Create(_fileName)) + { + writer.WriteStartElement("css"); + + // @-Directives + List directives = new List(root.AtDirectives); + directives.AddRange(schemas.SelectMany(s => s.AtDirectives)); + directives = RemoveDuplicates(directives); + + writer.WriteStartElement("atDirectives"); + WriteSection(writer, directives); + //WriteSection(writer, root.AtDirectives); + //foreach (var schema in schemas) + // WriteSection(writer, schema.AtDirectives); + writer.WriteEndElement(); + + // Pseudos + List pseudos = new List(root.PseudoClassesAndElements); + pseudos.AddRange(schemas.SelectMany(s => s.PseudoClassesAndElements)); + pseudos = RemoveDuplicates(pseudos); + + writer.WriteStartElement("pseudoClasses"); + WriteSection(writer, pseudos.Where(p => p.DisplayText[1] != ':')); + writer.WriteEndElement(); + + writer.WriteStartElement("pseudoElements"); + WriteSection(writer, pseudos.Where(p => p.DisplayText[1] == ':')); + writer.WriteEndElement(); + + // Properties + List properties = new List(root.Properties); + properties.AddRange(schemas.SelectMany(s => s.Properties)); + properties = RemoveDuplicates(properties); + + writer.WriteStartElement("properties"); + WriteProperties(writer, properties, root); + //WriteProperties(writer, root.Properties, root); + //foreach (var schema in schemas) + // WriteProperties(writer, schema.Properties, schema); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + } + + private List RemoveDuplicates(List list) + { + for (int i = list.Count() - 1; i > -1; i--) + { + if (list.Count(p => p.DisplayText == list.ElementAt(i).DisplayText) > 1) + list.RemoveAt(i); + } + + return list; + } + + string[] vs = new[] { "@-we-palette", "@unspecified", "@global", "@specific" }; + + private IEnumerable GetAllSchemas(ICssSchemaInstance rootSchema) + { + foreach (ICssCompletionListEntry directive in rootSchema.AtDirectives) + { + if (vs.Contains(directive.DisplayText)) + continue; + + ICssSchemaInstance schema = rootSchema.GetAtDirectiveSchemaInstance(directive.DisplayText); + if (schema != null && schema.Properties.Count() != rootSchema.Properties.Count()) + yield return schema; + } + } + + private void WriteSection(XmlWriter writer, IEnumerable entries) + { + foreach (ICssCompletionListEntry entry in entries.OrderBy(e => e.DisplayText)) + { + writer.WriteStartElement("entry"); + writer.WriteAttributeString("name", entry.DisplayText); + writer.WriteAttributeString("version", entry.GetAttribute("version")); + WriteBrowserSupport(writer, entry); + + if (!string.IsNullOrEmpty(entry.GetAttribute("standard-reference"))) + writer.WriteAttributeString("ref", entry.GetAttribute("standard-reference")); + + if (!string.IsNullOrEmpty(entry.GetAttribute("syntax"))) + writer.WriteAttributeString("syntax", entry.GetAttribute("syntax")); + + if (!string.IsNullOrEmpty(entry.GetAttribute("description"))) + writer.WriteElementString("desc", entry.GetAttribute("description")); + + writer.WriteEndElement(); + } + } + + private void WriteProperties(XmlWriter writer, IEnumerable entries, ICssSchemaInstance schema) + { + foreach (ICssCompletionListEntry entry in entries.OrderBy(e => e.DisplayText)) + { + writer.WriteStartElement("entry"); + writer.WriteAttributeString("name", entry.DisplayText); + writer.WriteAttributeString("restriction", entry.GetAttribute("restriction")); + writer.WriteAttributeString("version", entry.GetAttribute("version")); + WriteBrowserSupport(writer, entry); + + if (!string.IsNullOrEmpty(entry.GetAttribute("standard-reference"))) + writer.WriteAttributeString("ref", entry.GetAttribute("standard-reference")); + + if (!string.IsNullOrEmpty(entry.GetAttribute("syntax"))) + writer.WriteAttributeString("syntax", entry.GetAttribute("syntax")); + + if (!string.IsNullOrEmpty(entry.GetAttribute("description"))) + writer.WriteElementString("desc", entry.GetAttribute("description")); + + var values = schema.GetPropertyValues(entry.DisplayText); + if (values.Count() > 2) + { + writer.WriteStartElement("values"); + foreach (ICssCompletionListEntry value in values.OrderBy(v => v.DisplayText)) + { + if (value.DisplayText == "initial" || value.DisplayText == "inherit") + continue; + + writer.WriteStartElement("value"); + writer.WriteAttributeString("name", value.DisplayText); + writer.WriteAttributeString("version", value.GetAttribute("version") != string.Empty ? value.GetAttribute("version") : entry.GetAttribute("version")); + WriteBrowserSupport(writer, value); + + if (!string.IsNullOrEmpty(value.GetAttribute("description"))) + writer.WriteElementString("desc", value.GetAttribute("description")); + + writer.WriteEndElement(); + } + writer.WriteEndElement(); + } + + writer.WriteEndElement(); + } + } + + private static void WriteBrowserSupport(XmlWriter writer, ICssCompletionListEntry entry) + { + string attr = entry.GetAttribute("browsers"); + + if (string.IsNullOrEmpty(attr)) + attr = "all"; + + writer.WriteAttributeString("browsers", attr); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/PasteJsonAsTypeScript.cs b/EditorExtensions/Commands/PasteJsonAsTypeScript.cs new file mode 100644 index 000000000..a96cf0e84 --- /dev/null +++ b/EditorExtensions/Commands/PasteJsonAsTypeScript.cs @@ -0,0 +1,136 @@ +using Microsoft.VisualStudio.Web.PasteJson; +using System; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Text; +using System.Text.RegularExpressions; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IPasteJsonCodeGenerator))] + [ExportMetadata("CodeGeneratorType", "TypeScript")] + internal class CSharpCodeGenerator : IPasteJsonCodeGenerator + { + private Regex _validIdentifierRegex = new Regex(@"[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Nl}\p{Mn}\p{Mc}\p{Cf}\p{Pc}\p{Lm}]"); + + public string GenerateStartClass(string className) + { + return string.Format("interface {0}", className) + Environment.NewLine + "{"; + } + + public string GenerateProperty(PasteJsonUtil.LangIndependentType langIndependentType, string propertyName) + { + return string.Format("{1}: {0};", GeneratePropertyTypeName(langIndependentType), propertyName); + } + + public string GenerateObjectProperty(string typeOfObject, string propertyName) + { + return string.Format("{1}: {0};", typeOfObject, propertyName); + } + + public string GenerateArrayProperty(int dimensions, string typeOfArray, string propertyName) + { + if (dimensions > 0) + { + string mutliDimension = GetArrayDeclaration(dimensions); + return string.Format("{2}: {0}{1};", typeOfArray, mutliDimension, propertyName); + } + return null; + } + + public string GenerateArrayProperty(int dimensions, PasteJsonUtil.LangIndependentType langIndependentType, string propertyName) + { + if (dimensions > 0) + { + string mutliDimension = GetArrayDeclaration(dimensions); + return string.Format("{2}: {0}{1};", GeneratePropertyTypeName(langIndependentType), mutliDimension, propertyName); + } + return null; + } + + private string GetArrayDeclaration(int dimension) + { + StringBuilder arrayDeclaration = new StringBuilder(); + for (int loop = 1; loop <= dimension; loop++) + { + arrayDeclaration.Append(GeneratePropertyTypeName(PasteJsonUtil.LangIndependentType.Array)); + } + return arrayDeclaration.ToString(); + } + + public string GenerateEndClass(string className) + { + return "}"; + } + + public string MakeValidName(string name) + { + return _validIdentifierRegex.Replace(name, ""); + } + + private string GeneratePropertyTypeName(PasteJsonUtil.LangIndependentType langIndependentType) + { + string returnType = string.Empty; + Debug.Assert(langIndependentType != PasteJsonUtil.LangIndependentType.Object, "I should not be expecting Object"); + + switch (langIndependentType) + { + case PasteJsonUtil.LangIndependentType.Array: + returnType = "[]"; + break; + case PasteJsonUtil.LangIndependentType.Boolean: + returnType = "bool"; + break; + case PasteJsonUtil.LangIndependentType.Date: + returnType = "Date"; + break; + case PasteJsonUtil.LangIndependentType.Double: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.Float: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.Integer: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.Long: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.NullableBoolean: + returnType = "bool"; + break; + case PasteJsonUtil.LangIndependentType.NullableDate: + returnType = "Date"; + break; + case PasteJsonUtil.LangIndependentType.NullableDouble: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.NullableFloat: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.NullableInteger: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.NullableLong: + returnType = "number"; + break; + case PasteJsonUtil.LangIndependentType.NullOrUndefined: + returnType = "any"; + break; + case PasteJsonUtil.LangIndependentType.String: + returnType = "string"; + break; + case PasteJsonUtil.LangIndependentType.Unknown: + returnType = "any"; + break; + case PasteJsonUtil.LangIndependentType.Uri: + returnType = "string"; + break; + default: + Debug.Assert(true, "Property Type:" + langIndependentType.ToString() + " is not supported !!"); + break; + } + return returnType; + } + } +} diff --git a/EditorExtensions/Commands/Shared/EncodeSelectionCommandTarget.cs b/EditorExtensions/Commands/Shared/EncodeSelectionCommandTarget.cs new file mode 100644 index 000000000..193558618 --- /dev/null +++ b/EditorExtensions/Commands/Shared/EncodeSelectionCommandTarget.cs @@ -0,0 +1,81 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Web; + +namespace MadsKristensen.EditorExtensions +{ + internal class EncodeSelection : CommandTargetBase + { + private DTE2 _dte; + private static uint[] _commandIds = new uint[] { + PkgCmdIDList.htmlEncode, + PkgCmdIDList.htmlDecode, + PkgCmdIDList.attrEncode, + PkgCmdIDList.urlEncode, + PkgCmdIDList.urlDecode, + PkgCmdIDList.urlPathEncode, + PkgCmdIDList.jsEncode, + }; + + private delegate string Replacement(string original); + + public EncodeSelection(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidEditorExtensionsCmdSet, _commandIds) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + switch (commandId) + { + case PkgCmdIDList.htmlEncode: + return Replace(HttpUtility.HtmlEncode); + case PkgCmdIDList.htmlDecode: + return Replace(HttpUtility.HtmlDecode); + case PkgCmdIDList.attrEncode: + return Replace(HttpUtility.HtmlAttributeEncode); + case PkgCmdIDList.urlEncode: + return Replace(HttpUtility.UrlEncode); + case PkgCmdIDList.urlDecode: + return Replace(HttpUtility.UrlDecode); + case PkgCmdIDList.urlPathEncode: + return Replace(HttpUtility.UrlPathEncode); + case PkgCmdIDList.jsEncode: + return Replace(HttpUtility.JavaScriptStringEncode); + } + + return true; + } + + private bool Replace(Replacement callback) + { + TextDocument document = GetTextDocument(); + string replacement = callback(document.Selection.Text); + + _dte.UndoContext.Open(callback.Method.Name); + document.Selection.Insert(replacement, 0); + _dte.UndoContext.Close(); + + return true; + } + + private TextDocument GetTextDocument() + { + return _dte.ActiveDocument.Object("TextDocument") as TextDocument; + } + + protected override bool IsEnabled() + { + if (TextView != null && TextView.Selection.SelectedSpans.Count > 0) + { + return TextView.Selection.SelectedSpans[0].Length > 0; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs b/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs new file mode 100644 index 000000000..99c104569 --- /dev/null +++ b/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs @@ -0,0 +1,48 @@ +using EnvDTE80; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + internal class MinifySelection : CommandTargetBase + { + private DTE2 _dte; + + public MinifySelection(IVsTextView adapter, IWpfTextView textView) + : base(adapter, textView, GuidList.guidMinifyCmdSet, PkgCmdIDList.MinifySelection) + { + _dte = EditorExtensionsPackage.DTE; + } + + protected override bool Execute(uint commandId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (TextView != null) + { + _dte.UndoContext.Open("Minify"); + + string content = TextView.Selection.SelectedSpans[0].GetText(); + string extension = Path.GetExtension(_dte.ActiveDocument.FullName).ToLowerInvariant(); + string result = MinifyFileMenu.MinifyString(extension, content); + + TextView.TextBuffer.Replace(TextView.Selection.SelectedSpans[0].Span, result); + + _dte.UndoContext.Close(); + } + + return true; + } + + protected override bool IsEnabled() + { + if (TextView != null && TextView.Selection.SelectedSpans.Count > 0) + { + return TextView.Selection.SelectedSpans[0].Length > 0; + } + + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Commands/Shared/TextCreationListener.cs b/EditorExtensions/Commands/Shared/TextCreationListener.cs new file mode 100644 index 000000000..9d5c8c5e0 --- /dev/null +++ b/EditorExtensions/Commands/Shared/TextCreationListener.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IVsTextViewCreationListener))] + [ContentType("text")] + [TextViewRole(PredefinedTextViewRoles.Document)] + class TextViewCreationListener : IVsTextViewCreationListener + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } + + [Import] + internal ICompletionBroker CompletionBroker { get; set; } + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); + + textView.Properties.GetOrCreateSingletonProperty(() => new EncodeSelection(textViewAdapter, textView)); + } + } +} diff --git a/EditorExtensions/Commands/TypeThrough/CSSTypeThroughControllerProvider.cs b/EditorExtensions/Commands/TypeThrough/CSSTypeThroughControllerProvider.cs new file mode 100644 index 000000000..8c37932ad --- /dev/null +++ b/EditorExtensions/Commands/TypeThrough/CSSTypeThroughControllerProvider.cs @@ -0,0 +1,84 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IIntellisenseControllerProvider))] + [ContentType(CssContentTypeDefinition.CssContentType)] + [Name("CSS Type Through Completion Controller")] + [Order(Before = "Default Completion Controller")] + [TextViewRole(PredefinedTextViewRoles.Editable)] + internal class CssTypeThroughControllerProvider : IIntellisenseControllerProvider + { + public IIntellisenseController TryCreateIntellisenseController(ITextView view, IList subjectBuffers) + { + if (subjectBuffers[0].ContentType.IsOfType(CssContentTypeDefinition.CssContentType)) + { + var completionController = ServiceManager.GetService(subjectBuffers[0]); + + if (completionController == null) + completionController = new CssTypeThroughController(view, subjectBuffers); + + return completionController; + } + + return null; + } + } + + internal class CssTypeThroughController : TypeThroughController + { + public CssTypeThroughController(ITextView textView, IList subjectBuffers) + : base(textView, subjectBuffers) + { + } + + protected override bool CanComplete(ITextBuffer textBuffer, int position) + { + var document = CssEditorDocument.FromTextBuffer(textBuffer); + + var item = document.StyleSheet.ComplexItemFromRange(position, 0); + if (item is Comment) + return false; + + var tokenItem = document.StyleSheet.ItemFromRange(position, 0); + var ti = tokenItem as TokenItem; + if (ti != null) + { + if ((ti.TokenType == CssTokenType.String || ti.TokenType == CssTokenType.MultilineString) && !ti.IsUnclosed) + return false; + } + + return true; + } + + protected override char GetCompletionCharacter(char typedCharacter) + { + switch (typedCharacter) + { + //case '\"': + //case '\'': + // return typedCharacter; + + //case '[': + // return ']'; + + //case '(': + // return ')'; + + case '{': + return '}'; + } + + return '\0'; + } + } +} diff --git a/EditorExtensions/Commands/TypeThrough/JavaScriptTypeThroughControllerProvider.cs b/EditorExtensions/Commands/TypeThrough/JavaScriptTypeThroughControllerProvider.cs new file mode 100644 index 000000000..d3b7004b6 --- /dev/null +++ b/EditorExtensions/Commands/TypeThrough/JavaScriptTypeThroughControllerProvider.cs @@ -0,0 +1,76 @@ +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IIntellisenseControllerProvider))] + [ContentType("JavaScript")] + [ContentType("TypeScript")] + [Name("JavaScript Type Through Completion Controller")] + [Order(Before = "Default Completion Controller")] + [TextViewRole(PredefinedTextViewRoles.Editable)] + internal class JavaScriptTypeThroughControllerProvider : IIntellisenseControllerProvider + { + public IIntellisenseController TryCreateIntellisenseController(ITextView view, IList subjectBuffers) + { + if (subjectBuffers.Count > 0 && (subjectBuffers[0].ContentType.IsOfType("JavaScript") || subjectBuffers[0].ContentType.IsOfType("TypeScript"))) + { + var completionController = ServiceManager.GetService(subjectBuffers[0]); + + if (completionController == null) + completionController = new JavaScriptTypeThroughController(view, subjectBuffers); + + return completionController; + } + + return null; + } + } + + internal class JavaScriptTypeThroughController : TypeThroughController + { + public JavaScriptTypeThroughController(ITextView textView, IList subjectBuffers) + : base(textView, subjectBuffers) + { + } + + protected override bool CanComplete(ITextBuffer textBuffer, int position) + { + bool result = WESettings.GetBoolean(WESettings.Keys.JavaScriptAutoCloseBraces); + + if (result) + { + var line = textBuffer.CurrentSnapshot.GetLineFromPosition(position); + result = line.Start.Position + line.GetText().TrimEnd('\r', '\n', ' ', ';', ',').Length == position + 1; + } + + return result; + } + + protected override char GetCompletionCharacter(char typedCharacter) + { + switch (typedCharacter) + { + //case '\"': + //case '\'': + // return typedCharacter; + + case '[': + return ']'; + + case '(': + return ')'; + + case '{': + return '}'; + } + + return '\0'; + } + } +} diff --git a/EditorExtensions/Commands/TypeThrough/LESSTypeThroughControllerProvider.cs b/EditorExtensions/Commands/TypeThrough/LESSTypeThroughControllerProvider.cs new file mode 100644 index 000000000..5a4996557 --- /dev/null +++ b/EditorExtensions/Commands/TypeThrough/LESSTypeThroughControllerProvider.cs @@ -0,0 +1,58 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.Less.Core; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IIntellisenseControllerProvider))] + [ContentType(LessContentTypeDefinition.LessContentType)] + [Name("LESS Type Through Completion Controller")] + [Order(Before = "Default Completion Controller")] + [TextViewRole(PredefinedTextViewRoles.Editable)] + internal class LessTypeThroughControllerProvider : IIntellisenseControllerProvider + { + public IIntellisenseController TryCreateIntellisenseController(ITextView view, IList subjectBuffers) + { + var completionController = ServiceManager.GetService(subjectBuffers[0]); + + if (completionController == null) + completionController = new LessTypeThroughController(view, subjectBuffers); + + return completionController; + } + } + + internal class LessTypeThroughController : CssTypeThroughController + { + public LessTypeThroughController(ITextView view, IList subjectBuffers) : + base(view, subjectBuffers) + { + } + + protected override bool CanComplete(ITextBuffer textBuffer, int position) + { + var document = CssEditorDocument.FromTextBuffer(textBuffer); + + var item = document.StyleSheet.ComplexItemFromRange(position, 0); + if (item is CppComment || item is CppCommentText) + return false; + + var tokenItem = document.StyleSheet.ItemFromRange(position, 0); + var ti = tokenItem as TokenItem; + if (ti != null) + { + if (ti.Token.IsComment) + return false; + } + + return base.CanComplete(textBuffer, position); + } + } +} diff --git a/EditorExtensions/Commands/TypeThrough/ProvisionalText.cs b/EditorExtensions/Commands/TypeThrough/ProvisionalText.cs new file mode 100644 index 000000000..38505bf7f --- /dev/null +++ b/EditorExtensions/Commands/TypeThrough/ProvisionalText.cs @@ -0,0 +1,264 @@ +using System; +using System.Linq; +using System.ComponentModel.Composition; +using System.Windows; +using System.Windows.Media; +using System.Windows.Shapes; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Projection; +using Microsoft.VisualStudio.Utilities; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IWpfTextViewCreationListener))] + [ContentType("CSS")] + [ContentType("JavaScript")] + [TextViewRole(PredefinedTextViewRoles.Document)] + internal sealed class HtmlProvisionalTextHighlightFactory : IWpfTextViewCreationListener + { + [Export(typeof(AdornmentLayerDefinition))] + [Name("HtmlProvisionalTextHighlight")] + [Order(Before = PredefinedAdornmentLayers.Outlining)] + [TextViewRole(PredefinedTextViewRoles.Document)] + public AdornmentLayerDefinition EditorAdornmentLayer { get; set; } + + public void TextViewCreated(IWpfTextView textView) + { + } + } + + public class ProvisionalText + { + public static bool IgnoreChange { get; set; } + + public event EventHandler OnClose; + public char ProvisionalChar { get; private set; } + public ITrackingSpan TrackingSpan { get; private set; } + + private ITextView _textView; + private IAdornmentLayer _layer; + private Path _highlightAdornment; + private Brush _highlightBrush; + private bool _overtype = false; + private bool _delete = false; + private bool _projectionsChanged = false; + private bool _adornmentRemoved = false; + private IProjectionBuffer _projectionBuffer; + + public ProvisionalText(ITextView textView, Span textSpan) + { + IgnoreChange = false; + + _textView = textView; + + var wpfTextView = _textView as IWpfTextView; + _layer = wpfTextView.GetAdornmentLayer("HtmlProvisionalTextHighlight"); + + var textBuffer = _textView.TextBuffer; + var snapshot = textBuffer.CurrentSnapshot; + var provisionalCharSpan = new Span(textSpan.End - 1, 1); + + TrackingSpan = snapshot.CreateTrackingSpan(textSpan, SpanTrackingMode.EdgeExclusive); + _textView.Caret.PositionChanged += OnCaretPositionChanged; + + textBuffer.Changed += OnTextBufferChanged; + textBuffer.PostChanged += OnPostChanged; + + var _projectionBuffer = _textView.TextBuffer as IProjectionBuffer; + if (_projectionBuffer != null) + { + _projectionBuffer.SourceSpansChanged += OnSourceSpansChanged; + } + + Color highlightColor = SystemColors.HighlightColor; + Color baseColor = Color.FromArgb(96, highlightColor.R, highlightColor.G, highlightColor.B); + _highlightBrush = new SolidColorBrush(baseColor); + + ProvisionalChar = snapshot.GetText(provisionalCharSpan)[0]; + HighlightSpan(provisionalCharSpan.Start); + } + + public Span CurrentSpan + { + get + { + return TrackingSpan.GetSpan(_textView.TextBuffer.CurrentSnapshot); + } + } + + private void EndTracking() + { + if (_textView != null) + { + ClearHighlight(); + + if (_projectionBuffer != null) + { + _projectionBuffer.SourceSpansChanged -= OnSourceSpansChanged; + _projectionBuffer = null; + } + + if (_projectionsChanged || _adornmentRemoved) + { + _projectionsChanged = false; + _adornmentRemoved = false; + } + + _textView.TextBuffer.Changed -= OnTextBufferChanged; + _textView.TextBuffer.PostChanged -= OnPostChanged; + + _textView.Caret.PositionChanged -= OnCaretPositionChanged; + _textView = null; + + if (OnClose != null) + OnClose(this, EventArgs.Empty); + } + } + + public bool IsPositionInSpan(int position) + { + if (_textView != null) + { + if (CurrentSpan.Contains(position) && position > CurrentSpan.Start) + return true; + } + + return false; + } + + private void OnSourceSpansChanged(object sender, ProjectionSourceSpansChangedEventArgs e) + { + _projectionsChanged = true; + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ResoreHighlight())); + } + + void OnCaretPositionChanged(object sender, CaretPositionChangedEventArgs e) + { + // If caret moves outside of the text tracking span, consider text final + var position = _textView.Caret.Position.BufferPosition; + + if (!CurrentSpan.Contains(position) || position == CurrentSpan.Start) + { + EndTracking(); + } + } + + void OnPostChanged(object sender, EventArgs e) + { + if (_textView != null && !IgnoreChange && !_projectionsChanged) + { + if (_overtype || _delete) + { + _textView.TextBuffer.Replace(new Span(CurrentSpan.End - 1, 1), String.Empty); + EndTracking(); + } + else + { + HighlightSpan(CurrentSpan.End - 1); + } + } + } + + void OnTextBufferChanged(object sender, TextContentChangedEventArgs e) + { + // Zero changes typically means secondary buffer regeneration + if (e.Changes.Count == 0) + { + _projectionsChanged = true; + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ResoreHighlight())); + } + + if (_textView != null && !IgnoreChange && !_projectionsChanged) + { + // If there is a change outside text span or change over provisional + // text, we are done here: commit provisional text and disconnect. + + if (CurrentSpan.Length > 0 && e.Changes.Count == 1) + { + var change = e.Changes[0]; + + if (CurrentSpan.Contains(change.OldSpan)) + { + // Check provisional text overtype + if (change.OldLength == 0 && change.NewLength == 1 && change.OldPosition == CurrentSpan.End - 2) + { + char ch = _textView.TextBuffer.CurrentSnapshot.GetText(change.NewPosition, 1)[0]; + + if (ch == ProvisionalChar) + _overtype = true; + } + else if (change.NewLength > 0 && change.NewText.Last() == ProvisionalChar)//(change.NewLength == 0 && change.OldLength > 0 && change.OldPosition == CurrentSpan.Start) + { + // Deleting open quote or brace should also delete provisional character + _delete = true; + } + + return; + } + } + + EndTracking(); + } + } + + private void ResoreHighlight() + { + if (_textView != null && (_projectionsChanged || _adornmentRemoved)) + { + HighlightSpan(CurrentSpan.End - 1); + } + + _projectionsChanged = false; + _adornmentRemoved = false; + } + + void HighlightSpan(int bufferPosition) + { + ClearHighlight(); + + var wpfTextView = _textView as IWpfTextView; + var snapshotSpan = new SnapshotSpan(wpfTextView.TextBuffer.CurrentSnapshot, new Span(bufferPosition, 1)); + + Geometry highlightGeometry = wpfTextView.TextViewLines.GetTextMarkerGeometry(snapshotSpan); + if (highlightGeometry != null) + { + _highlightAdornment = new Path(); + _highlightAdornment.Data = highlightGeometry; + _highlightAdornment.Fill = _highlightBrush; + } + + if (_highlightAdornment != null) + { + _layer.AddAdornment( + AdornmentPositioningBehavior.TextRelative, snapshotSpan, + this, _highlightAdornment, new AdornmentRemovedCallback(OnAdornmentRemoved)); + } + } + + private bool _removing = false; + + private void OnAdornmentRemoved(object tag, UIElement element) + { + if (_removing) + return; + + _adornmentRemoved = true; + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ResoreHighlight())); + } + + private void ClearHighlight() + { + if (_highlightAdornment != null) + { + _removing = true; + + _layer.RemoveAdornment(_highlightAdornment); + _highlightAdornment = null; + + _removing = false; + } + } + } +} diff --git a/EditorExtensions/Commands/TypeThrough/TypeThroughController.cs b/EditorExtensions/Commands/TypeThrough/TypeThroughController.cs new file mode 100644 index 000000000..2f54e8a6c --- /dev/null +++ b/EditorExtensions/Commands/TypeThrough/TypeThroughController.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace MadsKristensen.EditorExtensions +{ + public class TypeThroughController : IIntellisenseController + { + ITextBuffer _textBuffer; + ITextView _textView; + + List _provisionalTexts = new List(); + char _typedChar = '\0'; + bool _processing = false; + int _caretPosition = 0; + int _bufferVersionWaterline; + + public TypeThroughController(ITextView textView, IList subjectBuffers) + { + _textBuffer = subjectBuffers[0]; + _textView = textView; + + _textBuffer.Changed += TextBuffer_Changed; + _textBuffer.PostChanged += TextBuffer_PostChanged; + + _bufferVersionWaterline = _textBuffer.CurrentSnapshot.Version.ReiteratedVersionNumber; + } + + protected virtual bool CanComplete(ITextBuffer textBuffer, int position) + { + return true; + } + + void TextBuffer_PostChanged(object sender, System.EventArgs e) + { + if (!_processing && _typedChar != '\0') + { + OnPostTypeChar(_typedChar); + _typedChar = '\0'; + } + } + + void TextBuffer_Changed(object sender, TextContentChangedEventArgs e) + { + if (_processing) + return; + + _typedChar = '\0'; + + if (e.Changes.Count == 1 && e.AfterVersion.ReiteratedVersionNumber > _bufferVersionWaterline) + { + var change = e.Changes[0]; + + _bufferVersionWaterline = e.AfterVersion.ReiteratedVersionNumber; + + // Change length may be > 1 in autoformatting languages. + // However, there will be only one non-ws character in the change. + // Be careful when is inserted: the change won't + // actually be in this buffer. + + var snapshot = _textBuffer.CurrentSnapshot; + if (change.NewSpan.End <= snapshot.Length) + { + var text = _textBuffer.CurrentSnapshot.GetText(change.NewSpan); + text = text.Trim(); + + if (text.Length == 1) + { + // Allow completion of different characters inside spans, but not when + // character and its completion pair is the same. For example, we do + // want to complete () in foo(bar|) when user types ( after bar. However, + // we do not want to complete " when user is typing in a string which + // was already completed and instead " should be a terminating type-through. + + var typedChar = text[0]; + var completionChar = GetCompletionCharacter(typedChar); + + var caretPosition = GetCaretPositionInBuffer(); + if (caretPosition.HasValue) + { + bool compatible = true; + + var innerText = GetInnerProvisionalText(); + if (innerText != null) + compatible = IsCompatibleCharacter(innerText.ProvisionalChar, typedChar); + + if (!IsPositionInProvisionalText(caretPosition.Value) || typedChar != completionChar || compatible) + { + _typedChar = typedChar; + _caretPosition = caretPosition.Value; + } + } + } + } + } + } + + protected virtual char GetCompletionCharacter(char typedCharacter) + { + switch (typedCharacter) + { + //case '\"': + //case '\'': + // return typedCharacter; + + //case '[': + // return ']'; + + //case '(': + // return ')'; + + case '{': + case '}': + return '}'; + } + + return '\0'; + } + + protected virtual bool IsCompatibleCharacter(char primaryCharacter, char candidateCharacter) + { + if (primaryCharacter == '\"' || primaryCharacter == '\'') + return false; // no completion in strings + + return true; + } + + private void OnPostTypeChar(char typedCharacter) + { + // When language autoformats, like JS, caret may be in a very different + // place by now. Check if store caret position still makes sense and + // if not, reacquire it. In contained language scenario + // current caret position may be beyond projection boundary like when + // typing at the end of onclick="return foo(". + + //var settings = WebEditor.GetSettings(_textBuffer.ContentType.TypeName); + //if (settings.GetBoolean(CommonSettings.InsertMatchingBracesKey)) + if (WESettings.GetBoolean(WESettings.Keys.AutoCloseCurlyBraces)) + { + char completionCharacter = GetCompletionCharacter(typedCharacter); + if (completionCharacter != '\0') + { + var viewCaretPosition = _textView.Caret.Position.BufferPosition; + _processing = true; + + var bufferCaretPosition = GetCaretPositionInBuffer(); + if (bufferCaretPosition.HasValue) + { + _caretPosition = bufferCaretPosition.Value; + } + else if (viewCaretPosition.Position == _textView.TextBuffer.CurrentSnapshot.Length) + { + _caretPosition = _textBuffer.CurrentSnapshot.Length; + } + + if (_caretPosition > 0) + { + if (CanComplete(_textBuffer, _caretPosition - 1)) + { + ProvisionalText.IgnoreChange = true; + _textView.TextBuffer.Replace(new Span(viewCaretPosition, 0), completionCharacter.ToString()); + ProvisionalText.IgnoreChange = false; + + _textView.Caret.MoveTo(new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, viewCaretPosition)); + + var provisionalText = new ProvisionalText(_textView, new Span(viewCaretPosition - 1, 2)); + provisionalText.OnClose += new System.EventHandler(OnCloseProvisionalText); + + _provisionalTexts.Add(provisionalText); + } + } + } + + _processing = false; + } + } + + private SnapshotPoint? GetCaretPositionInBuffer() + { + var viewCaretPosition = _textView.Caret.Position.BufferPosition.Position; + var snapshot = _textView.TextBuffer.CurrentSnapshot; + + if (viewCaretPosition > snapshot.Length) + return null; + + return _textView.BufferGraph.MapDownToBuffer( + new SnapshotPoint(_textView.TextBuffer.CurrentSnapshot, viewCaretPosition), PointTrackingMode.Positive, + _textBuffer, PositionAffinity.Predecessor); + } + + private bool IsPositionInProvisionalText(int position) + { + foreach (var pt in _provisionalTexts) + { + if (pt.IsPositionInSpan(position)) + return true; + } + + return false; + } + + private ProvisionalText GetInnerProvisionalText() + { + int minLength = Int32.MaxValue; + ProvisionalText innerText = null; + + foreach (var pt in _provisionalTexts) + { + if (pt.CurrentSpan.Length < minLength) + { + minLength = pt.CurrentSpan.Length; + innerText = pt; + } + } + + return innerText; + } + + private void OnCloseProvisionalText(object sender, EventArgs e) + { + _provisionalTexts.Remove(sender as ProvisionalText); + } + + #region IIntellisenseController Members + + public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) + { + if (_textBuffer != null) + { + _textBuffer.Changed += TextBuffer_Changed; + _textBuffer.PostChanged += TextBuffer_PostChanged; + } + } + + public void Detach(ITextView textView) + { + } + + public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) + { + if (_textBuffer != null) + { + _textBuffer.Changed -= TextBuffer_Changed; + _textBuffer.PostChanged -= TextBuffer_PostChanged; + } + } + + #endregion + } +} diff --git a/EditorExtensions/Completion/CompletionListEntry.cs b/EditorExtensions/Completion/CompletionListEntry.cs new file mode 100644 index 000000000..a3cd2ae5b --- /dev/null +++ b/EditorExtensions/Completion/CompletionListEntry.cs @@ -0,0 +1,77 @@ +using System; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + internal class CompletionListEntry : ICssCompletionListEntry + { + private string _name; + + public CompletionListEntry(string name, int sortingPriority = 0) + { + _name = name; + SortingPriority = sortingPriority; + } + + public string Description + { + get { return string.Empty; } + } + + public string DisplayText + { + get { return _name; } + } + + public string GetSyntax(Version version) + { + return string.Empty; + } + + public StandardGlyphGroup StandardGlyph + { + get { return StandardGlyphGroup.GlyphGroupEnumMember; } + } + + public string GetAttribute(string name) + { + return string.Empty; + } + + public string GetInsertionText(CssTextSource textSource, ITrackingSpan typingSpan) + { + return DisplayText; + } + + public string GetVersionedAttribute(string name, Version version) + { + return GetAttribute(name); + } + + public bool AllowQuotedString + { + get { return false; } + } + + public bool IsBuilder + { + get { return false; } + } + + public int SortingPriority { get; set; } + + + public bool IsSupported(BrowserVersion browser) + { + return true; + } + + public bool IsSupported(Version cssVersion) + { + return true; + } + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/AnimationNameCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/AnimationNameCompletionProvider.cs new file mode 100644 index 000000000..f9c3b8473 --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/AnimationNameCompletionProvider.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("AnimationNameCompletionProvider")] + internal class AnimationNameCompletionProvider : ICssCompletionListProvider + { + public CssCompletionContextType ContextType + { + get { return CssCompletionContextType.PropertyValue; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + HashSet entries = new HashSet(); + Declaration dec = context.ContextItem.FindType(); + + if (dec == null || dec.PropertyName == null || (!dec.PropertyName.Text.EndsWith("animation-name", StringComparison.OrdinalIgnoreCase) && dec.PropertyName.Text != "animation")) + return entries; + + StyleSheet stylesheet = context.ContextItem.StyleSheet; + var visitor = new CssItemCollector(); + stylesheet.Accept(visitor); + + foreach (KeyFramesDirective keyframes in visitor.Items) + { + if (!entries.Any(e => e.DisplayText.Equals(keyframes.Name.Text, StringComparison.OrdinalIgnoreCase))) + entries.Add(new CompletionListEntry(keyframes.Name.Text)); + } + + return entries; + } + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/ClassCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/ClassCompletionProvider.cs new file mode 100644 index 000000000..76710f230 --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/ClassCompletionProvider.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("ClassCompletionProvider")] + internal class ClassCompletionProvider : ICssCompletionListProvider + { + public CssCompletionContextType ContextType + { + get { return (CssCompletionContextType)602; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + HashSet classNames = new HashSet(); + HashSet entries = new HashSet(); + + StyleSheet stylesheet = context.ContextItem.StyleSheet; + var visitorRules = new CssItemCollector(); + stylesheet.Accept(visitorRules); + + foreach (ClassSelector item in visitorRules.Items) + { + if (item != context.ContextItem && !classNames.Contains(item.Text)) + { + classNames.Add(item.Text); + entries.Add(new CompletionListEntry(item.Text)); + } + } + + return entries; + } + + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/ColorCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/ColorCompletionProvider.cs new file mode 100644 index 000000000..aefb808b7 --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/ColorCompletionProvider.cs @@ -0,0 +1,49 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Drawing; +using System.Reflection; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("ColorCompletionProvider")] + [Order(Before = "Default PropertyValue")] + internal class ColorCompletionProvider : ICssCompletionListProvider, ICssCompletionPresenterProvider + { + public CssCompletionContextType ContextType + { + get { return CssCompletionContextType.PropertyValue; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + yield break; + } + + public CompletionPresenterInfo TryCreateCompletionPresenter(ICompletionSession session, CssCompletionContext context) + { + string text = context.Snapshot.GetText(context.SpanStart, context.SpanLength); + if (Color.FromName(text).IsKnownColor) + { + return CreatePresenter(session, context); + } + + return new CompletionPresenterInfo(null, true); + } + + private static CompletionPresenterInfo CreatePresenter(ICompletionSession session, CssCompletionContext context) + { + object[] parameters = new object[] { session, context }; + BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; + Type type = typeof(CssClassifier).Assembly.GetType("Microsoft.CSS.Editor.ColorPickerPresenter"); + object colorPicker = Activator.CreateInstance(type, flags, null, parameters, null); + + return new CompletionPresenterInfo((IIntellisensePresenter)colorPicker, false); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/CompletionProviders/FontCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/FontCompletionProvider.cs new file mode 100644 index 000000000..7e74e032e --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/FontCompletionProvider.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using System.Windows.Threading; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("FontCompletionProvider")] + internal class FontCompletionProvider : ICssCompletionListProvider, ICssCompletionCommitListener + { + private static List _emptyList = new List(); + public CssCompletionContextType ContextType + { + get { return CssCompletionContextType.PropertyValue; } + } + + public static bool IsFontFamilyContext(CssCompletionContext context) + { + if (context != null && context.ContextItem != null) + { + Declaration decl = context.ContextItem.Parent as Declaration; + string propertyName = (decl != null && decl.PropertyName != null) ? decl.PropertyName.Text : string.Empty; + + // Currently, only "font-family" will show font names, so just hard-code that name. + if (propertyName == "font-family") + { + return true; + } + } + + return false; + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + if (IsFontFamilyContext(context)) + { + List entries = new List(); + List idNames = new List(); + + StyleSheet stylesheet = context.ContextItem.StyleSheet; + var visitorRules = new CssItemCollector(); + stylesheet.Accept(visitorRules); + + foreach (FontFaceDirective item in visitorRules.Items) + { + var visitorDec = new CssItemCollector(); + item.Block.Accept(visitorDec); + + Declaration family = visitorDec.Items.FirstOrDefault(i => i.PropertyName.Text == "font-family"); + + if (family != null) + { + string value = string.Join(string.Empty, family.Values.Select(v => v.Text)); + entries.Add(new FontFamilyCompletionListEntry(value.Trim('\'', '"'))); + } + } + + entries.Add(new FontFamilyCompletionListEntry("Pick from file...")); + + return entries; + } + + return _emptyList; + } + + public void OnCommitted(ICssCompletionListEntry entry, ITrackingSpan contextSpan, SnapshotPoint caret, ITextView textView) + { + if (entry.DisplayText == "Pick from file...") + { + string fontFamily; + string atDirective = GetFontFromFile(entry.DisplayText, (IWpfTextView)textView, out fontFamily); + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => Replace(contextSpan, textView, atDirective, fontFamily)), DispatcherPriority.Normal); + + } + } + + private static void Replace(ITrackingSpan contextSpan, ITextView textView, string atDirective, string fontFamily) + { + EditorExtensionsPackage.DTE.UndoContext.Open("Embed font"); + textView.TextBuffer.Insert(0, atDirective + Environment.NewLine + Environment.NewLine); + textView.TextBuffer.Insert(contextSpan.GetSpan(textView.TextBuffer.CurrentSnapshot).Start, fontFamily); + EditorExtensionsPackage.DTE.UndoContext.Close(); + + } + + private static object _syncRoot = new object(); + private string GetFontFromFile(string text, IWpfTextView view, out string fontFamily) + { + lock (_syncRoot) + { + fontFamily = text; + OpenFileDialog dialog = new OpenFileDialog(); + dialog.InitialDirectory = Path.GetDirectoryName(EditorExtensionsPackage.DTE.ActiveDocument.FullName); + dialog.Filter = "Fonts (*.woff;*.eot;*.ttf;*.otf;*.svg)|*.woff;*.eot;*.ttf;*.otf;*.svg"; + dialog.DefaultExt = ".woff"; + + if (dialog.ShowDialog() == DialogResult.OK) + { + FontDropHandler fdh = new FontDropHandler(view); + return fdh.GetCodeFromFile(dialog.FileName, out fontFamily); + } + + return text; + } + } + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/FontFamilyCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/FontFamilyCompletionProvider.cs new file mode 100644 index 000000000..0aa82bb6d --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/FontFamilyCompletionProvider.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("FontFamilyCompletionProvider")] + internal class FontFamilyCompletionProvider : ICssCompletionListProvider + { + private static List _entryCache = new List() + { + "Arial, 'DejaVu Sans', 'Liberation Sans', Freesans, sans-serif", + "'Arial Narrow', 'Nimbus Sans L', sans-serif", + "'Arial Black', Gadget, sans-serif", + "'Bookman Old Style', Bookman, 'URW Bookman L', 'Palatino Linotype', serif", + "'Century Gothic', futura, 'URW Gothic L', Verdana, sans-serif", + "'Comic Sans MS', cursive", + "Consolas, 'Lucida Console', 'DejaVu Sans Mono', monospace", + "'Courier New', Courier, 'Nimbus Mono L', monospace", + "Constantina, Georgia, 'Nimbus Roman No9 L', serif", + "Helvetica, Arial, 'DejaVu Sans', 'Liberation Sans', Freesans, sans-serif", + "Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif", + "'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans Condensed', sans-serif", + "Cambria, 'Palatino Linotype', 'Book Antiqua', 'URW Palladio L', serif", + "symbol, 'Standard Symbols L'", + "Cambria, 'Times New Roman', 'Nimbus Roman No9 L', 'Freeserif', Times, serif", + "Verdana, Geneva, 'DejaVu Sans', sans-serif", + "'Monotype Corsiva', 'Apple Chancery', 'ITC Zapf Chancery', 'URW Chancery L', cursive", + "'Monotype Sorts', dingbats, 'ITC Zapf Dingbats', fantasy" + }; + + public CssCompletionContextType ContextType + { + get { return CssCompletionContextType.PropertyValue; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + Declaration dec = context.ContextItem.FindType(); + + if (dec == null || dec.PropertyName == null || dec.PropertyName.Text != "font-family") + yield break; + + foreach (string item in _entryCache) + { + ICssCompletionListEntry entry = new CompletionListEntry(item, 1); + yield return entry; + } + } + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/IdCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/IdCompletionProvider.cs new file mode 100644 index 000000000..4a8b2d07c --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/IdCompletionProvider.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("IdCompletionProvider")] + internal class IdCompletionProvider : ICssCompletionListProvider + { + public CssCompletionContextType ContextType + { + get { return (CssCompletionContextType)603; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + List idNames = new List(); + List entries = new List(); + + StyleSheet stylesheet = context.ContextItem.StyleSheet; + var visitorRules = new CssItemCollector(); + stylesheet.Accept(visitorRules); + + foreach (IdSelector item in visitorRules.Items) + { + if (item != context.ContextItem && !idNames.Contains(item.Text)) + { + idNames.Add(item.Text); + entries.Add(new CompletionListEntry(item.Text)); + } + } + + return entries; + } + + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/ImportantCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/ImportantCompletionProvider.cs new file mode 100644 index 000000000..ce33b0aee --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/ImportantCompletionProvider.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("ImportantCompletionProvider")] + internal class ImportantCompletionProvider : ICssCompletionListProvider + { + public CssCompletionContextType ContextType + { + get { return CssCompletionContextType.PropertyValue; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + List entries = new List(); + Declaration dec = context.ContextItem.FindType(); + if (dec == null || dec.Colon == null || dec.Important != null || dec.Values.Count == 0) + return entries; + + ParseItem before = dec.ItemBeforePosition(context.SpanStart); + if (before != null && before.Text == "!") + entries.Add(new CompletionListEntry("important", 1)); + + return entries; + } + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/RegionCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/RegionCompletionProvider.cs new file mode 100644 index 000000000..2c1f40f66 --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/RegionCompletionProvider.cs @@ -0,0 +1,44 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("RegionCompletionProvider")] + internal class RegionCompletionProvider : ICssCompletionListProvider, ICssCompletionCommitListener + { + private RegionCompletionListEntry _entry = new RegionCompletionListEntry(); + + public CssCompletionContextType ContextType + { + get { return (CssCompletionContextType)601; } //ItemName + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + var line = context.Snapshot.GetLineFromPosition(context.ContextItem.Start); + string text = line.GetText().Trim(); + + if (text.Length == context.ContextItem.Length) + { + yield return _entry; + } + } + + public void OnCommitted(ICssCompletionListEntry entry, ITrackingSpan contextSpan, SnapshotPoint caret, ITextView textView) + { + if (entry.DisplayText == "Add region...") + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => System.Windows.Forms.SendKeys.Send("{TAB}")), DispatcherPriority.Normal); + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/CompletionProviders/TagCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/TagCompletionProvider.cs new file mode 100644 index 000000000..c0fa109e0 --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/TagCompletionProvider.cs @@ -0,0 +1,154 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.VisualStudio.Utilities; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("TagCompletionProvider")] + internal class TagCompletionProvider : ICssCompletionListProvider + { + private static IEnumerable _entryCache = GetListEntriesCache(); + + public CssCompletionContextType ContextType + { + get { return (CssCompletionContextType)601; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + return _entryCache; + } + + private static IEnumerable GetListEntriesCache() + { + List entries = new List(); + + entries.Add(new CompletionListEntry("a")); + entries.Add(new CompletionListEntry("abbr")); + entries.Add(new CompletionListEntry("acronym")); + entries.Add(new CompletionListEntry("address")); + //entries.Add(new CompletionListEntry("applet")); + entries.Add(new CompletionListEntry("area")); + entries.Add(new CompletionListEntry("article")); + entries.Add(new CompletionListEntry("aside")); + entries.Add(new CompletionListEntry("audio")); + entries.Add(new CompletionListEntry("b")); + //entries.Add(new CompletionListEntry("base")); + //entries.Add(new CompletionListEntry("basefont")); + entries.Add(new CompletionListEntry("bdi")); + entries.Add(new CompletionListEntry("bdo")); + entries.Add(new CompletionListEntry("big")); + entries.Add(new CompletionListEntry("blockquote")); + entries.Add(new CompletionListEntry("body")); + //entries.Add(new CompletionListEntry("br")); + entries.Add(new CompletionListEntry("button")); + entries.Add(new CompletionListEntry("canvas")); + entries.Add(new CompletionListEntry("caption")); + entries.Add(new CompletionListEntry("center")); + entries.Add(new CompletionListEntry("cite")); + entries.Add(new CompletionListEntry("code")); + entries.Add(new CompletionListEntry("col")); + entries.Add(new CompletionListEntry("colgroup")); + //entries.Add(new CompletionListEntry("command")); + entries.Add(new CompletionListEntry("datalist")); + entries.Add(new CompletionListEntry("dd")); + entries.Add(new CompletionListEntry("del")); + entries.Add(new CompletionListEntry("details")); + entries.Add(new CompletionListEntry("dfn")); + //entries.Add(new CompletionListEntry("dir")); + entries.Add(new CompletionListEntry("div")); + entries.Add(new CompletionListEntry("dl")); + entries.Add(new CompletionListEntry("dt")); + entries.Add(new CompletionListEntry("em")); + entries.Add(new CompletionListEntry("embed")); + entries.Add(new CompletionListEntry("fieldset")); + entries.Add(new CompletionListEntry("figcaption")); + entries.Add(new CompletionListEntry("figure")); + //entries.Add(new CompletionListEntry("font")); + entries.Add(new CompletionListEntry("footer")); + entries.Add(new CompletionListEntry("form")); + //entries.Add(new CompletionListEntry("frame")); + //entries.Add(new CompletionListEntry("frameset")); + entries.Add(new CompletionListEntry("h1")); + entries.Add(new CompletionListEntry("h2")); + entries.Add(new CompletionListEntry("h3")); + entries.Add(new CompletionListEntry("h4")); + entries.Add(new CompletionListEntry("h5")); + entries.Add(new CompletionListEntry("h6")); + //entries.Add(new CompletionListEntry("head")); + entries.Add(new CompletionListEntry("header")); + entries.Add(new CompletionListEntry("hgroup")); + entries.Add(new CompletionListEntry("hr")); + entries.Add(new CompletionListEntry("html")); + entries.Add(new CompletionListEntry("i")); + entries.Add(new CompletionListEntry("iframe")); + entries.Add(new CompletionListEntry("img")); + entries.Add(new CompletionListEntry("input")); + entries.Add(new CompletionListEntry("ins")); + //entries.Add(new CompletionListEntry("keygen")); + entries.Add(new CompletionListEntry("kbd")); + entries.Add(new CompletionListEntry("label")); + entries.Add(new CompletionListEntry("legend")); + entries.Add(new CompletionListEntry("li")); + //entries.Add(new CompletionListEntry("link")); + entries.Add(new CompletionListEntry("map")); + entries.Add(new CompletionListEntry("mark")); + entries.Add(new CompletionListEntry("menu")); + //entries.Add(new CompletionListEntry("meta")); + entries.Add(new CompletionListEntry("meter")); + entries.Add(new CompletionListEntry("nav")); + //entries.Add(new CompletionListEntry("noframes")); + //entries.Add(new CompletionListEntry("noscript")); + entries.Add(new CompletionListEntry("object")); + entries.Add(new CompletionListEntry("ol")); + entries.Add(new CompletionListEntry("optgroup")); + entries.Add(new CompletionListEntry("option")); + entries.Add(new CompletionListEntry("output")); + entries.Add(new CompletionListEntry("p")); + entries.Add(new CompletionListEntry("param")); + entries.Add(new CompletionListEntry("pre")); + entries.Add(new CompletionListEntry("progress")); + entries.Add(new CompletionListEntry("q")); + entries.Add(new CompletionListEntry("rp")); + entries.Add(new CompletionListEntry("rt")); + entries.Add(new CompletionListEntry("ruby")); + entries.Add(new CompletionListEntry("s")); + entries.Add(new CompletionListEntry("samp")); + //entries.Add(new CompletionListEntry("script")); + entries.Add(new CompletionListEntry("section")); + entries.Add(new CompletionListEntry("select")); + entries.Add(new CompletionListEntry("small")); + //entries.Add(new CompletionListEntry("source")); + entries.Add(new CompletionListEntry("span")); + //entries.Add(new CompletionListEntry("strike")); + entries.Add(new CompletionListEntry("strong")); + entries.Add(new CompletionListEntry("style")); + entries.Add(new CompletionListEntry("sub")); + entries.Add(new CompletionListEntry("summary")); + entries.Add(new CompletionListEntry("sup")); + entries.Add(new CompletionListEntry("svg")); + entries.Add(new CompletionListEntry("table")); + entries.Add(new CompletionListEntry("tbody")); + entries.Add(new CompletionListEntry("td")); + entries.Add(new CompletionListEntry("textarea")); + entries.Add(new CompletionListEntry("tfoot")); + entries.Add(new CompletionListEntry("th")); + entries.Add(new CompletionListEntry("thead")); + entries.Add(new CompletionListEntry("time")); + //entries.Add(new CompletionListEntry("title")); + entries.Add(new CompletionListEntry("tr")); + entries.Add(new CompletionListEntry("track")); + entries.Add(new CompletionListEntry("tt")); + entries.Add(new CompletionListEntry("u")); + entries.Add(new CompletionListEntry("ul")); + entries.Add(new CompletionListEntry("var")); + entries.Add(new CompletionListEntry("video")); + //entries.Add(new CompletionListEntry("wbr")); + + return entries; + } + } +} diff --git a/EditorExtensions/Completion/CompletionProviders/UrlPickerCompletionProvider.cs b/EditorExtensions/Completion/CompletionProviders/UrlPickerCompletionProvider.cs new file mode 100644 index 000000000..a636d2512 --- /dev/null +++ b/EditorExtensions/Completion/CompletionProviders/UrlPickerCompletionProvider.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Threading; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionProvider))] + [Name("UrlPickerCompletionProvider")] + internal class UrlPickerCompletionProvider : ICssCompletionListProvider, ICssCompletionCommitListener + { + private static List _imageExtensions = new List() { "", ".png", ".jpg", "gif", ".svg", ".jpeg", ".bmp", ".tif", ".tiff" }; + public CssCompletionContextType ContextType + { + get { return (CssCompletionContextType)604; } + } + + public IEnumerable GetListEntries(CssCompletionContext context) + { + UrlItem urlItem = (UrlItem)context.ContextItem; + + string url = urlItem.UrlString != null ? urlItem.UrlString.Text : string.Empty; + string directory = GetDirectory(url); + + if (url.StartsWith("http") || url.Contains("//") || url.Contains(";base64,") || !Directory.Exists(directory)) + yield break; + + foreach (string item in Directory.GetFileSystemEntries(directory)) + { + string entry = item.Substring(item.LastIndexOf("\\") + 1); + + //if (_imageExtensions.Contains(Path.GetExtension(entry))) + yield return new UrlPickerCompletionListEntry(entry); + } + } + + private static string GetDirectory(string url) + { + if (url == "/" || url.LastIndexOf('/') == 0) + return GetRootFolder(); + + return GetRelativeFolder(url); + } + + private static string GetRelativeFolder(string url) + { + int end = Math.Max(0, url.LastIndexOf('/')); + return ProjectHelpers.ToAbsoluteFilePath(url.Substring(0, end)); + } + + private static string GetRootFolder() + { + string root = ProjectHelpers.GetRootFolder(); + if (File.Exists(root)) + return Path.GetDirectoryName(root); + + return root; + } + + public void OnCommitted(ICssCompletionListEntry entry, Microsoft.VisualStudio.Text.ITrackingSpan contextSpan, Microsoft.VisualStudio.Text.SnapshotPoint caret, Microsoft.VisualStudio.Text.Editor.ITextView textView) + { + if (Path.GetExtension(entry.DisplayText).Length == 0) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => CssCompletionController.FromView(textView).OnShowMemberList(filterList: true)), DispatcherPriority.Normal); + } + } + } +} diff --git a/EditorExtensions/Completion/ContextProviders/ClassContextProvider.cs b/EditorExtensions/Completion/ContextProviders/ClassContextProvider.cs new file mode 100644 index 000000000..17e5093e9 --- /dev/null +++ b/EditorExtensions/Completion/ContextProviders/ClassContextProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionContextProvider))] + [Name("ClassCompletionContextProvider")] + internal class ClassCompletionContextProvider : ICssCompletionContextProvider + { + public ClassCompletionContextProvider() + { + } + + public IEnumerable ItemTypes + { + get + { + return new Type[] { typeof(ClassSelector), }; + } + } + + public CssCompletionContext GetCompletionContext(ParseItem item, int position) + { + return new CssCompletionContext((CssCompletionContextType)602, item.Start, item.Length, null); + } + } +} diff --git a/EditorExtensions/Completion/ContextProviders/IdContextProvider.cs b/EditorExtensions/Completion/ContextProviders/IdContextProvider.cs new file mode 100644 index 000000000..51424f6cd --- /dev/null +++ b/EditorExtensions/Completion/ContextProviders/IdContextProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionContextProvider))] + [Name("IdCompletionContextProvider")] + internal class IdCompletionContextProvider : ICssCompletionContextProvider + { + public IdCompletionContextProvider() + { + } + + public IEnumerable ItemTypes + { + get + { + return new Type[] { typeof(IdSelector), }; + } + } + + public CssCompletionContext GetCompletionContext(ParseItem item, int position) + { + return new CssCompletionContext((CssCompletionContextType)603, item.Start, item.Length, null); + } + } +} diff --git a/EditorExtensions/Completion/ContextProviders/LessPseudoContextProvider.cs b/EditorExtensions/Completion/ContextProviders/LessPseudoContextProvider.cs new file mode 100644 index 000000000..ff818d58b --- /dev/null +++ b/EditorExtensions/Completion/ContextProviders/LessPseudoContextProvider.cs @@ -0,0 +1,43 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.Less.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionContextProvider))] + [Name("LessPseudoContextProvider")] + [Order(Before = "Default Pseudo")] + internal class LessPseudoContextProvider : ICssCompletionContextProvider + { + public IEnumerable ItemTypes + { + get + { + return new Type[] + { + typeof(PseudoClassFunctionSelector), + typeof(PseudoClassSelector), + typeof(PseudoElementFunctionSelector), + typeof(PseudoElementSelector) + }; + } + } + + public CssCompletionContext GetCompletionContext(ParseItem item, int position) + { + RuleSet rule = item.FindType(); + + if (rule != null && rule.Parent is LessRuleBlock) + { + return new CssCompletionContext(CssCompletionContextType.Invalid, item.Start, item.Length, item); + } + + return null; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/ContextProviders/TagContextProvider.cs b/EditorExtensions/Completion/ContextProviders/TagContextProvider.cs new file mode 100644 index 000000000..32a74710e --- /dev/null +++ b/EditorExtensions/Completion/ContextProviders/TagContextProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionContextProvider))] + [Name("TagCompletionContextProvider")] + internal class TagCompletionContextProvider : ICssCompletionContextProvider + { + public TagCompletionContextProvider() + { + } + + public IEnumerable ItemTypes + { + get + { + return new Type[] { typeof(ItemName), }; + } + } + + public CssCompletionContext GetCompletionContext(ParseItem item, int position) + { + return new CssCompletionContext((CssCompletionContextType)601, item.Start, item.Length, null); + } + } +} diff --git a/EditorExtensions/Completion/ContextProviders/UrlPickerContextProvider.cs b/EditorExtensions/Completion/ContextProviders/UrlPickerContextProvider.cs new file mode 100644 index 000000000..66bf6672e --- /dev/null +++ b/EditorExtensions/Completion/ContextProviders/UrlPickerContextProvider.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssCompletionContextProvider))] + [Name("UrlPickerCompletionContextProvider")] + internal class UrlPickerCompletionContextProvider : ICssCompletionContextProvider + { + public UrlPickerCompletionContextProvider() + { + } + + public IEnumerable ItemTypes + { + get + { + return new Type[] { typeof(UrlItem), }; + } + } + + public CssCompletionContext GetCompletionContext(ParseItem item, int position) + { + UrlItem urlItem = (UrlItem)item; + int start = item.Start + 4; + int length = 0; + + if (urlItem.UrlString != null) + { + start = urlItem.UrlString.Start; + length = urlItem.UrlString.Length; + + int relative = position - start; + int lastSlash = urlItem.UrlString.Text.LastIndexOf('/'); + if (lastSlash < relative) + { + start = start + lastSlash + 1; + length = length - (lastSlash + 1); + } + } + + return new CssCompletionContext((CssCompletionContextType)604, start, length, null); + } + } +} diff --git a/EditorExtensions/Completion/CustomCompletionListEntry.cs b/EditorExtensions/Completion/CustomCompletionListEntry.cs new file mode 100644 index 000000000..34b3d3292 --- /dev/null +++ b/EditorExtensions/Completion/CustomCompletionListEntry.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + internal class CustomCompletionListEntry : ICssCompletionListEntry + { + private string _insertion; + + public CustomCompletionListEntry(string name, string insertion) + { + this.DisplayText = name; + _insertion = insertion; + } + + + public string Description { get; set; } + + public string DisplayText { get; set; } + + public string GetSyntax(Version version) + { + return string.Empty; + } + + public StandardGlyphGroup StandardGlyph + { + get { return StandardGlyphGroup.GlyphGroupEnumMember; } + } + + public string GetAttribute(string name) + { + return string.Empty; + } + + public string GetInsertionText(CssTextSource textSource, ITrackingSpan typingSpan) + { + return _insertion; + } + + public string GetVersionedAttribute(string name, Version version) + { + return GetAttribute(name); + } + + public bool AllowQuotedString + { + get { return false; } + } + + public bool IsBuilder + { + get { return false; } + } + + public int SortingPriority { get; set; } + + + public bool IsSupported(BrowserVersion browser) + { + return true; + } + + public bool IsSupported(Version cssVersion) + { + return true; + } + } +} diff --git a/EditorExtensions/Completion/Filter/GradientCompletionListFilter.cs b/EditorExtensions/Completion/Filter/GradientCompletionListFilter.cs new file mode 100644 index 000000000..168f7961d --- /dev/null +++ b/EditorExtensions/Completion/Filter/GradientCompletionListFilter.cs @@ -0,0 +1,97 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Reflection; + +namespace MadsKristensen.EditorExtensions.Completion +{ + [Export(typeof(ICssCompletionListFilter))] + [Name("Gradient Filter")] + internal class GradientCompletionListFilter : ICssCompletionListFilter + { + [Import] + private IGlyphService _glyphService = null; + + public void FilterCompletionList(IList completions, CssCompletionContext context) + { + if (context.ContextType != CssCompletionContextType.PropertyValue) + return; + + for (int i = 0; i < completions.Count; i++) + { + CssSchemaCompletionEntry entry = completions[i] as CssSchemaCompletionEntry; + + if (entry != null && entry.DisplayText.Contains("gradient(")) + { + var cce = CreateCompletionEntry(context, entry); + cce.FilterType = entry.FilterType; + cce.IsBuilder = entry.IsBuilder; + + completions[i] = cce; + } + } + } + + private CssSchemaCompletionEntry CreateCompletionEntry(CssCompletionContext context, CssSchemaCompletionEntry entry) + { + CustomCompletionListEntry interim = new CustomCompletionListEntry(entry.DisplayText, GetArguments(entry.DisplayText)); + interim.Description = entry.Description; + + object[] parameters = new object[] + { + interim, + entry.CompletionProvider, + CssTextSource.Document, + context.Snapshot.CreateTrackingSpan(context.SpanStart, context.SpanLength, SpanTrackingMode.EdgeExclusive), + _glyphService + }; + + BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; + return (CssSchemaCompletionEntry)Activator.CreateInstance(typeof(CssSchemaCompletionEntry), flags, null, parameters, null); + } + + private static string GetArguments(string functionName) + { + switch (functionName) + { + case "linear-gradient()": + case "-webkit-linear-gradient()": + case "-ms-linear-gradient()": + case "-moz-linear-gradient()": + case "-o-linear-gradient()": + return functionName.Replace("()", "(top, #1e5799 0%, #7db9e8 100%)"); + + case "-webkit-gradient()": + return functionName.Replace("()", "(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(100%,#7db9e8))"); + + case "radial-gradient()": + case "-webkit-radial-gradient()": + case "-ms-radial-gradient()": + case "-moz-radial-gradient()": + case "-o-radial-gradient()": + return functionName.Replace("()", "(50px 50px, circle closest-side, black, white)"); + + case "repeating-linear-gradient()": + case "-webkit-repeating-linear-gradient()": + case "-ms-repeating-linear-gradient()": + case "-moz-repeating-linear-gradient()": + case "-o-repeating-linear-gradient()": + return functionName.Replace("()", "(red, blue 20px, red 40px)"); + + case "repeating-radial-gradient()": + case "-webkit-repeating-radial-gradient()": + case "-ms-repeating-radial-gradient()": + case "-moz-repeating-radial-gradient()": + case "-o-repeating-radial-gradient()": + return functionName.Replace("()", "(red, blue 20px, red 40px)"); + } + + return functionName; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/Filter/HideInheritInitialCompletionListFilter.cs b/EditorExtensions/Completion/Filter/HideInheritInitialCompletionListFilter.cs new file mode 100644 index 000000000..a496624ec --- /dev/null +++ b/EditorExtensions/Completion/Filter/HideInheritInitialCompletionListFilter.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions.Completion +{ + [Export(typeof(ICssCompletionListFilter))] + [Name("Inherit/Initial Filter")] + internal class HideInheritInitialCompletionListFilter : ICssCompletionListFilter + { + public void FilterCompletionList(IList completions, CssCompletionContext context) + { + if (context.ContextType != CssCompletionContextType.PropertyValue || WESettings.GetBoolean(WESettings.Keys.ShowInitialInherit)) + return; + + foreach (CssCompletionEntry entry in completions) + { + if (entry.DisplayText == "initial" || entry.DisplayText == "inherit") + { + entry.FilterType = CompletionEntryFilterType.NeverVisible; + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/Filter/HideUnsupportedCompletionListFilter.cs b/EditorExtensions/Completion/Filter/HideUnsupportedCompletionListFilter.cs new file mode 100644 index 000000000..cecee7a6e --- /dev/null +++ b/EditorExtensions/Completion/Filter/HideUnsupportedCompletionListFilter.cs @@ -0,0 +1,41 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Utilities; +using System; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssSchemaFilterProvider))] + [Name("HideUnsupportedSchemaFilterProvider")] + internal class HideUnsupportedSchemaFilterProvider : ICssSchemaFilterProvider + { + public ICssSchemaFilter CreateFilter(ICssSchemaManager schemaManager, ITextBuffer textBuffer) + { + return textBuffer.Properties.GetOrCreateSingletonProperty(() => new HideUnsupportedSchemaFilter()); + } + } + + internal class HideUnsupportedSchemaFilter : ICssSchemaFilter + { + public bool IsSupported(Version cssVersion, ICssCompletionListEntry entry) + { + if (WESettings.GetBoolean(WESettings.Keys.ShowUnsupported)) + return entry.IsSupported(cssVersion); + + return entry.GetAttribute("browsers") != "none" || entry.DisplayText.Contains("gradient"); + } + + public string Name + { + get { return WESettings.GetBoolean(WESettings.Keys.ShowUnsupported) ? string.Empty : "WE"; } + } + + public bool Equals(ICssSchemaFilter other) + { + return other.Name.Equals(Name); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/Filter/WebkitScrollbarCompletionListFilter.cs b/EditorExtensions/Completion/Filter/WebkitScrollbarCompletionListFilter.cs new file mode 100644 index 000000000..695bb1f3f --- /dev/null +++ b/EditorExtensions/Completion/Filter/WebkitScrollbarCompletionListFilter.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions.Completion +{ + [Export(typeof(ICssCompletionListFilter))] + [Name("WebkitScrollbarCompletionListFilter")] + internal class WebkitScrollbarCompletionListFilter : ICssCompletionListFilter + { + private static readonly StringCollection _cache = new StringCollection() + { + ":horizontal", + ":vertical", + ":decrement", + ":increment", + ":start", + ":end", + ":double-button", + ":single-button", + ":no-button", + ":corner-present", + ":window-inactive", + }; + + public void FilterCompletionList(IList completions, CssCompletionContext context) + { + if (context.ContextType != CssCompletionContextType.PseudoClassOrElement) + return; + + ParseItem prev = context.ContextItem.PreviousSibling; + bool hasScrollbar = false; + + if (prev != null) + { + hasScrollbar = prev.Text.Contains(":-webkit-resizer") || prev.Text.Contains(":-webkit-scrollbar"); + } + + foreach (CssCompletionEntry entry in completions) + { + if (hasScrollbar) + { + entry.FilterType = _cache.Contains(entry.DisplayText) ? entry.FilterType : CompletionEntryFilterType.NeverVisible; + } + else + { + entry.FilterType = !_cache.Contains(entry.DisplayText) ? entry.FilterType : CompletionEntryFilterType.NeverVisible; + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Completion/FontFamilyCompletionListEntry.cs b/EditorExtensions/Completion/FontFamilyCompletionListEntry.cs new file mode 100644 index 000000000..4b98ee913 --- /dev/null +++ b/EditorExtensions/Completion/FontFamilyCompletionListEntry.cs @@ -0,0 +1,112 @@ +using System; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + /// + /// This represents a font family in the completion list + /// + internal class FontFamilyCompletionListEntry : ICssCompletionListEntry + { + private string _name; + + public FontFamilyCompletionListEntry(string name) + { + _name = name ?? string.Empty; + } + + public string DisplayText + { + get { return _name; } + } + + public string Description + { + get { return string.Empty; } + } + + public string GetSyntax(Version version) + { + return string.Empty; + } + + public string GetAttribute(string name) + { + return string.Empty; + } + + public string GetVersionedAttribute(string name, System.Version version) + { + return string.Empty; + } + + public string GetInsertionText(CssTextSource textSource, ITrackingSpan typingSpan) + { + string text = DisplayText; + bool needsQuote = text.IndexOf(' ') != -1; + if (text == "Pick from file...") + { + return string.Empty; + } + + if (needsQuote) + { + // Prefer to use single quotes, but if the inline style uses single quotes, then use double quotes. + char quote = (textSource == CssTextSource.InlineStyleSingleQuote) ? '"' : '\''; + + if (typingSpan != null) + { + // If the user already typed a quote, then use it + + string typingText = typingSpan.GetText(typingSpan.TextBuffer.CurrentSnapshot); + + if (!string.IsNullOrEmpty(typingText) && (typingText[0] == '"' || typingText[0] == '\'')) + { + quote = typingText[0]; + } + } + + if (text != null && text.IndexOf(quote) == -1) + { + text = quote.ToString() + text + quote.ToString(); + } + } + + return text; + } + + public StandardGlyphGroup StandardGlyph + { + get { return StandardGlyphGroup.GlyphGroupEnumMember; } + } + + public bool AllowQuotedString + { + get { return true; } + } + + public bool IsBuilder + { + get { return DisplayText == "Pick from file..."; } + } + + public int SortingPriority + { + get { return 0; } + } + + + public bool IsSupported(BrowserVersion browser) + { + return true; + } + + public bool IsSupported(Version cssVersion) + { + return true; + } + } +} diff --git a/EditorExtensions/Completion/RegionCompletionListEntry.cs b/EditorExtensions/Completion/RegionCompletionListEntry.cs new file mode 100644 index 000000000..8c5c8fd08 --- /dev/null +++ b/EditorExtensions/Completion/RegionCompletionListEntry.cs @@ -0,0 +1,69 @@ +using System; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + internal class RegionCompletionListEntry : ICssCompletionListEntry + { + public string Description + { + get { return string.Empty; } + } + + public string DisplayText + { + get { return "Add region..."; } + } + + public string GetSyntax(Version version) + { + return string.Empty; + } + + public StandardGlyphGroup StandardGlyph + { + get { return StandardGlyphGroup.GlyphCSharpExpansion; } + } + + public string GetAttribute(string name) + { + return string.Empty; + } + + public string GetInsertionText(CssTextSource textSource, ITrackingSpan typingSpan) + { + return "region";//"/*#region MyRegion */\n\n\n\n/*#endregion*/"; + } + + public string GetVersionedAttribute(string name, Version version) + { + return GetAttribute(name); + } + + public bool AllowQuotedString + { + get { return false; } + } + + public bool IsBuilder + { + get { return true; } + } + + public int SortingPriority { get; set; } + + + public bool IsSupported(BrowserVersion browser) + { + return true; + } + + public bool IsSupported(Version cssVersion) + { + return true; + } + } +} diff --git a/EditorExtensions/Completion/UrlPickerCompletionListEntry.cs b/EditorExtensions/Completion/UrlPickerCompletionListEntry.cs new file mode 100644 index 000000000..cf9d8cee5 --- /dev/null +++ b/EditorExtensions/Completion/UrlPickerCompletionListEntry.cs @@ -0,0 +1,89 @@ +using System; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + internal class UrlPickerCompletionListEntry : ICssCompletionListEntry + { + private string _name; + + public UrlPickerCompletionListEntry(string name) + { + _name = name; + } + + public bool AllowQuotedString + { + get { return false; } + } + + public string Description + { + get { return string.Empty; } + } + + public string DisplayText + { + get { return _name; } + } + + public string GetSyntax(Version version) + { + return string.Empty; + } + + public int SortingPriority + { + get { return IsFolder ? 1 : 0; } + } + + public bool IsBuilder + { + get { return false; } + } + + public StandardGlyphGroup StandardGlyph + { + get { return IsFolder ? StandardGlyphGroup.GlyphClosedFolder : StandardGlyphGroup.GlyphBscFile; } + } + + public string GetAttribute(string name) + { + return string.Empty; + } + + public string GetInsertionText(CssTextSource textSource, ITrackingSpan typingSpan) + { + if (IsFolder) + { + return DisplayText + "/"; + } + + return DisplayText; + } + + public string GetVersionedAttribute(string name, Version version) + { + return GetAttribute(name); + } + + private bool IsFolder + { + get { return !DisplayText.Contains("."); } + } + + + public bool IsSupported(BrowserVersion browser) + { + return true; + } + + public bool IsSupported(Version cssVersion) + { + return true; + } + } +} diff --git a/EditorExtensions/DropTargets/BundleDrop.cs b/EditorExtensions/DropTargets/BundleDrop.cs new file mode 100644 index 000000000..61dc38798 --- /dev/null +++ b/EditorExtensions/DropTargets/BundleDrop.cs @@ -0,0 +1,83 @@ +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.DragDrop; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IDropHandlerProvider))] + [DropFormat("CF_VSSTGPROJECTITEMS")] + [Name("BundleDropDropHandler")] + [ContentType("XML")] + [Order(Before = "DefaultFileDropHandler")] + internal class BundleDropHandlerProvider : IDropHandlerProvider + { + public IDropHandler GetAssociatedDropHandler(IWpfTextView view) + { + return view.Properties.GetOrCreateSingletonProperty(() => new BundleDropHandler(view)); + } + } + + internal class BundleDropHandler : IDropHandler + { + private IWpfTextView _view; + private readonly List _allowedExtensions = new List { ".css", ".less", ".js", ".coffee", ".ts" }; + private string _draggedFilename; + private string _format = Environment.NewLine + "\t/{0}"; + + public BundleDropHandler(IWpfTextView view) + { + this._view = view; + } + + public DragDropPointerEffects HandleDataDropped(DragDropInfo dragDropInfo) + { + string reference = FileHelpers.RelativePath(ProjectHelpers.GetRootFolder(), _draggedFilename); + + if (reference.StartsWith("http://localhost:")) + { + int index = reference.IndexOf('/', 20); + if (index > -1) + reference = reference.Substring(index + 1).ToLowerInvariant(); + } + + _view.TextBuffer.Insert(dragDropInfo.VirtualBufferPosition.Position.Position, string.Format(_format, reference)); + + return DragDropPointerEffects.Copy; + } + + public void HandleDragCanceled() + { + + } + + public DragDropPointerEffects HandleDragStarted(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public DragDropPointerEffects HandleDraggingOver(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public bool IsDropEnabled(DragDropInfo dragDropInfo) + { + _draggedFilename = FontDropHandler.GetImageFilename(dragDropInfo); + + if (!string.IsNullOrEmpty(_draggedFilename)) + { + string fileExtension = Path.GetExtension(_draggedFilename).ToLowerInvariant(); + if (this._allowedExtensions.Contains(fileExtension)) + { + return true; + } + } + + return false; + } + } +} diff --git a/EditorExtensions/DropTargets/FontDrop.cs b/EditorExtensions/DropTargets/FontDrop.cs new file mode 100644 index 000000000..9c8aeb693 --- /dev/null +++ b/EditorExtensions/DropTargets/FontDrop.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.DragDrop; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IDropHandlerProvider))] + [DropFormat("FileDrop")] + [DropFormat("CF_VSSTGPROJECTITEMS")] + [Name("FontDropHandler")] + [ContentType("CSS")] + [ContentType("LESS")] + [Order(Before = "DefaultFileDropHandler")] + internal class FontDropHandlerProvider : IDropHandlerProvider + { + public IDropHandler GetAssociatedDropHandler(IWpfTextView view) + { + return view.Properties.GetOrCreateSingletonProperty(() => new FontDropHandler(view)); + } + } + + internal class FontDropHandler : IDropHandler + { + IWpfTextView view; + private readonly Dictionary formats = new Dictionary() + { + {".ttf", " format('truetype')"}, + {".woff", ""}, + {".eot", ""}, + {".otf", " format('opentype')"} + }; + private string draggedFilename; + private string fontName = string.Empty; + string fontFace = "@font-face {{\n\tfont-family: {0};\n\tsrc: {1};\n}}"; + string fontUrls = "url('{0}'){1}"; + //ITextDocument document; + + public FontDropHandler(IWpfTextView view) + { + this.view = view; + //view.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document); + } + + public DragDropPointerEffects HandleDataDropped(DragDropInfo dragDropInfo) + { + if (File.Exists(draggedFilename)) + { + //var files = GetRelativeFiles(draggedFilename); + //string[] sources = new string[files.Count()]; + + //for (int i = 0; i < files.Count(); i++) + //{ + // string file = files.ElementAt(i); + // string extension = Path.GetExtension(file).ToLowerInvariant(); + // string reference = RelativePath(document.FilePath, file); + + // if (reference.StartsWith("http://localhost:")) + // { + // int index = reference.IndexOf('/', 24); + // if (index > -1) + // reference = reference.Substring(index + 1).ToLowerInvariant(); + // } + + // sources[i] = string.Format(fontUrls, reference, formats[extension]); + //} + + //string sourceUrls = string.Join(", ", sources); + string fontFamily; + view.TextBuffer.Insert(dragDropInfo.VirtualBufferPosition.Position.Position, GetCodeFromFile(draggedFilename, out fontFamily)); + + return DragDropPointerEffects.Copy; + } + else if (draggedFilename.StartsWith("http://localhost:")) + { + //int index = draggedFilename.IndexOf('/', 24); + //if (index > -1) + // draggedFilename = draggedFilename.Substring(index).ToLowerInvariant(); + + //string extension = Path.GetExtension(draggedFilename).ToLowerInvariant(); + //string sourceUrl = string.Format(fontUrls, draggedFilename, formats[extension]); + + view.TextBuffer.Insert(dragDropInfo.VirtualBufferPosition.Position.Position, GetCodeFromLocalhost(draggedFilename)); + + return DragDropPointerEffects.Copy; + } + else + { + return DragDropPointerEffects.None; + } + } + + public string GetCodeFromFile(string fileName, out string fontFamily) + { + var files = GetRelativeFiles(fileName); + string[] sources = new string[files.Count()]; + + for (int i = 0; i < files.Count(); i++) + { + string file = files.ElementAt(i); + string extension = Path.GetExtension(file).ToLowerInvariant(); + string reference = FileHelpers.RelativePath(EditorExtensionsPackage.DTE.ActiveDocument.FullName, file); + + if (reference.StartsWith("http://localhost:")) + { + int index = reference.IndexOf('/', 24); + if (index > -1) + reference = reference.Substring(index + 1).ToLowerInvariant(); + } + + sources[i] = string.Format(fontUrls, reference, formats[extension]); + } + + string sourceUrls = string.Join(", ", sources); + fontFamily = fontName; + return string.Format(fontFace, fontName, sourceUrls); + } + + private string GetCodeFromLocalhost(string fileName) + { + int index = draggedFilename.IndexOf('/', 24); + if (index > -1) + draggedFilename = draggedFilename.Substring(index).ToLowerInvariant(); + + string extension = Path.GetExtension(draggedFilename).ToLowerInvariant(); + string sourceUrl = string.Format(fontUrls, draggedFilename, formats[extension]); + + return string.Format(fontFace, "MyFontName", sourceUrl); + } + + private IEnumerable GetRelativeFiles(string fileName) + { + var fi = new FileInfo(fileName); + fontName = fi.Name.Replace(fi.Extension, string.Empty); + foreach (var file in fi.Directory.GetFiles(fontName + ".*")) + { + string extension = file.Extension.ToLowerInvariant(); + if (formats.ContainsKey(extension)) + yield return file.FullName; + } + } + + public void HandleDragCanceled() + { + } + + public DragDropPointerEffects HandleDragStarted(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public DragDropPointerEffects HandleDraggingOver(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public bool IsDropEnabled(DragDropInfo dragDropInfo) + { + //if (!Path.GetExtension(document.FilePath).Equals(".css", StringComparison.OrdinalIgnoreCase)) + // return false; + + draggedFilename = GetImageFilename(dragDropInfo); + + if (!string.IsNullOrEmpty(draggedFilename)) + { + string fileExtension = Path.GetExtension(draggedFilename).ToLowerInvariant(); + if (this.formats.ContainsKey(fileExtension)) + { + return true; + } + } + + return false; + } + + public static string GetImageFilename(DragDropInfo info) + { + DataObject data = new DataObject(info.Data); + + if (info.Data.GetDataPresent("FileDrop")) + { + // The drag and drop operation came from the file system + StringCollection files = data.GetFileDropList(); + + if (files != null && files.Count == 1) + { + return files[0]; + } + } + else if (info.Data.GetDataPresent("CF_VSSTGPROJECTITEMS")) + { + // The drag and drop operation came from the VS solution explorer + return data.GetText(); + } + + return null; + } + + //public static string RelativePath(string absPath, string relTo) + //{ + // string[] absDirs = absPath.Split('\\'); + // string[] relDirs = relTo.Split('\\'); + + // // Get the shortest of the two paths + // int len = absDirs.Length < relDirs.Length ? absDirs.Length : + // relDirs.Length; + + // // Use to determine where in the loop we exited + // int lastCommonRoot = -1; + // int index; + + // // Find common root + // for (index = 0; index < len; index++) + // { + // if (absDirs[index] == relDirs[index]) lastCommonRoot = index; + // else break; + // } + + // // If we didn't find a common prefix then throw + // if (lastCommonRoot == -1) + // { + // return relTo; + // } + + // // Build up the relative path + // StringBuilder relativePath = new StringBuilder(); + + // // Add on the .. + // for (index = lastCommonRoot + 2; index < absDirs.Length; index++) + // { + // if (absDirs[index].Length > 0) relativePath.Append("..\\"); + // } + + // // Add on the folders + // for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++) + // { + // relativePath.Append(relDirs[index] + "\\"); + // } + // relativePath.Append(relDirs[relDirs.Length - 1]); + + // return relativePath.ToString().Replace("\\", "/"); + //} + } +} diff --git a/EditorExtensions/DropTargets/ImageDrop.cs b/EditorExtensions/DropTargets/ImageDrop.cs new file mode 100644 index 000000000..3b71a6d21 --- /dev/null +++ b/EditorExtensions/DropTargets/ImageDrop.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.DragDrop; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IDropHandlerProvider))] + [DropFormat("FileDrop")] + [DropFormat("CF_VSSTGPROJECTITEMS")] + [Name("ImageDropHandler")] + [ContentType("CSS")] + [ContentType("LESS")] + [Order(Before = "DefaultFileDropHandler")] + internal class ImageDropHandlerProvider : IDropHandlerProvider + { + public IDropHandler GetAssociatedDropHandler(IWpfTextView view) + { + return view.Properties.GetOrCreateSingletonProperty(() => new ImageDropHandler(view)); + } + } + + internal class ImageDropHandler : IDropHandler + { + IWpfTextView _view; + private readonly List _imageExtensions = new List { ".jpg", ".jpeg", ".bmp", ".png", ".gif", ".svg", ".tif", ".tiff" }; + private string _imageFilename; + string _background = "background-image: url({0});"; + + public ImageDropHandler(IWpfTextView view) + { + this._view = view; + } + + public DragDropPointerEffects HandleDataDropped(DragDropInfo dragDropInfo) + { + string reference = FileHelpers.RelativePath(EditorExtensionsPackage.DTE.ActiveDocument.FullName, _imageFilename); + + if (reference.Contains("://")) + { + int index = reference.IndexOf('/', 12); + if (index > -1) + reference = reference.Substring(index).ToLowerInvariant(); + } + + _view.TextBuffer.Insert(dragDropInfo.VirtualBufferPosition.Position.Position, string.Format(_background, reference)); + + return DragDropPointerEffects.Copy; + } + + public void HandleDragCanceled() + { + + } + + public DragDropPointerEffects HandleDragStarted(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public DragDropPointerEffects HandleDraggingOver(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public bool IsDropEnabled(DragDropInfo dragDropInfo) + { + _imageFilename = FontDropHandler.GetImageFilename(dragDropInfo); + + if (!string.IsNullOrEmpty(_imageFilename)) + { + string fileExtension = Path.GetExtension(_imageFilename).ToLowerInvariant(); + if (this._imageExtensions.Contains(fileExtension)) + { + return true; + } + } + + return false; + } + } +} diff --git a/EditorExtensions/DropTargets/StylesheetDrop.cs b/EditorExtensions/DropTargets/StylesheetDrop.cs new file mode 100644 index 000000000..448244ead --- /dev/null +++ b/EditorExtensions/DropTargets/StylesheetDrop.cs @@ -0,0 +1,84 @@ +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.DragDrop; +using Microsoft.VisualStudio.Utilities; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IDropHandlerProvider))] + [DropFormat("StylesheetDrop")] + [DropFormat("CF_VSSTGPROJECTITEMS")] + [Name("StylesheetDropDropHandler")] + [ContentType("CSS")] + [ContentType("LESS")] + [Order(Before = "DefaultFileDropHandler")] + internal class StylesheetDropHandlerProvider : IDropHandlerProvider + { + public IDropHandler GetAssociatedDropHandler(IWpfTextView view) + { + return view.Properties.GetOrCreateSingletonProperty(() => new StylesheetDropHandler(view)); + } + } + + internal class StylesheetDropHandler : IDropHandler + { + IWpfTextView _view; + private readonly List _imageExtensions = new List { ".css", ".less", ".sass", ".scss" }; + private string _imageFilename; + string _background = "@import url('{0}');"; + + public StylesheetDropHandler(IWpfTextView view) + { + this._view = view; + } + + public DragDropPointerEffects HandleDataDropped(DragDropInfo dragDropInfo) + { + string reference = FileHelpers.RelativePath(EditorExtensionsPackage.DTE.ActiveDocument.FullName, _imageFilename); + + if (reference.StartsWith("http://localhost:")) + { + int index = reference.IndexOf('/', 24); + if (index > -1) + reference = reference.Substring(index).ToLowerInvariant(); + } + + _view.TextBuffer.Insert(dragDropInfo.VirtualBufferPosition.Position.Position, string.Format(_background, reference)); + + return DragDropPointerEffects.Copy; + } + + public void HandleDragCanceled() + { + + } + + public DragDropPointerEffects HandleDragStarted(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public DragDropPointerEffects HandleDraggingOver(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public bool IsDropEnabled(DragDropInfo dragDropInfo) + { + _imageFilename = FontDropHandler.GetImageFilename(dragDropInfo); + + if (!string.IsNullOrEmpty(_imageFilename)) + { + string fileExtension = Path.GetExtension(_imageFilename).ToLowerInvariant(); + if (this._imageExtensions.Contains(fileExtension)) + { + return true; + } + } + + return false; + } + } +} diff --git a/EditorExtensions/DropTargets/TypeScriptDrop.cs b/EditorExtensions/DropTargets/TypeScriptDrop.cs new file mode 100644 index 000000000..dd0b7af1b --- /dev/null +++ b/EditorExtensions/DropTargets/TypeScriptDrop.cs @@ -0,0 +1,86 @@ +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.DragDrop; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IDropHandlerProvider))] + [DropFormat("CF_VSSTGPROJECTITEMS")] + [Name("TypeScriptDropHandler")] + [ContentType("TypeScript")] + [Order(Before = "DefaultFileDropHandler")] + internal class TypeScriptDropHandlerProvider : IDropHandlerProvider + { + public IDropHandler GetAssociatedDropHandler(IWpfTextView view) + { + return view.Properties.GetOrCreateSingletonProperty(() => new TypeScriptDropHandler(view)); + } + } + + internal class TypeScriptDropHandler : IDropHandler + { + IWpfTextView _view; + private readonly List _imageExtensions = new List { ".ts", ".js" }; + private string _imageFilename; + string _background = "/// "; + + public TypeScriptDropHandler(IWpfTextView view) + { + this._view = view; + } + + public DragDropPointerEffects HandleDataDropped(DragDropInfo dragDropInfo) + { + string reference = FileHelpers.RelativePath(EditorExtensionsPackage.DTE.ActiveDocument.FullName, _imageFilename); + + if (reference.StartsWith("http://localhost:")) + { + int index = reference.IndexOf('/', 24); + if (index > -1) + reference = reference.Substring(index).ToLowerInvariant(); + } + + reference = reference.Trim('/'); + string comment = string.Format(_background, reference); + + _view.TextBuffer.Insert(0, comment + Environment.NewLine); + + return DragDropPointerEffects.Copy; + } + + public void HandleDragCanceled() + { + + } + + public DragDropPointerEffects HandleDragStarted(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public DragDropPointerEffects HandleDraggingOver(DragDropInfo dragDropInfo) + { + return DragDropPointerEffects.All; + } + + public bool IsDropEnabled(DragDropInfo dragDropInfo) + { + _imageFilename = FontDropHandler.GetImageFilename(dragDropInfo); + + if (!string.IsNullOrEmpty(_imageFilename)) + { + string fileExtension = Path.GetExtension(_imageFilename).ToLowerInvariant(); + if (this._imageExtensions.Contains(fileExtension)) + { + return true; + } + } + + return false; + } + } +} diff --git a/EditorExtensions/EditorExtensions.vsct b/EditorExtensions/EditorExtensions.vsct new file mode 100644 index 000000000..4236bb5b9 --- /dev/null +++ b/EditorExtensions/EditorExtensions.vsct @@ -0,0 +1,753 @@ + + + + + + + + + + + + Encode Selection + Encode Selection + + + + + + Transform Selection + Transform Selection + + + + + DynamicVisibility + + Web Essentials + Web Essentials + + + + + + Web Essentials + Web Essentials + + + + + + Web Essentials + Web Essentials + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EditorExtensions/EditorExtensionsPackage.cs b/EditorExtensions/EditorExtensionsPackage.cs new file mode 100644 index 000000000..d620163c0 --- /dev/null +++ b/EditorExtensions/EditorExtensionsPackage.cs @@ -0,0 +1,227 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.ComponentModelHost; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using System; +using System.ComponentModel.Design; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + // The key for registering option pages in Text Editors -> CSS + //HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Languages\Language Services\CSS\EditorToolsOptions\Format + + + [PackageRegistration(UseManagedResourcesOnly = true)] + [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] + [Guid(GuidList.guidEditorExtensionsPkgString)] + [ProvideMenuResource("Menus.ctmenu", 1)] + [ProvideAutoLoad(UIContextGuids80.SolutionExists)] + [ProvideOptionPage(typeof(GeneralOptions), "Web Essentials", "General", 101, 101, true, new[] { "ZenCoding", "Mustache", "Handlebars", "Comments", "Bundling", "Bundle" })] + [ProvideOptionPage(typeof(CssOptions), "Web Essentials", "CSS", 101, 102, true, new[] { "Minify", "Minification", "W3C", "CSS3" })] + [ProvideOptionPage(typeof(JsHintOptions), "Web Essentials", "JSHint", 101, 103, true, new[] { "JSLint", "Lint" })] + //[ProvideOptionPage(typeof(TypeScriptOptions), "Web Essentials", "TypeScript", 101, 104, true, new[] { "Minify", "Minification" })] + [ProvideOptionPage(typeof(LessOptions), "Web Essentials", "LESS", 101, 105, true)] + [ProvideOptionPage(typeof(CoffeeScriptOptions), "Web Essentials", "CoffeeScript", 101, 106, true, new[] { "Iced", "JavaScript", "JS", "JScript" })] + [ProvideOptionPage(typeof(JavaScriptOptions), "Web Essentials", "JavaScript", 101, 107, true, new[] { "JScript", "JS", "Minify", "Minification", "EcmaScript" })] + //[ProvideOptionPage(typeof(ScssOptions), "Web Essentials", "SCSS", 101, 108, true)] + [ProvideSearchProvider(typeof(Microsoft.MSDNSearch.VSSearchProvider), "VS Gallery Search")] + public sealed class EditorExtensionsPackage : ExtensionPointPackage + { + private static DTE2 _dte; + private static IVsRegisterPriorityCommandTarget _pct; + + public EditorExtensionsPackage() + { + } + + internal static DTE2 DTE + { + get + { + if (_dte == null) + { + _dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE2; + Debug.Assert(_dte != null); + } + + return _dte; + } + } + + internal static IVsRegisterPriorityCommandTarget PriorityCommandTarget + { + get + { + if (_pct == null) + { + _pct = ServiceProvider.GlobalProvider.GetService(typeof(SVsRegisterPriorityCommandTarget)) as IVsRegisterPriorityCommandTarget; + } + + return _pct; + } + } + + public static EditorExtensionsPackage Instance { get; private set; } + + protected override void Initialize() + { + base.Initialize(); + Instance = this; + JsDocComments.Register(); + + OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; + if (null != mcs) + { + HandleMenuVisibility(mcs); + + //EncodingMenu encoding = new EncodingMenu(DTE, mcs); + //encoding.SetupCommands(); + + TransformMenu transform = new TransformMenu(DTE, mcs); + transform.SetupCommands(); + + //CssSortPropertiesMenu cssTasks = new CssSortPropertiesMenu(DTE, mcs); + //cssTasks.SetupCommands(); + + //CssRemoveDuplicates cssRemoveDuplicates = new CssRemoveDuplicates(DTE, mcs); + //cssRemoveDuplicates.SetupCommands(); + + //CssAddMissingVendor cssAddMissingVendor = new CssAddMissingVendor(DTE, mcs); + //cssAddMissingVendor.SetupCommands(); + + //CssAddMissingStandard cssAddMissingStandard = new CssAddMissingStandard(DTE, mcs); + //cssAddMissingStandard.SetupCommands(); + + DiffMenu diffMenu = new DiffMenu(DTE, mcs); + diffMenu.SetupCommands(); + + MinifyFileMenu minifyMenu = new MinifyFileMenu(DTE, mcs); + minifyMenu.SetupCommands(); + + BundleFilesMenu bundleMenu = new BundleFilesMenu(DTE, mcs); + bundleMenu.SetupCommands(); + + JsHintMenu jsHintMenu = new JsHintMenu(DTE, mcs); + jsHintMenu.SetupCommands(); + + ProjectSettingsMenu projectSettingsMenu = new ProjectSettingsMenu(DTE, mcs); + projectSettingsMenu.SetupCommands(); + + SolutionColorsMenu solutionColorsMenu = new SolutionColorsMenu(DTE, mcs); + solutionColorsMenu.SetupCommands(); + + BuildMenu buildMenu = new BuildMenu(DTE, mcs); + buildMenu.SetupCommands(); + + MarkdownStylesheetMenu markdownMenu = new MarkdownStylesheetMenu(DTE, mcs); + markdownMenu.SetupCommands(); + + //CssExtractToFileMenu extractToFileMenu = new CssExtractToFileMenu(DTE, mcs); + //extractToFileMenu.SetupCommands(); + } + + // Hook up event handlers + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => + { + DTE.Events.BuildEvents.OnBuildDone += BuildEvents_OnBuildDone; + DTE.Events.SolutionEvents.Opened += delegate { Settings.UpdateCache(); Settings.UpdateStatusBar("applied"); }; + DTE.Events.SolutionEvents.AfterClosing += delegate { DTE.StatusBar.Clear(); }; + + }), DispatcherPriority.ApplicationIdle, null); + } + + private void BuildEvents_OnBuildDone(vsBuildScope Scope, vsBuildAction Action) + { + if (Action != vsBuildAction.vsBuildActionClean) + { + //if (WESettings.GetBoolean(WESettings.Keys.CompileTypeScriptOnBuild)) + // _dte.Commands.Raise(GuidList.guidBuildCmdSetString, (int)PkgCmdIDList.cmdBuildTypeScript, null, null); + //new TypeScriptMargin().CompileProjectFiles(null); + + if (WESettings.GetBoolean(WESettings.Keys.LessCompileOnBuild)) + _dte.Commands.Raise(GuidList.guidBuildCmdSetString, (int)PkgCmdIDList.cmdBuildLess, null, null); + //LessProjectCompiler.CompileProject(); + + if (WESettings.GetBoolean(WESettings.Keys.CoffeeScriptCompileOnBuild)) + _dte.Commands.Raise(GuidList.guidBuildCmdSetString, (int)PkgCmdIDList.cmdBuildCoffeeScript, null, null); + + //BundleFilesMenu.UpdateBundles(null, true); + _dte.Commands.Raise(GuidList.guidBuildCmdSetString, (int)PkgCmdIDList.cmdBuildBundles, null, null); + + if (WESettings.GetBoolean(WESettings.Keys.RunJsHintOnBuild)) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => JsHintProjectRunner.RunOnAllFilesInProject()), DispatcherPriority.ApplicationIdle, null); + } + } + else if (Action == vsBuildAction.vsBuildActionClean) + { + System.Threading.Tasks.Task.Run(() => JsHintRunner.Reset()); + } + } + + public static void ExecuteCommand(string commandName) + { + var command = EditorExtensionsPackage.DTE.Commands.Item(commandName); + if (command.IsAvailable) + { + EditorExtensionsPackage.DTE.ExecuteCommand(commandName); + } + } + + private void HandleMenuVisibility(OleMenuCommandService mcs) + { + CommandID commandId = new CommandID(GuidList.guidCssIntellisenseCmdSet, (int)PkgCmdIDList.CssIntellisenseSubMenu); + OleMenuCommand menuCommand = new OleMenuCommand((s, e) => { }, commandId); + menuCommand.BeforeQueryStatus += menuCommand_BeforeQueryStatus; + mcs.AddCommand(menuCommand); + } + + private readonly string[] _supported = new[] { "CSS", "LESS", "SCSS", "JAVASCRIPT", "PROJECTION", "TYPESCRIPT", "MARKDOWN" }; + + void menuCommand_BeforeQueryStatus(object sender, EventArgs e) + { + OleMenuCommand menu = (OleMenuCommand)sender; + var buffer = ProjectHelpers.GetCurentTextBuffer(); + + menu.Visible = buffer != null && _supported.Contains(buffer.ContentType.DisplayName.ToUpperInvariant()); + } + + public static T GetGlobalService(Type type = null) where T : class + { + return Microsoft.VisualStudio.Shell.Package.GetGlobalService(type ?? typeof(T)) as T; + } + + public static IComponentModel ComponentModel + { + get { return GetGlobalService(typeof(SComponentModel)); } + } + + //internal static IVsHierarchy GetIVsHierarchy(Project project) + //{ + // IVsSolution solution = (IVsSolution)ServiceProvider.GlobalProvider.GetService(typeof(IVsSolution)); + // if (solution == null) + // { + // return null; + // } + + // IVsHierarchy hier; + + // Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(solution.GetProjectOfUniqueName(project.UniqueName, out hier)); + + // if (hier == null) + // { + // return null; + // } + // else + // { + // return hier; + // } + //} + } +} diff --git a/EditorExtensions/ErrorTags/Filters/Backslash9CssErrorFilter.cs b/EditorExtensions/ErrorTags/Filters/Backslash9CssErrorFilter.cs new file mode 100644 index 000000000..0940a2a10 --- /dev/null +++ b/EditorExtensions/ErrorTags/Filters/Backslash9CssErrorFilter.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssErrorFilter))] + [Name("Backslash9CssErrorFilter")] + [Order(After = "Default")] + internal class Backslash9CssErrorFilter : ICssErrorFilter + { + public void FilterErrorList(IList errors, ICssCheckerContext context) + { + for (int i = errors.Count - 1; i > -1; i--) + { + ICssError error = errors[i]; + Declaration dec = error.Item.FindType(); + + if (dec != null && dec.Text.Contains("\\9")) + { + errors.RemoveAt(i); + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Filters/CustomCssErrorFilter.cs b/EditorExtensions/ErrorTags/Filters/CustomCssErrorFilter.cs new file mode 100644 index 000000000..a1f6d8ba1 --- /dev/null +++ b/EditorExtensions/ErrorTags/Filters/CustomCssErrorFilter.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssErrorFilter))] + [Name("Custom Errors")] + [Order(After = "Default")] + internal class CustomCssErrorFilter : ICssErrorFilter + { + private readonly Dictionary _messsages = new Dictionary() + { + { "cursorhand", "Consider using \"pointer\" instead." }, + { "cursornormal", "Consider using \"default\" instead." } + }; + + public void FilterErrorList(IList errors, ICssCheckerContext context) + { + for (int i = errors.Count - 1; i > -1; i--) + { + ICssError error = errors[i]; + if (error.Item.IsValid) + { + Declaration dec = error.Item.FindType(); + if (dec != null && dec.IsValid && dec.PropertyName.Text == "cursor") + { + if (error.Item.Text == "hand") + { + errors.RemoveAt(i); + errors.Insert(i, CreateNewError(error, "cursorhand")); + } + else if (error.Item.Text == "normal") + { + errors.RemoveAt(i); + errors.Insert(i, CreateNewError(error, "cursornormal")); + } + } + } + } + } + + private SimpleErrorTag CreateNewError(ICssError error, string messageKey) + { + string message = error.Text + " " + _messsages[messageKey]; + return new SimpleErrorTag(error.Item, message, CssErrorFlags.TaskListError | CssErrorFlags.UnderlineRed); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Filters/MsFilterCssErrorFilter.cs b/EditorExtensions/ErrorTags/Filters/MsFilterCssErrorFilter.cs new file mode 100644 index 000000000..29f23083e --- /dev/null +++ b/EditorExtensions/ErrorTags/Filters/MsFilterCssErrorFilter.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssErrorFilter))] + [Name("MsFilterCssErrorFilter")] + [Order(After = "Default")] + internal class MsFilterCssErrorFilter : ICssErrorFilter + { + public void FilterErrorList(IList errors, ICssCheckerContext context) + { + for (int i = errors.Count - 1; i > -1; i--) + { + ICssError error = errors[i]; + Declaration dec = error.Item.FindType(); + if (dec != null && dec.IsValid && dec.PropertyName.Text == "-ms-filter") + { + errors.RemoveAt(i); + errors.Insert(i, CreateNewError(error)); + } + } + } + + private SimpleErrorTag CreateNewError(ICssError error) + { + string message = error.Text + " " + " The value must be wrapped in single or double qoutation marks."; + return new SimpleErrorTag(error.Item, message, CssErrorFlags.TaskListError | CssErrorFlags.UnderlineRed); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Filters/MsKeyframesCssErrorFilter.cs b/EditorExtensions/ErrorTags/Filters/MsKeyframesCssErrorFilter.cs new file mode 100644 index 000000000..df4c4e6e6 --- /dev/null +++ b/EditorExtensions/ErrorTags/Filters/MsKeyframesCssErrorFilter.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssErrorFilter))] + [Name("MsKeyframesCssErrorFilter")] + [Order(After = "Default")] + internal class MsKeyframesCssErrorFilter : ICssErrorFilter + { + private static readonly string _message = " IE only supportes the standard @keyframes implementation."; + + public void FilterErrorList(IList errors, ICssCheckerContext context) + { + for (int i = errors.Count - 1; i > -1; i--) + { + ICssError error = errors[i]; + if (error.Item.IsValid) + { + AtDirective atDir = error.Item.FindType(); + if (atDir != null && atDir.IsValid && atDir.Keyword.Text == "-ms-keyframes") + { + errors.RemoveAt(i); + ICssError tag = new SimpleErrorTag(error.Item, error.Text + _message, CssErrorFlags.TaskListError | CssErrorFlags.UnderlineRed); + errors.Insert(i, tag); + } + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Filters/ScssErrorFilter.cs b/EditorExtensions/ErrorTags/Filters/ScssErrorFilter.cs new file mode 100644 index 000000000..055314037 --- /dev/null +++ b/EditorExtensions/ErrorTags/Filters/ScssErrorFilter.cs @@ -0,0 +1,33 @@ +//using System.Collections.Generic; +//using System.ComponentModel.Composition; +//using Microsoft.CSS.Core; +//using Microsoft.VisualStudio.Utilities; +//using System.IO; +//using System; + +//namespace MadsKristensen.EditorExtensions +//{ +// [Export(typeof(ICssErrorFilter))] +// [Name("ScssErrorFilter")] +// [Order(After = "Default")] +// internal class ScssErrorFilter : ICssErrorFilter +// { +// public void FilterErrorList(IList errors, ICssCheckerContext context) +// { +// var document = EditorExtensionsPackage.DTE.ActiveDocument; + +// if (document == null || !Path.GetExtension(document.FullName).Equals(ScssContentTypeDefinition.ScssFileExtension, StringComparison.OrdinalIgnoreCase)) +// return; + +// for (int i = errors.Count - 1; i > -1; i--) +// { +// ICssError error = errors[i]; + +// if ((error.Flags & CssErrorFlags.TaskListError) == CssErrorFlags.TaskListError) +// { +// errors.RemoveAt(i); +// } +// } +// } +// } +//} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/ColorValuesInRangeErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/ColorValuesInRangeErrorTagProvider.cs new file mode 100644 index 000000000..3ad98f643 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/ColorValuesInRangeErrorTagProvider.cs @@ -0,0 +1,86 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("ColorValuesInRangeErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class ColorValuesInRangeErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + FunctionColor function = (FunctionColor)item; + + if (!function.IsValid || context == null) + return ItemCheckResult.Continue; + + if (function.FunctionName.Text.StartsWith("rgb")) + { + ValidateRgb(context, function); + } + //else if (function.FunctionName.Text.StartsWith("hsl")) + //{ + // ValidateHsl(context, function); + //} + + return ItemCheckResult.Continue; + } + + private static void ValidateRgb(ICssCheckerContext context, FunctionColor function) + { + for (int i = 0; i < function.Arguments.Count; i++) + { + var argument = function.Arguments[i]; + string text = argument.Text.Trim(','); + + if (i < 3) + { + int value; + if (int.TryParse(text, out value) && (value < 0 || value > 255)) + context.AddError(new SimpleErrorTag(argument, Resources.ValidationColorValuesInRange, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + else + { + ValidateAlphaValue(context, argument, text); + } + } + } + + private static void ValidateHsl(ICssCheckerContext context, FunctionColor function) + { + for (int i = 0; i < function.Arguments.Count; i++) + { + var argument = function.Arguments[i]; + string text = argument.Text.Trim(',','%'); + + if (i < 3) + { + int value; + if (int.TryParse(text, out value) && (value < 0 || value > 100)) + context.AddError(new SimpleErrorTag(argument, "Validation: Values must be between 0 and 100%", CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + else + { + ValidateAlphaValue(context, argument, text); + } + } + } + + private static void ValidateAlphaValue(ICssCheckerContext context, ParseItem argument, string text) + { + double value; + if (double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value) && (value < 0 || value > 1)) + context.AddError(new SimpleErrorTag(argument, "Validation: The opacity value must be between 0 and 1", CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(FunctionColor) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/DisplayInlineErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/DisplayInlineErrorTagProvider.cs new file mode 100644 index 000000000..34e93107e --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/DisplayInlineErrorTagProvider.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Utilities; +using System.Reflection; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IWpfTextViewConnectionListener))] + [ContentType(Microsoft.Web.Editor.CssContentTypeDefinition.CssContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + class DisplayInlineTextViewCreationListener : IWpfTextViewConnectionListener + { + public void SubjectBuffersConnected(IWpfTextView textView, ConnectionReason reason, Collection subjectBuffers) + { + foreach (ITextBuffer buffer in subjectBuffers) + { + CssEditorDocument doc = CssEditorDocument.FromTextBuffer(buffer); + doc.Tree.ItemsChanged += Tree_ItemsChanged; + doc.Tree.TreeUpdated += Tree_TreeUpdated; + InitializeCache(doc.Tree.StyleSheet); + } + } + + void Tree_TreeUpdated(object sender, CssTreeUpdateEventArgs e) + { + InitializeCache(e.Tree.StyleSheet); + } + + private void InitializeCache(StyleSheet stylesheet) + { + _cache.Clear(); + + var visitor = new CssItemCollector(true); + stylesheet.Accept(visitor); + + foreach (Declaration dec in visitor.Items.Where(d => d.PropertyName != null)) + { + if (dec.PropertyName.Text == "display" && dec.Values.Any(v => v.Text == "inline")) + _cache.Add(dec); + } + } + + public void SubjectBuffersDisconnected(IWpfTextView textView, ConnectionReason reason, Collection subjectBuffers) + { + foreach (ITextBuffer buffer in subjectBuffers) + { + CssEditorDocument doc = CssEditorDocument.FromTextBuffer(buffer); + doc.Tree.ItemsChanged -= Tree_ItemsChanged; + } + } + + private HashSet _cache = new HashSet(); + + void Tree_ItemsChanged(object sender, CssItemsChangedEventArgs e) + { + CssTree tree = (CssTree)sender; + + foreach (ParseItem item in e.InsertedItems) + { + var visitor = new CssItemCollector(true); + item.Accept(visitor); + + foreach (Declaration dec in visitor.Items) + { + if (dec.PropertyName != null && dec.PropertyName.Text == "display" && dec.Values.Any(v => v.Text == "inline")) + { + _cache.Add(dec); + + ParseItem rule = dec.Parent; + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => Update(rule, tree)), DispatcherPriority.Normal); + } + } + } + + foreach (ParseItem item in e.DeletedItems) + { + var visitor = new CssItemCollector(true); + item.Accept(visitor); + + foreach (Declaration deleted in visitor.Items) + { + if (_cache.Contains(deleted)) + { + _cache.Remove(deleted); + + ParseItem rule = deleted.Parent; + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => Update(rule, tree)), DispatcherPriority.Normal); + } + } + } + } + + private static void Update(ParseItem rule, CssTree tree) + { + BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod; + object[] parameters = new object[3]; + parameters[0] = new ParseItemList(); + parameters[1] = new ParseItemList(); + parameters[2] = new ParseItemList() { rule }; + + typeof(CssTree).InvokeMember("FireOnItemsChanged", flags, null, tree, parameters); + } + } + + [Export(typeof(ICssItemChecker))] + [Name("DisplayInlineErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class DisplayInlineErrorTagProvider : ICssItemChecker + { + private static string[] invalidProperties = new[] { "margin-top", "margin-bottom", "height", "width" }; + + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + RuleBlock rule = (RuleBlock)item; + + if (!rule.IsValid || context == null) + return ItemCheckResult.Continue; + + bool isInline = rule.Declarations.Any(d => d.PropertyName != null && d.PropertyName.Text == "display" && d.Values.Any(v => v.Text == "inline")); + if (!isInline) + return ItemCheckResult.Continue; + + IEnumerable invalids = rule.Declarations.Where(d => invalidProperties.Contains(d.PropertyName.Text)); + + foreach (Declaration invalid in invalids) + { + string error = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeInlineIncompat, invalid.PropertyName.Text); + context.AddError(new SimpleErrorTag(invalid.PropertyName, error)); + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(RuleBlock) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/DuplicatePropertyErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/DuplicatePropertyErrorTagProvider.cs new file mode 100644 index 000000000..e489d7497 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/DuplicatePropertyErrorTagProvider.cs @@ -0,0 +1,64 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System.Globalization; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("DuplicatePropertyErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class DuplicatePropertyErrorTagProvider : ICssItemChecker + { + // The rules of this error is specified here: https://github.com/stubbornella/csslint/wiki/Disallow-duplicate-properties + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + RuleBlock rule = (RuleBlock)item; + + if (!rule.IsValid || context == null) + return ItemCheckResult.Continue; + + Dictionary dic = new Dictionary(); + + foreach (Declaration declaration in rule.Declarations) + { + ParseItem prop = declaration.PropertyName; + if (prop == null || prop.Text == "filter") + continue; + + string error = null; + + if (!dic.ContainsKey(declaration.Text)) + { + if (dic.ContainsValue(prop.Text) && dic.Last().Value != prop.Text) + { + // The same property name is specified, but not by the immidiate previous declaration + error = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeDuplicatePropertyInRule, prop.Text); + } + + dic.Add(declaration.Text, prop.Text); + } + else + { + // The same property and value exist more than once in the rule. The exact declaration duplicate + error = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeDuplicatePropertyWithSameValueInRule, prop.Text); + } + + if (error != null) + { + context.AddError(new SimpleErrorTag(prop, error)); + } + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(RuleBlock) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/DuplicateSelectorErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/DuplicateSelectorErrorTagProvider.cs new file mode 100644 index 000000000..7aaccfd1b --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/DuplicateSelectorErrorTagProvider.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("DuplicateSelectorErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class DuplicateSelectorErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + RuleSet rule = (RuleSet)item; + + if (!rule.IsValid || context == null) + return ItemCheckResult.Continue; + + List cache = context.GetState(this) as List; + + if (cache == null || (cache.Count > 0 && cache[0].Rule.Parent != rule.Parent)) + { + cache = BuildCache(rule); + context.SetState(this, cache); + } + + string ruleText = GetSelectorText(rule); + int start = rule.Start; + RuleResult dupe = null; + for (int i = 0; i < cache.Count; i++) + { + if (cache[i].Start >= start) + break; + + if (ruleText == cache[i].Value) + { + dupe = cache[i]; + break; + } + } + + if (dupe != null) + { + int length = GetSelectorLength(rule); + int lineNo = FindLineNumber(dupe); + + string errorMessage = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeDuplicateSelectors, lineNo); + SelectorErrorTag tag = new SelectorErrorTag(rule.Selectors, errorMessage); + context.AddError(tag); + } + + return ItemCheckResult.Continue; + } + + // TODO: Is there a better way to find the line number? + private static int FindLineNumber(RuleResult ost) + { + string text = ost.Rule.StyleSheet.Text.Substring(0, ost.Start); + return text.Count(t => t == '\n') + 1; + } + + private static string GetSelectorText(RuleSet rule) + { + var selectorsText = rule.Selectors.OrderBy(s => s.Text.Trim(',')).Select(s => s.Text.Trim(',')); + return string.Concat(selectorsText); + } + + private static int GetSelectorLength(RuleSet rule) + { + var selector = rule.Selectors.Last(); + return selector.AfterEnd - rule.Start; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(RuleSet) }; } + } + + private List BuildCache(RuleSet rule) + { + var visitor = new CssItemCollector(); + rule.Parent.Accept(visitor); + List list = new List(); + + foreach (RuleSet rs in visitor.Items) + { + RuleResult result = new RuleResult(rs, rs.Start, GetSelectorText(rs)); + list.Add(result); + } + + return list; + } + + private class RuleResult + { + public RuleResult(RuleSet rule, int start, string value) + { + Rule = rule; + Start = start; + Value = value; + } + + public RuleSet Rule; + public int Start; + public string Value; + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/EmbedImagesErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/EmbedImagesErrorTagProvider.cs new file mode 100644 index 000000000..78dd1e091 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/EmbedImagesErrorTagProvider.cs @@ -0,0 +1,46 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("EmbedImagesErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class EmbedImagesErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + UrlItem url = (UrlItem)item; + + if (!WESettings.GetBoolean(WESettings.Keys.ValidateEmbedImages) || !url.IsValid || url.UrlString.Text.Contains("base64,") || context == null) + return ItemCheckResult.Continue; + + string fileName = ImageQuickInfo.GetFileName(url.UrlString.Text); + if (fileName.Contains("://")) + return ItemCheckResult.Continue; + + FileInfo file = new FileInfo(fileName); + + if (file.Exists && file.Length < (1024 * 3)) + { + Declaration dec = url.FindType(); + if (dec != null && dec.PropertyName != null && dec.PropertyName.Text[0] != '*' && dec.PropertyName.Text[0] != '_') + { + string error = string.Format(Resources.PerformanceEmbedImageAsDataUri, file.Length); + context.AddError(new SimpleErrorTag(url.UrlString, error)); + } + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(UrlItem) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/HoverOrderErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/HoverOrderErrorTagProvider.cs new file mode 100644 index 000000000..2cc31f619 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/HoverOrderErrorTagProvider.cs @@ -0,0 +1,79 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("HoverOrderErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class HoverOrderErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + if (item.Text.TrimStart(':').StartsWith("-")) + return ItemCheckResult.Continue; + + ParseItem next = item.NextSibling; + //ParseItem prev = item.PreviousSibling; + SimpleSelector sel = item.FindType(); + + //if (item.Text == ":hover" && prev != null && _invalids.Contains(prev.Text)) + //{ + // string error = string.Format(Resources.ValidationHoverOrder, prev.Text); + // context.AddError(new SimpleErrorTag(item, error, CssErrorFlags.TaskListError | CssErrorFlags.UnderlineRed)); + //} + + if (next != null) + { + if (next.Text.StartsWith(":") && item.IsPseudoElement() && !next.IsPseudoElement()) + { + string error = string.Format(Resources.ValidationPseudoOrder, item.Text, next.Text); + context.AddError(new SimpleErrorTag(item, error, CssErrorFlags.TaskListError | CssErrorFlags.UnderlineRed)); + } + + else if (!next.Text.StartsWith(":") && item.AfterEnd == next.Start) + { + string error = string.Format(Resources.BestPracticePseudosAfterOtherSelectors, next.Text); + context.AddError(new SimpleErrorTag(next, error)); + } + } + + return ItemCheckResult.Continue; + } + + //public static bool IsPseudoElement(ParseItem item) + //{ + // if (item.Text.StartsWith("::")) + // return true; + + // var schema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + // return schema.GetPseudo(":" + item.Text) != null; + //} + + private static List _invalids = new List() + { + ":before", + "::before", + ":after", + "::after", + }; + + public IEnumerable ItemTypes + { + get + { + return new[] + { + typeof(PseudoClassSelector), + typeof(PseudoClassFunctionSelector), + typeof(PseudoElementFunctionSelector), + typeof(PseudoElementSelector), + }; + } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/Ie10PrefixErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/Ie10PrefixErrorTagProvider.cs new file mode 100644 index 000000000..39e274743 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/Ie10PrefixErrorTagProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("Ie10PrefixErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class Ie10PrefixErrorTagProvider : ICssItemChecker + { + private static readonly string _message = "Validation (WE): {0} no longer applies to Internet Explorer 10. Use the standard implementation instead."; + + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + Declaration dec = (Declaration)item; + + if (context == null || !dec.IsValid) + return ItemCheckResult.Continue; + + string text = dec.PropertyName.Text; + + if (text.StartsWith("-ms-transition", StringComparison.Ordinal) || text.StartsWith("-ms-animation", StringComparison.Ordinal)) + { + string error = string.Format(_message, text); + ICssError tag = new SimpleErrorTag(dec.PropertyName, error); + context.AddError(tag); + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(Declaration) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/InvalidVendorErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/InvalidVendorErrorTagProvider.cs new file mode 100644 index 000000000..7273f1131 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/InvalidVendorErrorTagProvider.cs @@ -0,0 +1,126 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("InvalidVendorDeclarationErrorTagProvider")] + [Order(After = "Ie10PrefixErrorTagProvider")] + internal class InvalidVendorDeclarationErrorTagProvider : ICssItemChecker + { + //private HashSet _deprecated = new HashSet() + //{ + // "-moz-opacity", + // "-moz-outline", + // "-moz-outline-style", + //}; + + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + if (!WESettings.GetBoolean(WESettings.Keys.ValidateVendorSpecifics)) + return ItemCheckResult.Continue; + + Declaration dec = (Declaration)item; + + if (!dec.IsValid || !dec.IsVendorSpecific() || context == null) + return ItemCheckResult.Continue; + + ICssSchemaInstance rootSchema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, item); + + //if (_deprecated.Contains(dec.PropertyName.Text)) + //{ + // string message = string.Format(Resources.ValidationDeprecatedVendorDeclaration, dec.PropertyName.Text); + // context.AddError(new SimpleErrorTag(dec.PropertyName, message)); + // return ItemCheckResult.CancelCurrentItem; + //} + if (schema.GetProperty(dec.PropertyName.Text) == null) + { + string message = string.Format(Resources.ValidationVendorDeclarations, dec.PropertyName.Text); + context.AddError(new SimpleErrorTag(dec.PropertyName, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(Declaration) }; } + } + } + + [Export(typeof(ICssItemChecker))] + [Name("InvalidVendorPseudoErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class InvalidVendorPseudoErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + if (!WESettings.GetBoolean(WESettings.Keys.ValidateVendorSpecifics)) + return ItemCheckResult.Continue; + + if (!item.IsValid || context == null) + return ItemCheckResult.Continue; + + ICssSchemaInstance rootSchema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, item); + + string normalized = item.Text.Trim(':'); + + if (normalized.Length > 0 && normalized[0] == '-' && schema.GetPseudo(item.Text) == null) + { + string message = string.Format(Resources.ValidationVendorPseudo, item.Text); + context.AddError(new SimpleErrorTag(item, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(PseudoClassSelector), typeof(PseudoElementSelector) }; } + } + } + + [Export(typeof(ICssItemChecker))] + [Name("InvalidVendorDirectiveErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class InvalidVendorDirectiveErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + if (!WESettings.GetBoolean(WESettings.Keys.ValidateVendorSpecifics)) + return ItemCheckResult.Continue; + + AtDirective dir = item as AtDirective; + + if (!dir.IsValid || !dir.IsVendorSpecific() || context == null) + return ItemCheckResult.Continue; + + + ICssSchemaInstance rootSchema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, dir); + + if (schema.GetAtDirective("@" + dir.Keyword.Text) == null) + { + string message = string.Format(Resources.ValidationVendorDirective, dir.Keyword.Text); + context.AddError(new SimpleErrorTag(dir.Keyword, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(AtDirective) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/MissingStandardDirectiveErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/MissingStandardDirectiveErrorTagProvider.cs new file mode 100644 index 000000000..5a3bd2b19 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/MissingStandardDirectiveErrorTagProvider.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Intellisense; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("MissingStandardDirectiveErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class MissingStandardDirectiveErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + AtDirective directive = (AtDirective)item; + + if (context == null || !directive.IsValid || !directive.IsVendorSpecific()) + return ItemCheckResult.Continue; + + ICssCompletionListEntry entry = VendorHelpers.GetMatchingStandardEntry(directive, context); + + if (entry != null) + { + var visitor = new CssItemCollector(); + directive.Parent.Accept(visitor); + if (!visitor.Items.Any(a => "@" + a.Keyword.Text == entry.DisplayText)) + { + string message = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeAddMissingStandardDirective, entry.DisplayText); + context.AddError(new SimpleErrorTag(directive.Keyword, message)); + return ItemCheckResult.CancelCurrentItem; + } + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(AtDirective) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/MissingVendorDirectiveErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/MissingVendorDirectiveErrorTagProvider.cs new file mode 100644 index 000000000..6cfe2a944 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/MissingVendorDirectiveErrorTagProvider.cs @@ -0,0 +1,45 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.CSS.Editor.SyntaxCheck; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("MissingVendorDirectiveErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class MissingVendorDirectiveErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + AtDirective directive = (AtDirective)item; + + if (!directive.IsValid || directive.IsVendorSpecific() || context == null) + return ItemCheckResult.Continue; + + ICssSchemaInstance schema = CssEditorChecker.GetSchemaForItem(context, item); + var missingEntries = directive.GetMissingVendorSpecifics(schema); + + if (missingEntries.Any()) + { + string error = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeAddMissingVendorSpecificDirective, directive.Keyword.Text, string.Join(", ", missingEntries)); + ICssError tag = new SimpleErrorTag(directive.Keyword, error); + context.AddError(tag); + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(AtDirective) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/MissingVendorErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/MissingVendorErrorTagProvider.cs new file mode 100644 index 000000000..f0cc4f0c2 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/MissingVendorErrorTagProvider.cs @@ -0,0 +1,53 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.CSS.Editor.SyntaxCheck; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("MissingVendorErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class MissingVendorErrorTagProvider : ICssItemChecker + { + private static string[] _vendorIgnoreList = new[] { "filter", "zoom", "behavior" }; + + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + Declaration dec = (Declaration)item; + + if (!dec.IsValid || dec.IsVendorSpecific() || IgnoreProperty(dec) || context == null) + return ItemCheckResult.Continue; + + ICssSchemaInstance schema = CssEditorChecker.GetSchemaForItem(context, item); + var missingEntries = dec.GetMissingVendorSpecifics(schema); + + if (missingEntries.ToArray().Length > 0) + { + var missingPrefixes = missingEntries.Select(e => e.Substring(0, e.IndexOf('-', 1) + 1)); + string error = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeAddMissingVendorSpecific, dec.PropertyName.Text, string.Join(", ", missingPrefixes)); + ICssError tag = new SimpleErrorTag(dec.PropertyName, error); + context.AddError(tag); + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + private static bool IgnoreProperty(Declaration declaration) + { + return _vendorIgnoreList.Contains(declaration.PropertyName.Text); + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(Declaration) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/MissingVendorPseudoErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/MissingVendorPseudoErrorTagProvider.cs new file mode 100644 index 000000000..47a0bd591 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/MissingVendorPseudoErrorTagProvider.cs @@ -0,0 +1,116 @@ +//using Microsoft.CSS.Core; +//using Microsoft.CSS.Editor; +//using Microsoft.VisualStudio.Utilities; +//using System; +//using System.Collections.Generic; +//using System.ComponentModel.Composition; +//using System.Linq; + +//namespace MadsKristensen.EditorExtensions +//{ +// [Export(typeof(ICssItemChecker))] +// [Name("MissingVendorPseudoErrorTagProvider")] +// [Order(After = "Default Declaration")] +// internal class MissingVendorPseudoErrorTagProvider : ICssItemChecker +// { +// public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) +// { +// string name = item.Text.TrimStart(':'); +// RuleSet rule = item.FindType(); +// var buffer = ProjectHelpers.GetCurentTextBuffer(); + +// if (rule == null || buffer == null) +// return ItemCheckResult.Continue; + +// ICssSchemaInstance root = CssSchemaManager.SchemaManager.GetSchemaRootForBuffer(buffer); +// ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(root, item); +// string selector = GetSelectorText(rule); +// string standardName = StandardizeName(name); + +// //if (standardName == "selection" || standardName == "progress-bar") +// // return ItemCheckResult.Continue; + +// IEnumerable missingPseudos = FindMissingPseudos(standardName, selector, schema).Where(p => p != item.Text); + +// if (missingPseudos.Any()) +// { +// string message = string.Format("Browser compatibility: Add selector to the rule with missing pseudo element/class ({0})", string.Join(", ", missingPseudos)); +// context.AddError(new SimpleErrorTag(item, message)); +// } + +// return ItemCheckResult.Continue; +// } + +// public static string StandardizeName(string name) +// { +// if (name.StartsWith("-")) +// { +// int index = name.IndexOf('-', 1); +// if (index > -1) +// return name.Substring(index + 1); +// } + +// return name; +// } + +// public static IEnumerable FindMissingPseudos(string name, string selector, ICssSchemaInstance schema) +// { +// ICssCompletionListEntry standard = FindPseudo(schema, name); + +// if (standard != null && !selector.Contains(standard.DisplayText)) +// yield return standard.DisplayText; + +// foreach (string prefix in VendorHelpers.GetPrefixes(schema)) +// { +// string text = GetPseudoName(prefix, name); +// ICssCompletionListEntry pseudo = FindPseudo(schema, text); + +// if (pseudo != null) +// { +// if (!selector.Contains(pseudo.DisplayText)) +// yield return pseudo.DisplayText; +// } +// } +// } + +// private static ICssCompletionListEntry FindPseudo(ICssSchemaInstance schema, string text) +// { +// ICssCompletionListEntry pseudo = schema.GetPseudo(":" + text); + +// if (pseudo == null) +// { +// pseudo = schema.GetPseudo("::" + text); +// } + +// return pseudo; +// } + +// private static string GetPseudoName(string prefix, string name) +// { +// if (prefix == "-moz-") +// { +// if (name.EndsWith("input-placeholder")) +// return "-moz-placeholder"; +// } +// else +// { +// if (name == "placeholder") +// return prefix + "input-placeholder"; +// } + +// return prefix + name; +// } + +// public static string GetSelectorText(RuleSet rule) +// { +// IEnumerable text = rule.Selectors.Select(s => s.Text); + +// return string.Join(",", text); +// } + +// public IEnumerable ItemTypes +// { +// get { return new[] { typeof(PseudoClassSelector) }; } +// } +// } +//} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/MsViewState.cs b/EditorExtensions/ErrorTags/Providers/MsViewState.cs new file mode 100644 index 000000000..2cbb88f34 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/MsViewState.cs @@ -0,0 +1,45 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("MsViewState")] + [Order(After = "Default Declaration")] + internal class MsViewStateErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + var media = item as MediaExpression; + + if (media == null || context == null || !IsWindowsWebApp()) + return ItemCheckResult.Continue; + + int index = media.Text.IndexOf("-ms-view-state", StringComparison.OrdinalIgnoreCase); + + if (index > -1) + { + var property = item.StyleSheet.ItemAfterPosition(media.Start + index); + + string message = "The -ms-view-state has been deprecated in Internet Explorer 11"; + context.AddError(new SimpleErrorTag(property, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + + return ItemCheckResult.Continue; + } + + private bool IsWindowsWebApp() + { + // Add logic to determine if the current project is WWA + return true; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(MediaExpression) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/OverQualifiedSelectorErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/OverQualifiedSelectorErrorTagProvider.cs new file mode 100644 index 000000000..b8c627938 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/OverQualifiedSelectorErrorTagProvider.cs @@ -0,0 +1,44 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("OverQualifiedSelectorErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class OverQualifiedSelectorErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + Selector sel = (Selector)item; + + if (!WESettings.GetBoolean(WESettings.Keys.ValidateOverQualifiedSelector) || !sel.IsValid || context == null) + return ItemCheckResult.Continue; + + int index = sel.Text.IndexOf('#'); + + if (index > 0) + { + string idName = sel.ItemAfterPosition(sel.Start + index).Text; + string remove = sel.Text.Substring(0, index); + string errorMessage = string.Format(CultureInfo.InvariantCulture, Resources.PerformanceDontOverQualifySelectors, idName, remove); + + SimpleErrorTag tag = new SimpleErrorTag(sel, errorMessage, index); + + context.AddError(tag); + } + + return ItemCheckResult.Continue; + } + + + public IEnumerable ItemTypes + { + get { return new[] { typeof(Selector) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/OverriddenPropertyErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/OverriddenPropertyErrorTagProvider.cs new file mode 100644 index 000000000..a7330adc5 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/OverriddenPropertyErrorTagProvider.cs @@ -0,0 +1,55 @@ +//using Microsoft.CSS.Core; +//using Microsoft.VisualStudio.Utilities; +//using System; +//using System.Collections.Generic; +//using System.ComponentModel.Composition; +//using System.Linq; + +//namespace MadsKristensen.EditorExtensions +//{ +// [Export(typeof(ICssItemChecker))] +// [Name("OverriddenPropertyErrorTagProvider")] +// [Order(After = "Default Declaration")] +// internal class OverriddenPropertyErrorTagProvider : ICssItemChecker +// { +// public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) +// { +// Declaration dec = (Declaration)item; +// RuleBlock rule = item.Parent as RuleBlock; + +// if (!dec.IsValid || context == null || rule == null) +// return ItemCheckResult.Continue; + +// List list = new List(); + +// foreach (Declaration declaration in rule.Declarations.Where(d => d.PropertyName != null)) +// { +// if (declaration == dec) // Don't look beyond current declaration in the RuleBlock +// break; + +// ParseItem prop = declaration.PropertyName; +// if (prop == null || prop.Text == "border-radius" || dec.PropertyName.Text == "background" || dec.Values.Any(v => v.Text.StartsWith("-"))) +// continue; + +// if (prop.Length > dec.PropertyName.Length && prop.Text.StartsWith(dec.PropertyName.Text)) +// { +// list.Add(prop.Text); +// } +// } + +// if (list.Count > 0) +// { +// string message = "Best practice: '{0}' is overriding previously declared properties in the same rule block ({1})"; +// string error = string.Format(message, dec.PropertyName.Text, string.Join(", ", list.ToArray())); +// context.AddError(new SimpleErrorTag(dec.PropertyName, error)); +// } + +// return ItemCheckResult.Continue; +// } + +// public IEnumerable ItemTypes +// { +// get { return new[] { typeof(Declaration) }; } +// } +// } +//} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/ShorthandErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/ShorthandErrorTagProvider.cs new file mode 100644 index 000000000..c1fa565f2 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/ShorthandErrorTagProvider.cs @@ -0,0 +1,60 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("ShorthandErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class ShorthandErrorTagProvider : ICssItemChecker + { + private static Dictionary _cache = new Dictionary() + { + {"margin", new [] { "margin-top", "margin-right", "margin-bottom", "margin-left" }}, + {"padding", new [] { "padding-top", "padding-right", "padding-bottom", "padding-left" }}, + {"border", new [] { "border-width", "border-style", "border-color" }}, + {"border-color", new [] { "border-left-color", "border-top-color", "border-right-color", "border-bottom-color" }}, + {"border-style", new [] { "border-left-style", "border-top-style", "border-right-style", "border-bottom-style" }}, + {"border-radius", new [] { "border-top-left-radius", "border-top-right-radius", "border-bottom-left-radius", "border-bottom-right-radius" }}, + {"outline", new [] { "outline-width", "outline-style", "outline-color" }}, + {"list-style", new [] { "list-style-type", "list-style-position", "list-style-image" }}, + {"text-decoration", new [] { "text-decoration-color", "text-decoration-style", "text-decoration-line" }}, + }; + + + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + RuleBlock rule = (RuleBlock)item; + + if (!rule.IsValid || context == null) + return ItemCheckResult.Continue; + + IEnumerable properties = from d in rule.Declarations + where d.PropertyName != null && d.Values.Count < 2 + select d.PropertyName.Text; + + + foreach (string shorthand in _cache.Keys) + { + if (_cache[shorthand].All(p => properties.Contains(p))) + { + Declaration dec = rule.Declarations.First(p => p.PropertyName != null && _cache[shorthand].Contains(p.PropertyName.Text)); + string message = string.Format(Resources.PerformanceUseShorthand, string.Join(", ", _cache[shorthand]), shorthand); + + context.AddError(new SimpleErrorTag(dec, message)); + } + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(RuleBlock) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/StarSelectorErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/StarSelectorErrorTagProvider.cs new file mode 100644 index 000000000..abbe1ba90 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/StarSelectorErrorTagProvider.cs @@ -0,0 +1,44 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("StarSelectorErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class StarSelectorErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + SimpleSelector sel = (SimpleSelector)item; + + if (!WESettings.GetBoolean(WESettings.Keys.ValidateStarSelector) || !sel.IsValid || context == null) + return ItemCheckResult.Continue; + + if (sel.Text == "*") + { + //string afterStar = sel.Text.Length > index + 1 ? sel.Text.Substring(index + 1) : null; + //if (afterStar == null || !afterStar.Trim().StartsWith("html", StringComparison.OrdinalIgnoreCase)) + //{ + string errorMessage = string.Format(CultureInfo.InvariantCulture, Resources.PerformanceDontUseStarSelector); + + SimpleErrorTag tag = new SimpleErrorTag(sel, errorMessage); + + context.AddError(tag); + //} + } + + return ItemCheckResult.Continue; + } + + + public IEnumerable ItemTypes + { + get { return new[] { typeof(SimpleSelector) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/UnknownTagErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/UnknownTagErrorTagProvider.cs new file mode 100644 index 000000000..dd43890c3 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/UnknownTagErrorTagProvider.cs @@ -0,0 +1,163 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("UnknownTagErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class UnknownTagErrorTagProvider : ICssItemChecker + { + private HashSet _cache = new HashSet(){ + "*", + "a", + "abbr", + "acronym", + "address", + "applet", + "area", + "article", + "aside", + "audio", + "b", + "base", + "basefont", + "bdi", + "bdo", + "big", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "center", + "cite", + "code", + "col", + "colgroup", + "command", + "datalist", + "dd", + "del", + "details", + "dfn", + "dir", + "div", + "dl", + "dt", + "em", + "embed", + "fieldset", + "figcaption", + "figure", + "font", + "footer", + "form", + "frame", + "frameset", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hgroup", + "hr", + "html", + "i", + "iframe", + "img", + "input", + "ins", + "keygen", + "kbd", + "label", + "legend", + "li", + "link", + "map", + "mark", + "menu", + "meta", + "meter", + "nav", + "noframes", + "noscript", + "object", + "ol", + "optgroup", + "option", + "output", + "p", + "param", + "pre", + "progress", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "script", + "section", + "select", + "small", + "source", + "span", + "strike", + "strong", + "style", + "sub", + "summary", + "sup", + "svg", + "table", + "tbody", + "td", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "tt", + "u", + "ul", + "var", + "video", + "wbr" + }; + + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + ItemName itemName = (ItemName)item; + + if (!itemName.IsValid || context == null || (item.PreviousSibling != null && item.PreviousSibling.Text == "[")) + return ItemCheckResult.Continue; + + if (!_cache.Contains(itemName.Text.ToLowerInvariant())) + { + string error = "Validation: \"" + itemName.Text + "\" isn't a valid HTML tag."; + ICssError tag = new SimpleErrorTag(itemName, error); + context.AddError(tag); + + return ItemCheckResult.CancelCurrentItem; + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(ItemName) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/VendorOrderErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/VendorOrderErrorTagProvider.cs new file mode 100644 index 000000000..94cdcae82 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/VendorOrderErrorTagProvider.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Utilities; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.SyntaxCheck; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("VendorOrderErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class VendorOrderErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + Declaration dec = (Declaration)item; + + if (context == null || !dec.IsValid) + return ItemCheckResult.Continue; + + RuleBlock rule = dec.FindType(); + if (!rule.IsValid) + return ItemCheckResult.Continue; + + if (!dec.IsVendorSpecific()) + { + ICssSchemaInstance schema = CssEditorChecker.GetSchemaForItem(context, item); + bool hasVendor = VendorHelpers.HasVendorLaterInRule(dec, schema); + if (hasVendor) + { + context.AddError(new SimpleErrorTag(dec.PropertyName, Resources.BestPracticeStandardPropertyOrder)); + return ItemCheckResult.CancelCurrentItem; + } + } + else + { + ICssCompletionListEntry entry = VendorHelpers.GetMatchingStandardEntry(dec, context); + if (entry != null && !rule.Declarations.Any(d => d.PropertyName != null && d.PropertyName.Text == entry.DisplayText)) + { + if (entry.DisplayText != "filter" && entry.DisplayText != "zoom" && entry.DisplayText != "behavior") + { + string message = string.Format(CultureInfo.InvariantCulture, Resources.BestPracticeAddMissingStandardProperty, entry.DisplayText); + context.AddError(new SimpleErrorTag(dec.PropertyName, message)); + return ItemCheckResult.CancelCurrentItem; + } + } + } + + return ItemCheckResult.Continue; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(Declaration) }; } + } + } +} diff --git a/EditorExtensions/ErrorTags/Providers/W3cOnlyErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/W3cOnlyErrorTagProvider.cs new file mode 100644 index 000000000..11d3c7c10 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/W3cOnlyErrorTagProvider.cs @@ -0,0 +1,109 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("W3cOnlyErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class W3cOnlyErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + if (!WESettings.GetBoolean(WESettings.Keys.OnlyW3cAllowed)) + return ItemCheckResult.Continue; + + if (item is Declaration) + { + HandleDeclaration(item, context); + } + else if (item is AtDirective) + { + HandleDirective(item, context); + } + + else if (item is PseudoClassFunctionSelector || item is PseudoClassSelector || item is PseudoElementFunctionSelector || item is PseudoElementSelector) + { + HandlePseudo(item, context); + } + + return ItemCheckResult.Continue; + } + + private static void HandleDeclaration(ParseItem item, ICssCheckerContext context) + { + Declaration dec = (Declaration)item; + + if (dec == null || dec.PropertyName == null) + return; + + if (dec.IsVendorSpecific()) + { + string message = string.Format("Validation (W3C): \"{0}\" is not a valid W3C property", dec.PropertyName.Text); + context.AddError(new SimpleErrorTag(dec.PropertyName, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + + foreach (var value in dec.Values) + { + string text = value.Text; + if (!(value is NumericalValue) && text.StartsWith("-", StringComparison.Ordinal)) + { + int index = text.IndexOf('('); + + if (index > -1) + { + text = text.Substring(0, index); + } + + string message = string.Format("Validation (W3C): \"{0}\" is not a valid W3C value", text); + context.AddError(new SimpleErrorTag(value, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + } + } + + private static void HandleDirective(ParseItem item, ICssCheckerContext context) + { + AtDirective dir = (AtDirective)item; + + if (dir == null || dir.Keyword == null) + return; + + if (dir.IsVendorSpecific()) + { + string message = string.Format("Validation (W3C): \"@{0}\" is not a valid W3C @-directive", dir.Keyword.Text); + context.AddError(new SimpleErrorTag(dir.Keyword, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + } + + private static void HandlePseudo(ParseItem item, ICssCheckerContext context) + { + string text = item.Text.TrimStart(':'); + + if (text.StartsWith("-", StringComparison.Ordinal)) + { + string message = string.Format("Validation (W3C): \"{0}\" is not a valid W3C pseudo class/element", item.Text); + context.AddError(new SimpleErrorTag(item, message, CssErrorFlags.TaskListWarning | CssErrorFlags.UnderlineRed)); + } + } + + public IEnumerable ItemTypes + { + get + { + return new[] + { + typeof(Declaration), + typeof(AtDirective), + typeof(PseudoClassFunctionSelector), + typeof(PseudoClassSelector), + typeof(PseudoElementFunctionSelector), + typeof(PseudoElementSelector), + }; + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/Providers/ZeroUnitErrorTagProvider.cs b/EditorExtensions/ErrorTags/Providers/ZeroUnitErrorTagProvider.cs new file mode 100644 index 000000000..89733d6a3 --- /dev/null +++ b/EditorExtensions/ErrorTags/Providers/ZeroUnitErrorTagProvider.cs @@ -0,0 +1,46 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ICssItemChecker))] + [Name("ZeroUnitErrorTagProvider")] + [Order(After = "Default Declaration")] + internal class ZeroUnitErrorTagProvider : ICssItemChecker + { + public ItemCheckResult CheckItem(ParseItem item, ICssCheckerContext context) + { + if (!WESettings.GetBoolean(WESettings.Keys.ValidateZeroUnit)) + return ItemCheckResult.Continue; + + NumericalValue number = (NumericalValue)item; + UnitValue unit = number as UnitValue; + + if (unit == null || context == null) + return ItemCheckResult.Continue; + + if (number.Number.Text == "0" && unit.UnitType != UnitType.Unknown && unit.UnitType != UnitType.Time) + { + string message = string.Format(Resources.BestPracticeZeroUnit, unit.UnitToken.Text); + context.AddError(new SimpleErrorTag(number, message)); + } + + return ItemCheckResult.Continue; + } + + private static UnitType GetUnitType(ParseItem valueItem) + { + UnitValue unitValue = valueItem as UnitValue; + + return (unitValue != null) ? unitValue.UnitType : UnitType.Unknown; + } + + public IEnumerable ItemTypes + { + get { return new[] { typeof(NumericalValue) }; } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/ErrorTags/SelectorErrorTag.cs b/EditorExtensions/ErrorTags/SelectorErrorTag.cs new file mode 100644 index 000000000..b8a954294 --- /dev/null +++ b/EditorExtensions/ErrorTags/SelectorErrorTag.cs @@ -0,0 +1,62 @@ +using Microsoft.CSS.Core; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class SelectorErrorTag : ICssError + { + private SortedRangeList _range; + private string _errorMessage; + + public SelectorErrorTag(SortedRangeList range, string errorMessage) + { + _range = range; + _errorMessage = errorMessage; + Flags = GetLocation(); + } + + private static CssErrorFlags GetLocation() + { + switch ((WESettings.Keys.ErrorLocation)WESettings.GetInt(WESettings.Keys.CssErrorLocation)) + { + case WESettings.Keys.ErrorLocation.Warnings: + return CssErrorFlags.UnderlinePurple | CssErrorFlags.TaskListWarning; + + default: + return CssErrorFlags.UnderlinePurple | CssErrorFlags.TaskListMessage; + } + } + + public bool IsExposedToUser + { + get { return true; } + } + + public ParseItem Item + { + get { return _range.First(); } + } + + public string Text + { + get { return _errorMessage; } + } + + public int AfterEnd + { + get { return _range.Last().AfterEnd; } + } + + public int Length + { + get { return AfterEnd - Start; } + } + + public int Start + { + get { return _range.First().Start; } + } + + public CssErrorFlags Flags {get; set; } + } +} diff --git a/EditorExtensions/ErrorTags/SimpleErrorTag.cs b/EditorExtensions/ErrorTags/SimpleErrorTag.cs new file mode 100644 index 000000000..15c82901b --- /dev/null +++ b/EditorExtensions/ErrorTags/SimpleErrorTag.cs @@ -0,0 +1,79 @@ +using Microsoft.CSS.Core; + +namespace MadsKristensen.EditorExtensions +{ + internal class SimpleErrorTag : ICssError + { + private ParseItem _item; + private string _errorMessage; + private int _length; + + public SimpleErrorTag(ParseItem item, string errorMessage, CssErrorFlags flags = CssErrorFlags.TaskListMessage | CssErrorFlags.UnderlinePurple) + { + _item = item; + _errorMessage = errorMessage; + _length = AfterEnd - Start; + Flags = flags; + } + + public SimpleErrorTag(ParseItem item, string errorMessage) + { + _item = item; + _errorMessage = errorMessage; + _length = AfterEnd - Start; + Flags = GetLocation(); + } + + public SimpleErrorTag(ParseItem item, string errorMessage, int length) + { + _item = item; + _errorMessage = errorMessage; + _length = length; + Flags = GetLocation(); + } + + private static CssErrorFlags GetLocation() + { + switch ((WESettings.Keys.ErrorLocation)WESettings.GetInt(WESettings.Keys.CssErrorLocation)) + { + case WESettings.Keys.ErrorLocation.Warnings: + return CssErrorFlags.UnderlinePurple | CssErrorFlags.TaskListWarning; + + default: + return CssErrorFlags.UnderlinePurple | CssErrorFlags.TaskListMessage; + } + } + + public bool IsExposedToUser + { + get { return true; } + } + + public ParseItem Item + { + get { return _item; } + } + + public string Text + { + get { return _errorMessage; } + } + + public int AfterEnd + { + get { return _item.AfterEnd; } + } + + public int Length + { + get { return _length; } + } + + public int Start + { + get { return _item.Start; } + } + + public CssErrorFlags Flags {get; set; } + } +} diff --git a/EditorExtensions/ExtensionMethods/AtDirectiveExtensions.cs b/EditorExtensions/ExtensionMethods/AtDirectiveExtensions.cs new file mode 100644 index 000000000..7b93e9ac9 --- /dev/null +++ b/EditorExtensions/ExtensionMethods/AtDirectiveExtensions.cs @@ -0,0 +1,64 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal static class AtDirectiveExtensions + { + public static bool IsVendorSpecific(this AtDirective directive) + { + return directive.Keyword.Text[0] == '-'; + } + + + public static bool TryGetStandardPropertyName(this AtDirective directive, out string standardName, ICssSchemaInstance schema) + { + standardName = null; + + string propText = directive.Keyword.Text; + string prefix = VendorHelpers.GetPrefixes(schema).SingleOrDefault(p => propText.IndexOf(p, StringComparison.Ordinal) == 0); + if (prefix != null) + { + standardName = propText.Substring(prefix.Length); + return true; + } + + return false; + } + + public static IEnumerable GetMissingVendorSpecifics(this AtDirective directive, ICssSchemaInstance schema) + { + IEnumerable possible = GetPossibleVendorSpecifics(directive, schema); + + var visitorRules = new CssItemCollector(); + directive.Parent.Accept(visitorRules); + + foreach (string item in possible) + { + if (!visitorRules.Items.Any(d => d.Keyword != null && "@" + d.Keyword.Text == item)) + yield return item; + //if (!rule.Declarations.Any(d => d.PropertyName != null && d.PropertyName.Text == item)) + // yield return item; + } + } + + public static IEnumerable GetPossibleVendorSpecifics(this AtDirective directive, ICssSchemaInstance schema) + { + string text = directive.Keyword.Text; + + foreach (string prefix in VendorHelpers.GetPrefixes(schema).Where(p => p != "-o-")) // Remove -o- since the parser doesn't recognize -o-keyframes + { + ICssCompletionListEntry entry = schema.GetAtDirective("@" + prefix + text); + if (entry != null) + { + yield return entry.DisplayText; + } + } + } + } +} diff --git a/EditorExtensions/ExtensionMethods/ColorModelExtensions.cs b/EditorExtensions/ExtensionMethods/ColorModelExtensions.cs new file mode 100644 index 000000000..5908df2f1 --- /dev/null +++ b/EditorExtensions/ExtensionMethods/ColorModelExtensions.cs @@ -0,0 +1,56 @@ +using Microsoft.Web.Editor; +using System.Windows.Media; + +namespace MadsKristensen.EditorExtensions +{ + internal static class ColorModelExtensions + { + private const float _factor = 0.025F; + + public static ColorModel Brighten(this ColorModel color) + { + if ((color.HslLightness + _factor) < 1) + { + color.HslLightness += _factor; + } + + return color; + } + + public static ColorModel Darken(this ColorModel color) + { + if ((color.HslLightness - _factor) > 0) + { + color.HslLightness -= _factor; + } + + return color; + } + + public static ColorModel Invert(this ColorModel color) + { + ColorModel model = new ColorModel() + { + Red = ~(byte)color.Red, + Green = ~(byte)color.Green, + Blue = ~(byte)color.Blue + }; + + return model; + + } + + public static SolidColorBrush ToBrush(this ColorModel color) + { + Color c = Color.FromRgb( + (byte)color.Red, + (byte)color.Green, + (byte)color.Blue + ); + + SolidColorBrush brush = new SolidColorBrush(c); + brush.Freeze(); + return brush; + } + } +} diff --git a/EditorExtensions/ExtensionMethods/DeclarationExtensions.cs b/EditorExtensions/ExtensionMethods/DeclarationExtensions.cs new file mode 100644 index 000000000..a45d5cf4c --- /dev/null +++ b/EditorExtensions/ExtensionMethods/DeclarationExtensions.cs @@ -0,0 +1,62 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal static class DeclarationExtensions + { + public static bool IsVendorSpecific(this Declaration declaration) + { + return declaration.PropertyName.Length > 0 ? declaration.PropertyName.Text[0] == '-' : false; + } + + public static bool TryGetStandardPropertyName(this Declaration declaration, out string standardName, ICssSchemaInstance schema) + { + standardName = null; + + if (declaration.IsVendorSpecific()) + { + string propText = declaration.PropertyName.Text; + string prefix = VendorHelpers.GetPrefixes(schema).SingleOrDefault(p => propText.IndexOf(p, StringComparison.Ordinal) == 0); + if (prefix != null) + { + standardName = propText.Substring(prefix.Length); + return true; + } + } + + return false; + } + + public static IEnumerable GetMissingVendorSpecifics(this Declaration declaration, ICssSchemaInstance schema) + { + RuleBlock rule = declaration.FindType(); + IEnumerable possible = GetPossibleVendorSpecifics(declaration, schema); + + foreach (string item in possible) + { + if (!rule.Declarations.Any(d => d.PropertyName != null && d.PropertyName.Text == item)) + yield return item; + } + } + + public static IEnumerable GetPossibleVendorSpecifics(this Declaration declaration, ICssSchemaInstance schema) + { + string text = declaration.PropertyName.Text; + + foreach (string prefix in VendorHelpers.GetPrefixes(schema)) + { + ICssCompletionListEntry entry = schema.GetProperty(prefix + text); + if (entry != null) + { + yield return entry.DisplayText; + } + } + } + } +} diff --git a/EditorExtensions/ExtensionMethods/IVsExtensions.cs b/EditorExtensions/ExtensionMethods/IVsExtensions.cs new file mode 100644 index 000000000..a19ca8b02 --- /dev/null +++ b/EditorExtensions/ExtensionMethods/IVsExtensions.cs @@ -0,0 +1,38 @@ +using EnvDTE; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace MadsKristensen.EditorExtensions +{ + public static class IVsExtensions + { + public static void AddHierarchyItem(this ErrorTask task) + { + IVsHierarchy HierarchyItem; + IVsSolution solution = EditorExtensionsPackage.GetGlobalService(typeof(SVsSolution)); + Project project = ProjectHelpers.GetActiveProject(); + + if (solution != null && project != null) + { + int flag = solution.GetProjectOfUniqueName(project.FullName, out HierarchyItem); + + if (0 == flag) + { + task.HierarchyItem = HierarchyItem; + } + } + } + + public static bool IsLink(this ProjectItem item) + { + try + { + return (bool)item.Properties.Item("IsLink").Value; + } + catch + { + return false; + } + } + } +} diff --git a/EditorExtensions/ExtensionMethods/PseudoExtensions.cs b/EditorExtensions/ExtensionMethods/PseudoExtensions.cs new file mode 100644 index 000000000..447b69966 --- /dev/null +++ b/EditorExtensions/ExtensionMethods/PseudoExtensions.cs @@ -0,0 +1,18 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; + +namespace MadsKristensen.EditorExtensions +{ + public static class PseudoExtensions + { + public static bool IsPseudoElement(this ParseItem item) + { + if (item.Text.StartsWith("::")) + return true; + + var schema = CssSchemaManager.SchemaManager.GetSchemaRoot(null); + return schema.GetPseudo(":" + item.Text) != null; + } + } +} diff --git a/EditorExtensions/GlobalSuppressions.cs b/EditorExtensions/GlobalSuppressions.cs new file mode 100644 index 000000000..37d942cc4 --- /dev/null +++ b/EditorExtensions/GlobalSuppressions.cs @@ -0,0 +1 @@ +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] diff --git a/EditorExtensions/Guids.cs b/EditorExtensions/Guids.cs new file mode 100644 index 000000000..e1cdf3e43 --- /dev/null +++ b/EditorExtensions/Guids.cs @@ -0,0 +1,30 @@ +using System; + +namespace MadsKristensen.EditorExtensions +{ + static class GuidList + { + public const string guidEditorExtensionsPkgString = "5fb7364d-2e8c-44a4-95eb-2a382e30fec7"; + public const string guidEditorExtensionsCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e41"; + public const string guidCssCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e50"; + public const string guidCssIntellisensCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e51"; + public const string guidWcfToolsCmdSetString = "1446a66d-7e3e-40ce-808e-89a7202d050d"; + public const string guidDiffCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e59"; + public const string guidMinifyCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e61"; + public const string guidBundleCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e63"; + public const string guidExtractCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e64"; + public const string guidBuildCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e65"; + public const string guidFormattingCmdSetString = "e396b698-e00e-444b-9f5f-3dcb1ef74e66"; + + public static readonly Guid guidEditorExtensionsCmdSet = new Guid(guidEditorExtensionsCmdSetString); + public static readonly Guid guidCssCmdSet = new Guid(guidCssCmdSetString); + public static readonly Guid guidCssIntellisenseCmdSet = new Guid(guidCssIntellisensCmdSetString); + public static readonly Guid guidWcfToolsCmdSet = new Guid(guidWcfToolsCmdSetString); + public static readonly Guid guidDiffCmdSet = new Guid(guidDiffCmdSetString); + public static readonly Guid guidMinifyCmdSet = new Guid(guidMinifyCmdSetString); + public static readonly Guid guidBundleCmdSet = new Guid(guidBundleCmdSetString); + public static readonly Guid guidExtractCmdSet = new Guid(guidExtractCmdSetString); + public static readonly Guid guidBuildCmdSet = new Guid(guidBuildCmdSetString); + public static readonly Guid guidFormattingCmdSet = new Guid(guidFormattingCmdSetString); + }; +} \ No newline at end of file diff --git a/EditorExtensions/HTML/Base64ChromeAction.cs b/EditorExtensions/HTML/Base64ChromeAction.cs new file mode 100644 index 000000000..4a55bae9d --- /dev/null +++ b/EditorExtensions/HTML/Base64ChromeAction.cs @@ -0,0 +1,71 @@ +//using System; +//using System.IO; +//using System.Text; +//using System.Xml; +//using Microsoft.VisualStudio.Text; +//using Microsoft.VisualStudio.Text.Editor; +//using Microsoft.VisualStudio.Web.HTML.Chrome; + +//namespace MadsKristensen.EditorExtensions +//{ +// [ChromeAction, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] +// internal class Base64ChromeAction : IChromeAction +// { +// string IChromeAction.Name { get { return "Convert to dataURI"; } } + +// void IChromeAction.Execute(IWpfTextView view, string tagName, int tagPosition) +// { +// string line = view.TextBuffer.CurrentSnapshot.GetText(tagPosition, view.TextBuffer.CurrentSnapshot.Length - tagPosition); +// int length = line.IndexOf('>') + 1; + +// if (length > 0) +// { +// string element = line.Substring(0, length); +// XmlNode img = ConvertToXml(element); + +// if (img != null && img.Attributes["src"] != null) +// { +// XmlAttribute src = img.Attributes["src"]; +// string dataUri = ConvertToDataUri(src); + +// if (!string.IsNullOrEmpty(dataUri)) +// { +// src.InnerText = dataUri; +// view.TextBuffer.Replace(new Span(tagPosition, length), img.OuterXml); +// } +// } +// } +// } + +// private static string ConvertToDataUri(XmlAttribute src) +// { +// string fileName = ProjectHelpers.ToAbsoluteFilePath(src.InnerText); +// if (!string.IsNullOrEmpty(fileName) && File.Exists(fileName)) +// { +// return FileHelpers.ConvertToBase64(fileName); +// } + +// return null; +// } + +// private static XmlNode ConvertToXml(string element) +// { +// StringBuilder sb = new StringBuilder(); + +// using (XmlWriter writer = XmlWriter.Create(sb)) +// { +// writer.WriteRaw(element); +// } + +// XmlDocument doc = new XmlDocument(); +// doc.LoadXml(sb.ToString()); + +// return doc.SelectSingleNode("//img"); +// } + +// bool IChromeAction.IsAvailable(IWpfTextView view, string tagName, int tagPosition) +// { +// return tagName.Equals("img", StringComparison.OrdinalIgnoreCase); +// } +// } +//} \ No newline at end of file diff --git a/EditorExtensions/HTML/MathMlSchemaFileInfoProvider.cs b/EditorExtensions/HTML/MathMlSchemaFileInfoProvider.cs new file mode 100644 index 000000000..4c40f3325 --- /dev/null +++ b/EditorExtensions/HTML/MathMlSchemaFileInfoProvider.cs @@ -0,0 +1,33 @@ +//using System.Collections.Generic; +//using System.ComponentModel.Composition; +//using System.IO; +//using Microsoft.VisualStudio.Utilities; +//using Microsoft.VisualStudio.Web.HTML.Schemas; + +//namespace MadsKristensen.EditorExtensions +//{ +// [Export(typeof(IHtmlSchemaFileInfoProvider))] +// [Name("MathML")] +// [Order(Before = "Default")] +// internal class MathMlSchemaFileInfoProvider : IHtmlSchemaFileInfoProvider +// { +// private const string _file = @"C:\Users\madsk\Documents\mathml.xsd"; + +// public IEnumerable GetSchemas(string defaultSchemaPath, string defaultRegistryPath) +// { +// if (!File.Exists(_file)) +// yield break; + +// SchemaFileInfo info = new SchemaFileInfo() +// { +// File = _file, +// FriendlyName = "MathML", +// Uri = "http://www.w3.org/1998/Math/MathML", +// IsMobile = true, +// IsNonBrowsable = true, +// }; + +// yield return info; +// } +// } +//} diff --git a/EditorExtensions/Helpers/CssItemCollector.cs b/EditorExtensions/Helpers/CssItemCollector.cs new file mode 100644 index 000000000..4760a7094 --- /dev/null +++ b/EditorExtensions/Helpers/CssItemCollector.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Microsoft.CSS.Core; + +namespace MadsKristensen.EditorExtensions +{ + /// + /// Creates a list of CSS ParseItems of a certain type + /// (when passed in as the visitor to any item's Accept() function) + /// + internal class CssItemCollector : ICssSimpleTreeVisitor where T : ParseItem + { + public IList Items { get; private set; } + private bool _includeChildren; + + public CssItemCollector() : this(false) { } + + public CssItemCollector(bool includeChildren) + { + _includeChildren = includeChildren; + Items = new List(); + } + + public VisitItemResult Visit(ParseItem parseItem) + { + var item = parseItem as T; + + if (item != null) + { + Items.Add(item); + return (_includeChildren) ? VisitItemResult.Continue : VisitItemResult.SkipChildren; + } + + return VisitItemResult.Continue; + } + } +} diff --git a/EditorExtensions/Helpers/FileHelpers.cs b/EditorExtensions/Helpers/FileHelpers.cs new file mode 100644 index 000000000..9c44d7164 --- /dev/null +++ b/EditorExtensions/Helpers/FileHelpers.cs @@ -0,0 +1,92 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + public static class FileHelpers + { + public static string ConvertToBase64(string fileName) + { + string format = "data:{0};base64,{1}"; + byte[] buffer = File.ReadAllBytes(fileName); + string extension = Path.GetExtension(fileName).Substring(1); + string contentType = GetMimeType(extension); + + return string.Format(CultureInfo.InvariantCulture, format, contentType, Convert.ToBase64String(buffer)); + } + + private static string GetMimeType(string extension) + { + switch (extension) + { + case "png": + case "jpg": + case "jpeg": + case "gif": + return "image/" + extension; + + case "woff": + return "font/x-woff"; + + case "otf": + return "font/otf"; + + case "eot": + return "application/vnd.ms-fontobject"; + + case "ttf": + return "application/octet-stream"; + + default: + return "text/plain"; + } + } + + public static string RelativePath(string absPath, string relTo) + { + string[] absDirs = absPath.Split('\\'); + string[] relDirs = relTo.Split('\\'); + + // Get the shortest of the two paths + int len = absDirs.Length < relDirs.Length ? absDirs.Length : + relDirs.Length; + + // Use to determine where in the loop we exited + int lastCommonRoot = -1; + int index; + + // Find common root + for (index = 0; index < len; index++) + { + if (absDirs[index] == relDirs[index]) lastCommonRoot = index; + else break; + } + + // If we didn't find a common prefix then throw + if (lastCommonRoot == -1) + { + return relTo; + } + + // Build up the relative path + StringBuilder relativePath = new StringBuilder(); + + // Add on the .. + for (index = lastCommonRoot + 2; index < absDirs.Length; index++) + { + if (absDirs[index].Length > 0) relativePath.Append("..\\"); + } + + // Add on the folders + for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++) + { + relativePath.Append(relDirs[index] + "\\"); + } + relativePath.Append(relDirs[relDirs.Length - 1]); + + return relativePath.ToString().Replace("\\", "/"); + } + } +} diff --git a/EditorExtensions/Helpers/OptionHelpers.cs b/EditorExtensions/Helpers/OptionHelpers.cs new file mode 100644 index 000000000..d55c390fa --- /dev/null +++ b/EditorExtensions/Helpers/OptionHelpers.cs @@ -0,0 +1,87 @@ +using System; +using System.Windows.Media; +using VS = Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.Web.Editor; + +namespace MadsKristensen.EditorExtensions +{ + internal static class OptionHelpers + { + private static int _fontSize; + private static ColorModel _backgroundColor; + private static object _syncRoot = new object(); + + // TODO: Compensate for the current line highlighting + public static ColorModel BackgroundColor + { + get + { + if (_backgroundColor == null) + { + lock (_syncRoot) + { + if (_backgroundColor == null) + { + GetSize(); + } + } + } + + return _backgroundColor; + } + } + + public static int FontSize + { + get + { + if (_fontSize == 0) + { + lock (_syncRoot) + { + if (_fontSize == 0) + { + GetSize(); + } + } + } + + return _fontSize; + } + } + + private static void GetSize() + { + try + { + IVsFontAndColorStorage storage = (IVsFontAndColorStorage)EditorExtensionsPackage.GetGlobalService(typeof(IVsFontAndColorStorage)); + var guid = new Guid("A27B4E24-A735-4d1d-B8E7-9716E1E3D8E0"); + if (storage != null && storage.OpenCategory(ref guid, (uint)(__FCSTORAGEFLAGS.FCSF_READONLY | __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS)) == VS.VSConstants.S_OK) + { + LOGFONTW[] Fnt = new LOGFONTW[] { new LOGFONTW() }; + FontInfo[] Info = new FontInfo[] { new FontInfo() }; + storage.GetFont(Fnt, Info); + _fontSize = (int)Info[0].wPointSize; + } + + if (storage != null && storage.OpenCategory(ref guid, (uint)(__FCSTORAGEFLAGS.FCSF_NOAUTOCOLORS | __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS)) == VS.VSConstants.S_OK) + { + var info = new ColorableItemInfo[1]; + storage.GetItem("Plain Text", info); + _backgroundColor = ConvertFromWin32Color((int)info[0].crBackground); + } + + } + catch { } + } + + public static ColorModel ConvertFromWin32Color(int color) + { + int r = color & 0x000000FF; + int g = (color & 0x0000FF00) >> 8; + int b = (color & 0x00FF0000) >> 16; + return new ColorModel() { Red = r, Green = g, Blue = b }; + } + } +} diff --git a/EditorExtensions/Helpers/ProjectHelpers.cs b/EditorExtensions/Helpers/ProjectHelpers.cs new file mode 100644 index 000000000..6fd3b4042 --- /dev/null +++ b/EditorExtensions/Helpers/ProjectHelpers.cs @@ -0,0 +1,229 @@ +using EnvDTE; +using Microsoft.VisualStudio.ComponentModelHost; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + internal static class ProjectHelpers + { + public static string GetRootFolder() + { + try + { + EnvDTE80.DTE2 dte = EditorExtensionsPackage.DTE; + Project activeProject = null; + + if (dte.Solution.Projects.Count == 1 && !string.IsNullOrEmpty(dte.Solution.Projects.Item(1).FullName)) + { + return dte.Solution.Projects.Item(1).Properties.Item("FullPath").Value.ToString(); + } + + Array activeSolutionProjects = dte.ActiveSolutionProjects as Array; + + if (activeSolutionProjects != null && activeSolutionProjects.Length > 0) + { + activeProject = activeSolutionProjects.GetValue(0) as Project; + } + + return activeProject.Properties.Item("FullPath").Value.ToString(); + } + catch (Exception ex) + { + Logger.Log(ex); + return string.Empty; + } + } + + internal static bool AddFileToActiveProject(string fileName, string itemType = null) + { + Project project = GetActiveProject(); + + if (project != null) + { + string projectFilePath = project.Properties.Item("FullPath").Value.ToString(); + string projectDirPath = Path.GetDirectoryName(projectFilePath); + + if (fileName.StartsWith(projectDirPath, StringComparison.OrdinalIgnoreCase)) + { + ProjectItem item = project.ProjectItems.AddFromFile(fileName); + + if (itemType != null && item != null && !project.FullName.Contains("://")) + { + try + { + item.Properties.Item("ItemType").Value = itemType; + } + catch { } + } + } + } + + return false; + } + + public static Project GetActiveProject() + { + Project activeProject = null; + + try + { + Array activeSolutionProjects = EditorExtensionsPackage.DTE.ActiveSolutionProjects as Array; + + if (activeSolutionProjects != null && activeSolutionProjects.Length > 0) + { + activeProject = activeSolutionProjects.GetValue(0) as Project; + } + } + catch + { + Logger.Log("Error getting the active project"); + } + + return activeProject; + } + + public static string ToAbsoluteFilePath(string relativeUrl, string rootFolder = null) + { + string imageUrl = relativeUrl.Trim(new[] { '\'', '"' }); + string filePath = string.Empty; + + if (imageUrl.StartsWith("/", StringComparison.Ordinal)) + { + string root = rootFolder ?? ProjectHelpers.GetRootFolder(); + + if (root.Contains("://")) + { + filePath = root + imageUrl; + } + else if (!string.IsNullOrEmpty(root)) + { + if (!Directory.Exists(root)) + { + filePath = new FileInfo(root).Directory + imageUrl; + } + else + { + return root + imageUrl.Replace("/", "\\"); + } + } + } + else + { + FileInfo fi = new FileInfo(EditorExtensionsPackage.DTE.ActiveDocument.FullName); + DirectoryInfo dir = fi.Directory; + + while (imageUrl.Contains("../")) + { + imageUrl = imageUrl.Remove(imageUrl.IndexOf("../", StringComparison.Ordinal), 3); + dir = dir.Parent; + } + + filePath = Path.Combine(dir.FullName, imageUrl.Replace("/", "\\")); + } + + return filePath; + } + + public static ITextBuffer GetCurentTextBuffer() + { + return GetCurentTextView().TextBuffer; + } + + public static IWpfTextView GetCurentTextView() + { + var componentModel = GetComponentModel(); + var editorAdapter = componentModel.GetService(); + var textManager = (IVsTextManager)ServiceProvider.GlobalProvider.GetService(typeof(SVsTextManager)); + + IVsTextView activeView = null; + textManager.GetActiveView(1, null, out activeView); + + return editorAdapter.GetWpfTextView(activeView); + } + + public static IComponentModel GetComponentModel() + { + return (IComponentModel)ServiceProvider.GlobalProvider.GetService(typeof(SComponentModel)); + } + + public static IEnumerable GetSelectedItemPaths() + { + var items = (Array)EditorExtensionsPackage.DTE.ToolWindows.SolutionExplorer.SelectedItems; + foreach (UIHierarchyItem selItem in items) + { + var item = selItem.Object as ProjectItem; + if (item != null) + { + yield return item.Properties.Item("FullPath").Value.ToString(); + } + } + } + + public static bool CheckOutFileFromSourceControl(string fileName) + { + try + { + var dte = EditorExtensionsPackage.DTE; + + if (File.Exists(fileName) && dte.Solution.FindProjectItem(fileName) != null) + { + if (dte.SourceControl.IsItemUnderSCC(fileName) && !dte.SourceControl.IsItemCheckedOut(fileName)) + { + dte.SourceControl.CheckOutItem(fileName); + } + + return true; + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + + return false; + } + + public static string GetSolutionFolderPath() + { + EnvDTE.Solution solution = EditorExtensionsPackage.DTE.Solution; + + if (solution == null || string.IsNullOrEmpty(solution.FullName)) + return null; + + return Path.GetDirectoryName(solution.FullName); + } + + public static string GetProjectFolder(string fileNameOrFolder) + { + if (string.IsNullOrEmpty(fileNameOrFolder)) + return GetRootFolder(); + + ProjectItem item = EditorExtensionsPackage.DTE.Solution.FindProjectItem(fileNameOrFolder); + + if (item == null || item.ContainingProject == null || string.IsNullOrEmpty(item.ContainingProject.FullName)) // Solution items + return null; + + return item.ContainingProject.Properties.Item("FullPath").Value.ToString(); + } + + public static IEnumerable GetSelectedItems() + { + var items = (Array)EditorExtensionsPackage.DTE.ToolWindows.SolutionExplorer.SelectedItems; + foreach (UIHierarchyItem selItem in items) + { + var item = selItem.Object as ProjectItem; + if (item != null) + { + yield return item; + } + } + } + } +} diff --git a/EditorExtensions/Helpers/VendorHelpers.cs b/EditorExtensions/Helpers/VendorHelpers.cs new file mode 100644 index 000000000..beb27b859 --- /dev/null +++ b/EditorExtensions/Helpers/VendorHelpers.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.SyntaxCheck; + +namespace MadsKristensen.EditorExtensions +{ + internal static class VendorHelpers + { + private static object _syncRoot = new object(); + private static Dictionary prefixes = new Dictionary(); + + public static string[] GetPrefixes(ICssSchemaInstance schema) + { + int version = schema.Version.GetHashCode(); + int browser = schema.Filter.Name.GetHashCode(); + int hash = version ^ browser; + + if (!prefixes.ContainsKey(hash)) + { + CssSchemaManager.SchemaManager.CurrentSchemaChanged += CurrentSchemaChanged; + var properties = schema.Properties; + List list = new List(); + + foreach (ICssCompletionListEntry property in properties) + { + string text = property.DisplayText; + if (text[0] == '-') + { + int end = text.IndexOf('-', 1); + if (end > -1) + { + string prefix = text.Substring(0, end + 1); + if (!list.Contains(prefix)) + { + list.Add(prefix); + } + } + } + } + + prefixes.Add(hash, list.ToArray()); + } + + return prefixes[hash]; + } + + private static void CurrentSchemaChanged(object sender, EventArgs e) + { + CssSchemaManager.SchemaManager.CurrentSchemaChanged -= CurrentSchemaChanged; + } + + public static bool HasVendorLaterInRule(Declaration declaration, ICssSchemaInstance schema) + { + Declaration next = declaration.NextSibling as Declaration; + + while (next != null) + { + if (next.IsValid && next.IsVendorSpecific()) + { + foreach (string prefix in GetPrefixes(schema)) + { + if (next.PropertyName.Text == prefix + declaration.PropertyName.Text) + return true; + } + } + + next = next.NextSibling as Declaration; + } + + return false; + } + + public static IEnumerable GetMatchingVendorEntriesInRule(Declaration declaration, RuleBlock rule, ICssSchemaInstance schema) + { + foreach (Declaration d in rule.Declarations.Where(d => d.IsValid && d.IsVendorSpecific())) + foreach (string prefix in GetPrefixes(schema)) + { + if (d.PropertyName.Text == prefix + declaration.PropertyName.Text) + { + yield return d; + break; + } + } + } + + public static ICssCompletionListEntry GetMatchingStandardEntry(Declaration declaration, ICssSchemaInstance rootSchema) + { + string standardName; + if (declaration.TryGetStandardPropertyName(out standardName, rootSchema)) + { + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, declaration); + return schema.GetProperty(standardName); + } + + return null; + } + + public static ICssCompletionListEntry GetMatchingStandardEntry(Declaration declaration, ICssCheckerContext context) + { + string standardName; + if (declaration.TryGetStandardPropertyName(out standardName, CssEditorChecker.GetSchemaForItem(context, declaration))) + { + ICssSchemaInstance schema = CssEditorChecker.GetSchemaForItem(context, declaration); + return schema.GetProperty(standardName); + } + + return null; + } + + public static ICssCompletionListEntry GetMatchingStandardEntry(AtDirective directive, ICssCheckerContext context) + { + string standardName; + if (directive.TryGetStandardPropertyName(out standardName, CssEditorChecker.GetSchemaForItem(context, directive))) + { + ICssSchemaInstance schema = CssEditorChecker.GetSchemaForItem(context, directive); + return schema.GetAtDirective("@" + standardName); + } + + return null; + } + + public static ICssCompletionListEntry GetMatchingStandardEntry(AtDirective directive, ICssSchemaInstance rootSchema) + { + string standardName; + if (directive.TryGetStandardPropertyName(out standardName, rootSchema)) + { + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(rootSchema, directive); + return schema.GetAtDirective("@" + standardName); + } + + return null; + } + } +} diff --git a/EditorExtensions/Key.snk b/EditorExtensions/Key.snk new file mode 100644 index 000000000..d9d7495d7 Binary files /dev/null and b/EditorExtensions/Key.snk differ diff --git a/EditorExtensions/License.txt b/EditorExtensions/License.txt new file mode 100644 index 000000000..865551175 --- /dev/null +++ b/EditorExtensions/License.txt @@ -0,0 +1,33 @@ +Microsoft Reciprocal License (Ms-RL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose. + +(B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file diff --git a/EditorExtensions/Logger.cs b/EditorExtensions/Logger.cs new file mode 100644 index 000000000..184fea39e --- /dev/null +++ b/EditorExtensions/Logger.cs @@ -0,0 +1,59 @@ +using Microsoft.VisualStudio.Shell.Interop; +using System; + +namespace MadsKristensen.EditorExtensions +{ + public class Logger + { + private static IVsOutputWindowPane pane; + private static object _syncRoot = new object(); + + public static void Log(string message) + { + if (string.IsNullOrEmpty(message)) + return; + + try + { + if (EnsurePane()) + { + pane.OutputString(DateTime.Now.ToString() + ": " + message + Environment.NewLine); + //pane.Activate(); + } + } + catch + { + // Do nothing + } + } + + public static void Log(Exception ex) + { + if (ex != null) + { + string message = ex.Message + Environment.NewLine + ex.StackTrace; + + if (!string.IsNullOrEmpty(ex.StackTrace)) + message += Environment.NewLine + ex.StackTrace; + + Log(message); + } + } + + private static bool EnsurePane() + { + if (pane == null) + { + lock (_syncRoot) + { + if (pane == null) + { + pane = EditorExtensionsPackage.Instance.GetOutputPane(new Guid("f1536ef8-92ec-443c-9ed7-fdadf150da44"), "Web Essentials"); + } + } + } + + return pane != null; + } + } +} diff --git a/EditorExtensions/Margin/CoffeeScriptCompiler.cs b/EditorExtensions/Margin/CoffeeScriptCompiler.cs new file mode 100644 index 000000000..6d693a25e --- /dev/null +++ b/EditorExtensions/Margin/CoffeeScriptCompiler.cs @@ -0,0 +1,39 @@ +using MadsKristensen.EditorExtensions; +using System.Runtime.InteropServices; +using System.Windows.Threading; + +[ComVisible(true)] +public class CoffeeScriptCompiler : ScriptRunnerBase +{ + public CoffeeScriptCompiler(Dispatcher dispatcher) + : base(dispatcher) + { } + + protected override string CreateHtml(string source, string state) + { + string clean = source + .Replace("\\", "\\\\") + .Replace("\n", "\\n") + .Replace("\r", "\\r") + .Replace("'", "\\'"); + + string bare = WESettings.GetBoolean(WESettings.Keys.WrapCoffeeScriptClosure) ? "false" : "true"; + + string compiler = "MadsKristensen.EditorExtensions.Resources.Scripts.CoffeeScript-1.4.js"; + if (WESettings.GetBoolean(WESettings.Keys.EnableIcedCoffeeScript)) + { + compiler = "MadsKristensen.EditorExtensions.Resources.Scripts.IcedCoffeeScript-1.3.3.js"; + } + + string script = ReadResourceFile(compiler) + + "try{" + + "var result = CoffeeScript.compile('" + clean + "', { bare: " + bare + ", runtime:'inline' });" + + "window.external.Execute(result, '" + state.Replace("\\", "\\\\") + "');" + + "}" + + "catch (err){" + + "window.external.Execute('ERROR:' + err, '" + state.Replace("\\", "\\\\") + "');" + + "}"; + + return ""; + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/CoffeeScriptMargin.cs b/EditorExtensions/Margin/CoffeeScriptMargin.cs new file mode 100644 index 000000000..21c43404c --- /dev/null +++ b/EditorExtensions/Margin/CoffeeScriptMargin.cs @@ -0,0 +1,178 @@ +using Microsoft.VisualStudio.Text; +using System; +using System.IO; +using System.Text; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + class CoffeeScriptMargin : MarginBase + { + public const string MarginName = "CoffeeScriptMargin"; + private CoffeeScriptCompiler _compiler; + private int _projectFileCount, _projectFileStep; + + public CoffeeScriptMargin(string contentType, string source, bool showMargin, ITextDocument document) + : base(source, MarginName, contentType, showMargin, document) + { + _compiler = new CoffeeScriptCompiler(Dispatcher); + _compiler.Completed += _compiler_Completed; //+= (s, e) => { OnCompilationDone(e.Result, e.State); }; + } + + public CoffeeScriptMargin() + { + // Used for project compilation + } + + public void CompileProject(EnvDTE.Project project) + { + if (string.IsNullOrEmpty(project.FullName)) + return; + + Logger.Log("Compiling CoffeeScript..."); + _projectFileCount = 0; + + try + { + string fullPath = project.Properties.Item("FullPath").Value.ToString(); + + if (project != null && !string.IsNullOrEmpty(fullPath)) + { + string dir = Path.GetDirectoryName(fullPath); + var files = Directory.GetFiles(dir, "*.coffee", SearchOption.AllDirectories); + + foreach (string file in files) + { + string jsFile = GetCompiledFileName(file, ".js", UseCompiledFolder); + + if (EditorExtensionsPackage.DTE.Solution.FindProjectItem(file) != null && + File.Exists(jsFile)) + { + _projectFileCount++; + + CoffeeScriptCompiler compiler = new CoffeeScriptCompiler(Dispatcher.CurrentDispatcher); + compiler.Completed += compiler_Completed; + compiler.Compile(File.ReadAllText(file), file); + } + } + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + + void compiler_Completed(object sender, CompilerEventArgs e) + { + _projectFileStep++; + string file = GetCompiledFileName(e.State, ".js", UseCompiledFolder); + + ProjectHelpers.CheckOutFileFromSourceControl(file); + + using (StreamWriter writer = new StreamWriter(file, false, new UTF8Encoding(true))) + { + writer.Write(e.Result); + } + + MinifyFile(e.State, e.Result); + + if (_projectFileStep == _projectFileCount) + Logger.Log("CoffeeScript compiled"); + } + + protected override void StartCompiler(string source) + { + string fileName = GetCompiledFileName(Document.FilePath, ".js", UseCompiledFolder);//Document.FilePath.Replace(".coffee", ".js"); + + if (_isFirstRun && File.Exists(fileName)) + { + OnCompilationDone(File.ReadAllText(fileName), Document.FilePath); + return; + } + + Logger.Log("CoffeeScript: Compiling " + Path.GetFileName(Document.FilePath)); + _compiler.Compile(source, Document.FilePath); + } + + private void _compiler_Completed(object sender, CompilerEventArgs e) + { + if (e.Result.StartsWith("ERROR:", StringComparison.OrdinalIgnoreCase)) + { + CompilerError error = ParseError(e.Result); + CreateTask(error); + } + + OnCompilationDone(e.Result, e.State); + } + + private CompilerError ParseError(string error) + { + string message = error.Replace("ERROR:", string.Empty).Replace("Error:", string.Empty); + int index = message.IndexOf(':'); + int line = 0; + + if (index > -1) + { + int start = message.LastIndexOf(' ', index); + if (start > -1) + { + int length = index - start - 1; + string part = message.Substring(start + 1, length); + int.TryParse(part, out line); + } + } + + CompilerError result = new CompilerError() + { + Message = "CoffeeScript: " + message, + FileName = Document.FilePath, + Line = line, + }; + + return result; + } + + public override void MinifyFile(string fileName, string source) + { + if (WESettings.GetBoolean(WESettings.Keys.CoffeeScriptMinify)) + { + string content = MinifyFileMenu.MinifyString(".js", source); + string minFile = GetCompiledFileName(fileName, ".min.js", UseCompiledFolder);//fileName.Replace(".coffee", ".min.js"); + bool fileExist = File.Exists(minFile); + + ProjectHelpers.CheckOutFileFromSourceControl(minFile); + using (StreamWriter writer = new StreamWriter(minFile, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + + if (!fileExist) + AddFileToProject(fileName, minFile); + } + } + + public override bool UseCompiledFolder + { + get { return WESettings.GetBoolean(WESettings.Keys.CoffeeScriptCompileToFolder); } + } + + public override bool IsSaveFileEnabled + { + get { return WESettings.GetBoolean(WESettings.Keys.GenerateJsFileFromCoffeeScript); } + } + + protected override bool CanWriteToDisk(string source) + { + return !string.IsNullOrWhiteSpace(source); + } + } +} + +//static class Iced +//{ +// [Export] +// [FileExtension(".iced")] +// [ContentType("CoffeeScript")] +// internal static FileExtensionToContentTypeDefinition IcedFileExtensionDefinition; +//} \ No newline at end of file diff --git a/EditorExtensions/Margin/CompilerError.cs b/EditorExtensions/Margin/CompilerError.cs new file mode 100644 index 000000000..c4b9548c0 --- /dev/null +++ b/EditorExtensions/Margin/CompilerError.cs @@ -0,0 +1,11 @@ + +namespace MadsKristensen.EditorExtensions +{ + public class CompilerError + { + public int Line { get; set; } + public int Column { get; set; } + public string FileName { get; set; } + public string Message { get; set; } + } +} diff --git a/EditorExtensions/Margin/CompilerResult.cs b/EditorExtensions/Margin/CompilerResult.cs new file mode 100644 index 000000000..38f5f3120 --- /dev/null +++ b/EditorExtensions/Margin/CompilerResult.cs @@ -0,0 +1,16 @@ + +namespace MadsKristensen.EditorExtensions +{ + public class CompilerResult + { + public CompilerResult(string fileName) + { + FileName = fileName; + } + + public bool IsSuccess { get; set; } + public string FileName { get; set; } + public string Result { get; set; } + public CompilerError Error { get; set; } + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/EditorMarginFactory.cs b/EditorExtensions/Margin/EditorMarginFactory.cs new file mode 100644 index 000000000..7786115c8 --- /dev/null +++ b/EditorExtensions/Margin/EditorMarginFactory.cs @@ -0,0 +1,55 @@ +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IWpfTextViewMarginProvider))] + [Name(LessMargin.MarginName)] + [Order(After = PredefinedMarginNames.RightControl)] + [MarginContainer(PredefinedMarginNames.Right)] + [ContentType("LESS")] + [ContentType("CoffeeScript")] + //[ContentType("TypeScript")] + [ContentType("Markdown")] + [TextViewRole(PredefinedTextViewRoles.Debuggable)] + internal sealed class MarginFactory : IWpfTextViewMarginProvider + { + public IWpfTextViewMargin CreateMargin(IWpfTextViewHost textViewHost, IWpfTextViewMargin containerMargin) + { + string source = textViewHost.TextView.TextBuffer.CurrentSnapshot.GetText(); + ITextDocument document; + + if (textViewHost.TextView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document)) + { + switch (textViewHost.TextView.TextBuffer.ContentType.DisplayName) + { + case "LESS": + bool showLess = WESettings.GetBoolean(WESettings.Keys.ShowLessPreviewWindow); + return new LessMargin("CSS", source, showLess, document); + + //case "scss": + // return new ScssMargin("CSS", source, true, document); + + case "CoffeeScript": + bool showCoffee = WESettings.GetBoolean(WESettings.Keys.ShowCoffeeScriptPreviewWindow); + return new CoffeeScriptMargin("JavaScript", source, showCoffee, document); + + //case "TypeScript": + // if (!document.FilePath.EndsWith(".d.ts")) + // { + // bool showType = WESettings.GetBoolean(WESettings.Keys.ShowTypeScriptPreviewWindow); + // return new TypeScriptMargin("TypeScript", source, showType, document); + // } + // break; + + case "markdown": + return new MarkdownMargin("text", source, true, document); + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/LessCompiler.cs b/EditorExtensions/Margin/LessCompiler.cs new file mode 100644 index 000000000..2d91e2e67 --- /dev/null +++ b/EditorExtensions/Margin/LessCompiler.cs @@ -0,0 +1,147 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; + +namespace MadsKristensen.EditorExtensions +{ + public class LessCompiler + { + public LessCompiler(Action callback) + { + Callback = callback; + } + + public Action Callback { get; set; } + + public void Compile(string fileName) + { + string output = Path.GetTempFileName(); + + ProcessStartInfo start = new ProcessStartInfo(@"cscript"); + start.WindowStyle = ProcessWindowStyle.Hidden; + start.CreateNoWindow = true; + start.Arguments = "//nologo //s \"" + GetExecutablePath() + "\" \"" + fileName + "\" \"" + output + "\""; + start.EnvironmentVariables["output"] = output; + start.EnvironmentVariables["fileName"] = fileName; + start.UseShellExecute = false; + start.RedirectStandardError = true; + + Process p = new Process(); + p.StartInfo = start; + p.EnableRaisingEvents = true; + p.Exited += ProcessExited; + p.Start(); + } + + private void ProcessExited(object sender, EventArgs e) + { + using (Process process = (Process)sender) + { + string fileName = process.StartInfo.EnvironmentVariables["fileName"]; + CompilerResult result = new CompilerResult(fileName); + + try + { + ProcessResult(process, result); + } + catch (Exception ex) + { + Logger.Log(ex); + Callback(result); + } + + process.Exited -= ProcessExited; + + Logger.Log(Path.GetFileName(fileName) + " compiled"); + } + } + + private void ProcessResult(Process process, CompilerResult result) + { + string output = process.StartInfo.EnvironmentVariables["output"]; + + if (File.Exists(output)) + { + if (process.ExitCode == 0) + { + result.IsSuccess = true; + result.Result = File.ReadAllText(output); + } + else + { + using (StreamReader reader = process.StandardError) + { + result.Error = ParseError(reader.ReadToEnd()); + } + } + + File.Delete(output); + } + + Callback(result); + } + + private CompilerError ParseError(string error) + { + CompilerError result = new CompilerError(); + string[] lines = error.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + + if (error.Contains("message:")) + { + string[] args = line.Split(new[] { ':' }, 2); + + if (args[0].Trim() == "message") + result.Message = args[1].Trim(); + + if (args[0].Trim() == "filename") + result.FileName = args[1].Trim(); + + int lineNo = 0; + if (args[0].Trim() == "line" && int.TryParse(args[1], out lineNo)) + result.Line = lineNo; + + int columnNo = 0; + if (args[0].Trim() == "column" && int.TryParse(args[1], out columnNo)) + result.Column = columnNo; + } + else + { + if (i == 1 || i == 2) + result.Message += " " + line; + + if (i == 3) + { + string[] lineCol = line.Split(','); + + int lineNo = 0; + if (int.TryParse(lineCol[0].Replace("on line", string.Empty).Trim(), out lineNo)) + result.Line = lineNo; + + int columnNo = 0; + if (int.TryParse(lineCol[0].Replace("column", string.Empty).Trim(':').Trim(), out columnNo)) + result.Column = columnNo; + + result.Message = result.Message.Trim(); + } + + } + } + + return result; + } + + private static string GetExecutablePath() + { + string assembly = Assembly.GetExecutingAssembly().Location; + string folder = Path.GetDirectoryName(assembly).ToLowerInvariant(); + string file = Path.Combine(folder, "resources\\scripts\\lessc.wsf"); + + return file; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/LessMargin.cs b/EditorExtensions/Margin/LessMargin.cs new file mode 100644 index 000000000..fbc52b24a --- /dev/null +++ b/EditorExtensions/Margin/LessMargin.cs @@ -0,0 +1,89 @@ +using EnvDTE; +using Microsoft.VisualStudio.Text; +using System.IO; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + public class LessMargin : MarginBase + { + public const string MarginName = "LessMargin"; + + public LessMargin(string contentType, string source, bool showMargin, ITextDocument document) + : base(source, MarginName, contentType, showMargin, document) + { } + + protected override void StartCompiler(string source) + { + string fileName = GetCompiledFileName(Document.FilePath, ".css", UseCompiledFolder);// Document.FilePath.Replace(".less", ".css"); + + if (_isFirstRun && File.Exists(fileName)) + { + OnCompilationDone(File.ReadAllText(fileName), Document.FilePath); + } + else + { + Logger.Log("LESS: Compiling " + Path.GetFileName(Document.FilePath)); + + System.Threading.Tasks.Task.Run(() => + { + LessCompiler compiler = new LessCompiler(Completed); + compiler.Compile(Document.FilePath); + }); + } + } + + private void Completed(CompilerResult result) + { + if (result.IsSuccess) + { + OnCompilationDone(result.Result, result.FileName); + } + else + { + result.Error.Message = "LESS: " + result.Error.Message; + + CreateTask(result.Error); + + base.OnCompilationDone("ERROR:", Document.FilePath); + } + } + + public override void MinifyFile(string fileName, string source) + { + if (WESettings.GetBoolean(WESettings.Keys.LessMinify) && !Path.GetFileName(fileName).StartsWith("_")) + { + string content = MinifyFileMenu.MinifyString(".css", source); + string minFile = GetCompiledFileName(fileName, ".min.css", UseCompiledFolder);// fileName.Replace(".less", ".min.css"); + bool fileExist = File.Exists(minFile); + + ProjectHelpers.CheckOutFileFromSourceControl(minFile); + using (StreamWriter writer = new StreamWriter(minFile, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + + if (!fileExist) + AddFileToProject(Document.FilePath, minFile); + } + } + + public override bool UseCompiledFolder + { + get { return WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder); } + } + + public override bool IsSaveFileEnabled + { + get { return WESettings.GetBoolean(WESettings.Keys.GenerateCssFileFromLess) && !Path.GetFileName(Document.FilePath).StartsWith("_"); } + } + + protected override bool CanWriteToDisk(string source) + { + //var parser = new Microsoft.CSS.Core.CssParser(); + //StyleSheet stylesheet = parser.Parse(source, false); + + return true;// !string.IsNullOrWhiteSpace(stylesheet.Text); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/LessProjectCompiler.cs b/EditorExtensions/Margin/LessProjectCompiler.cs new file mode 100644 index 000000000..cdcd99757 --- /dev/null +++ b/EditorExtensions/Margin/LessProjectCompiler.cs @@ -0,0 +1,116 @@ +using EnvDTE; +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions +{ + internal class LessProjectCompiler + { + public static void CompileProject(Project project) + { + if (project != null && !string.IsNullOrEmpty(project.FullName)) + { + Task.Run(() => Compile(project)); + } + } + + private static void Compile(Project project) + { + LessCompiler compiler = new LessCompiler(Completed); + + string dir = Path.GetDirectoryName(project.Properties.Item("FullPath").Value.ToString()); + var files = Directory.GetFiles(dir, "*.less", SearchOption.AllDirectories).Where(f => CanCompile(f)); + + foreach (string file in files) + { + compiler.Compile(file); + } + } + + private static bool CanCompile(string fileName) + { + if (EditorExtensionsPackage.DTE.Solution.FindProjectItem(fileName) == null) + return false; + + if (Path.GetFileName(fileName).StartsWith("_")) + return false; + + string minFile = MarginBase.GetCompiledFileName(fileName, ".min.css", WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder)); + if (File.Exists(minFile) && WESettings.GetBoolean(WESettings.Keys.LessMinify)) + return true; + + string cssFile = MarginBase.GetCompiledFileName(fileName, ".css", WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder)); + if (!File.Exists(cssFile)) + return false; + + + return true; + } + + private static void Completed(CompilerResult result) + { + if (result.IsSuccess) + { + string cssFileName = MarginBase.GetCompiledFileName(result.FileName, ".css", WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder));// result.FileName.Replace(".less", ".css"); + + if (File.Exists(cssFileName)) + { + string old = File.ReadAllText(cssFileName); + + if (old != result.Result) + { + ProjectHelpers.CheckOutFileFromSourceControl(cssFileName); + try + { + using (StreamWriter writer = new StreamWriter(cssFileName, false, new UTF8Encoding(true))) + { + writer.Write(result.Result); + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + } + + MinifyFile(result.FileName, result.Result); + } + else if (result.Error != null && !string.IsNullOrEmpty(result.Error.Message)) + { + Logger.Log(result.Error.Message); + } + else + { + Logger.Log("Error compiling LESS file: " + result.FileName); + } + } + + public static void MinifyFile(string lessFileName, string source) + { + if (WESettings.GetBoolean(WESettings.Keys.LessMinify)) + { + string content = MinifyFileMenu.MinifyString(".css", source); + string minFile = MarginBase.GetCompiledFileName(lessFileName, ".min.css", WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder)); //lessFileName.Replace(".less", ".min.css"); + string old = File.ReadAllText(minFile); + + if (old != content) + { + bool fileExist = File.Exists(minFile); + + ProjectHelpers.CheckOutFileFromSourceControl(minFile); + using (StreamWriter writer = new StreamWriter(minFile, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + + if (!fileExist) + MarginBase.AddFileToProject(lessFileName, minFile); + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/MarginBase.cs b/EditorExtensions/Margin/MarginBase.cs new file mode 100644 index 000000000..7371d5ddc --- /dev/null +++ b/EditorExtensions/Margin/MarginBase.cs @@ -0,0 +1,448 @@ +using EnvDTE; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System; +using System.IO; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + public abstract class MarginBase : DockPanel, IWpfTextViewMargin + { + private bool _isDisposed = false; + private IWpfTextViewHost _viewHost; + private string _marginName; + protected string _settingsKey; + private bool _showMargin; + protected bool _isFirstRun = true; + private Dispatcher _dispatcher; + private ErrorListProvider _provider; + + public MarginBase() + { + _dispatcher = Dispatcher.CurrentDispatcher; + } + + public MarginBase(string source, string name, string contentType, bool showMargin, ITextDocument document) + { + Document = document; + _marginName = name; + _settingsKey = _marginName + "_width"; + _showMargin = showMargin; + _dispatcher = Dispatcher.CurrentDispatcher; + _provider = new ErrorListProvider(EditorExtensionsPackage.Instance); + + Document.FileActionOccurred += Document_FileActionOccurred; + + if (showMargin) + { + _dispatcher.BeginInvoke( + new Action(() => Initialize(contentType, source)), DispatcherPriority.ApplicationIdle, null); + } + } + + protected virtual void Document_FileActionOccurred(object sender, TextDocumentFileActionEventArgs e) + { + if (e.FileActionType == FileActionTypes.ContentSavedToDisk) + { + _dispatcher.BeginInvoke(new Action(() => + { + _provider.Tasks.Clear(); + StartCompiler(File.ReadAllText(e.FilePath)); + }), DispatcherPriority.ApplicationIdle, null); + } + } + + public abstract bool IsSaveFileEnabled { get; } + public abstract bool UseCompiledFolder { get; } + protected ITextDocument Document { get; set; } + + private void Initialize(string contentType, string source) + { + _viewHost = CreateTextViewHost(contentType); + CreateControls(_viewHost, source); + StartCompiler(source); + } + + private IWpfTextViewHost CreateTextViewHost(string contentType) + { + var componentModel = ProjectHelpers.GetComponentModel(); + var service = componentModel.GetService(); + var type = service.GetContentType(contentType); + + var textBufferFactory = componentModel.GetService(); + var textViewFactory = componentModel.GetService(); + + ITextBuffer textBuffer = textBufferFactory.CreateTextBuffer(string.Empty, type); + ITextViewRoleSet roles = textViewFactory.CreateTextViewRoleSet(PredefinedTextViewRoles.Interactive, PredefinedTextViewRoles.Document); + IWpfTextView textView = textViewFactory.CreateTextView(textBuffer, roles); + IWpfTextViewHost host = textViewFactory.CreateTextViewHost(textView, false); + + return host; + } + + protected virtual void CreateControls(IWpfTextViewHost host, string source) + { + int width; + + using (var key = EditorExtensionsPackage.Instance.UserRegistryRoot) + { + var raw = key.GetValue("WE_" + _settingsKey); + width = raw != null ? (int)raw : -1; + } + + width = width == -1 ? 400 : width; + + host.TextView.VisualElement.MinWidth = width; + host.TextView.VisualElement.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; + host.TextView.Options.SetOptionValue(DefaultTextViewHostOptions.GlyphMarginId, false); + host.TextView.Options.SetOptionValue(DefaultTextViewHostOptions.LineNumberMarginId, true); + host.TextView.VisualElement.KeyDown += VisualElement_KeyUp; + + //host.GetTextViewMargin(PredefinedMarginNames.BottomControl).VisualElement.Height = 0; + + Grid grid = new Grid(); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Star) }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(5, GridUnitType.Pixel) }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) }); + grid.RowDefinitions.Add(new RowDefinition()); + + grid.Children.Add(host.HostControl); + this.Children.Add(grid); + + Grid.SetColumn(host.HostControl, 2); + Grid.SetRow(host.HostControl, 0); + + GridSplitter splitter = new GridSplitter(); + splitter.Width = 5; + splitter.ResizeDirection = GridResizeDirection.Columns; + splitter.VerticalAlignment = System.Windows.VerticalAlignment.Stretch; + splitter.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; + splitter.DragCompleted += splitter_DragCompleted; + + grid.Children.Add(splitter); + Grid.SetColumn(splitter, 1); + Grid.SetRow(splitter, 0); + } + + void splitter_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e) + { + //Settings.SetValue(_settingsKey, (int)_viewHost.HostControl.ActualWidth); + //Settings.Save(); + using (var key = EditorExtensionsPackage.Instance.UserRegistryRoot) + { + key.SetValue("WE_" + _settingsKey, (int)_viewHost.HostControl.ActualWidth); + } + } + + protected void VisualElement_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key == Key.C && Keyboard.Modifiers == ModifierKeys.Control) + Clipboard.SetText(_viewHost.TextView.TextBuffer.CurrentSnapshot.GetText(_viewHost.TextView.Selection.Start.Position.Position, _viewHost.TextView.Selection.End.Position.Position - _viewHost.TextView.Selection.Start.Position.Position)); + else if (e.Key == Key.PageDown) + _viewHost.TextView.ViewScroller.ScrollViewportVerticallyByPage(ScrollDirection.Down); + else if (e.Key == Key.PageUp) + _viewHost.TextView.ViewScroller.ScrollViewportVerticallyByPage(ScrollDirection.Up); + else if (e.Key == Key.Down) + _viewHost.TextView.ViewScroller.ScrollViewportVerticallyByLine(ScrollDirection.Down); + else if (e.Key == Key.Up) + _viewHost.TextView.ViewScroller.ScrollViewportVerticallyByLine(ScrollDirection.Up); + else if (e.Key == Key.Home) + _viewHost.TextView.ViewScroller.EnsureSpanVisible(new SnapshotSpan(_viewHost.TextView.TextBuffer.CurrentSnapshot, 0, 0)); + else if (e.Key == Key.End) + _viewHost.TextView.ViewScroller.EnsureSpanVisible(new SnapshotSpan(_viewHost.TextView.TextBuffer.CurrentSnapshot, _viewHost.TextView.TextBuffer.CurrentSnapshot.Length, 0)); + } + + public void SetText(string text) + { + if (!_showMargin) + return; + + if (!string.IsNullOrEmpty(text)) + { + int position = _viewHost.TextView.TextViewLines.FirstVisibleLine.Extent.Start.Position; + using (var edit = _viewHost.TextView.TextBuffer.CreateEdit()) + { + edit.Replace(new Span(0, _viewHost.TextView.TextBuffer.CurrentSnapshot.Length), text); + edit.Apply(); + } + + try + { + _viewHost.HostControl.Opacity = 1; + _viewHost.TextView.ViewScroller.ScrollViewportVerticallyByLines(ScrollDirection.Down, _viewHost.TextView.TextSnapshot.GetLineNumberFromPosition(position)); + _viewHost.TextView.ViewScroller.ScrollViewportHorizontallyByPixels(-9999); + } + catch + { + // Threading issues when called from TypeScript + } + } + else + { + _viewHost.HostControl.Opacity = 0.3; + } + } + + protected abstract void StartCompiler(string source); + + protected void OnCompilationDone(string result, string state) + { + bool isSuccess = !result.StartsWith("ERROR:"); + + _dispatcher.BeginInvoke(new Action(() => + { + if (isSuccess) + { + SetText(result); + + if (!_isFirstRun) + { + if (IsSaveFileEnabled) + WriteCompiledFile(result, state); + + MinifyFile(state, result); + } + } + else + { + result = result.Replace("ERROR:", string.Empty); + SetText("/*\r\n\r\nCompile Error. \r\nSee error list for details\r\n" + result + "\r\n\r\n*/"); + } + + _isFirstRun = false; + }), DispatcherPriority.Normal, null); + } + + public abstract void MinifyFile(string fileName, string source); + + protected void WriteCompiledFile(string content, string currentFileName) + { + string extension = Path.GetExtension(currentFileName); + string fileName = null; + + switch (extension.ToLowerInvariant()) + { + case ".less": + case ".scss": + fileName = GetCompiledFileName(currentFileName, ".css", UseCompiledFolder); + break; + + case ".coffee": + case ".ts": + fileName = GetCompiledFileName(currentFileName, ".js", UseCompiledFolder); + break; + + default: // For the Diff view + return; + } + + bool fileExist = File.Exists(fileName); + bool fileWritten = false; + + ProjectHelpers.CheckOutFileFromSourceControl(fileName); + fileWritten = WriteFile(content, fileName, fileExist, fileWritten); + + if (!fileExist && fileWritten) + { + AddFileToProject(currentFileName, fileName); + } + } + + public static string GetCompiledFileName(string sourceFileName, string compiledExtension, bool useFolder) + { + string sourceExtension = Path.GetExtension(sourceFileName); + string compiledFileName = Path.GetFileName(sourceFileName).Replace(sourceExtension, compiledExtension); + string sourceDir = Path.GetDirectoryName(sourceFileName); + + if (useFolder) + { + string compiledDir = Path.Combine(sourceDir, compiledExtension.Replace(".min.", string.Empty).Replace(".", string.Empty)); + + if (!Directory.Exists(compiledDir)) + { + Directory.CreateDirectory(compiledDir); + } + + return Path.Combine(compiledDir, compiledFileName); + } + + return Path.Combine(sourceDir, compiledFileName); + } + + public static void AddFileToProject(string parentFileName, string fileName) + { + if (!File.Exists(fileName)) + return; + + var item = EditorExtensionsPackage.DTE.Solution.FindProjectItem(parentFileName); + + if (item != null && item.ContainingProject != null && !string.IsNullOrEmpty(item.ContainingProject.FullName)) + { + if (item.ProjectItems != null && Path.GetDirectoryName(parentFileName) == Path.GetDirectoryName(fileName)) + { + // WAP + item.ProjectItems.AddFromFile(fileName); + } + else + { // Website + item.ContainingProject.ProjectItems.AddFromFile(fileName); + } + } + } + + private bool WriteFile(string content, string fileName, bool fileExist, bool fileWritten) + { + try + { + if (fileExist || (!fileExist && CanWriteToDisk(content))) + { + using (StreamWriter writer = new StreamWriter(fileName, false, new UTF8Encoding(true))) + { + writer.Write(content); + fileWritten = true; + } + } + } + catch (Exception ex) + { + var error = new CompilerError + { + FileName = Document.FilePath, + Column = 0, + Line = 0, + Message = "Could not write to " + Path.GetFileName(fileName) + }; + + CreateTask(error); + + Logger.Log(ex); + } + + return fileWritten; + } + + protected void CreateTask(CompilerError error) + { + ErrorTask task = new ErrorTask() + { + Line = error.Line, + Column = error.Column, + ErrorCategory = TaskErrorCategory.Error, + Category = TaskCategory.Html, + Document = error.FileName, + Priority = TaskPriority.Low, + Text = error.Message, + }; + + task.AddHierarchyItem(); + + task.Navigate += task_Navigate; + _provider.Tasks.Add(task); + } + + private void task_Navigate(object sender, EventArgs e) + { + Task task = sender as Task; + + _provider.Navigate(task, new Guid(EnvDTE.Constants.vsViewKindPrimary)); + + if (task.Column > 0) + { + var doc = (TextDocument)EditorExtensionsPackage.DTE.ActiveDocument.Object("textdocument"); + doc.Selection.MoveToLineAndOffset(task.Line, task.Column, false); + } + } + + protected abstract bool CanWriteToDisk(string source); + + private void ThrowIfDisposed() + { + if (_isDisposed) + throw new ObjectDisposedException("MarginBase"); + } + + #region IWpfTextViewMargin Members + + /// + /// The that implements the visual representation + /// of the margin. + /// + public System.Windows.FrameworkElement VisualElement + { + // Since this margin implements Canvas, this is the object which renders + // the margin. + get + { + ThrowIfDisposed(); + return this; + } + } + + #endregion + + #region ITextViewMargin Members + + public double MarginSize + { + // Since this is a horizontal margin, its width will be bound to the width of the text view. + // Therefore, its size is its height. + get + { + ThrowIfDisposed(); + return this.ActualHeight; + } + } + + public bool Enabled + { + // The margin should always be enabled + get + { + ThrowIfDisposed(); + return true; + } + } + + /// + /// Returns an instance of the margin if this is the margin that has been requested. + /// + /// The name of the margin requested + /// An instance of EditorMargin1 or null + public ITextViewMargin GetTextViewMargin(string marginName) + { + return (marginName == this._marginName) ? (IWpfTextViewMargin)this : null; + } + + public void Dispose() + { + GC.SuppressFinalize(this); + Dispose(_isDisposed); + } + + protected virtual void Dispose(bool isDisposed) + { + if (!_isDisposed) + { + _isDisposed = true; + + if (_viewHost != null) + { + _viewHost.Close(); + } + + Document.FileActionOccurred -= Document_FileActionOccurred; + _provider.Tasks.Clear(); + _provider.Dispose(); + } + } + #endregion + + } +} diff --git a/EditorExtensions/Margin/MarkdownMargin.cs b/EditorExtensions/Margin/MarkdownMargin.cs new file mode 100644 index 000000000..c5b304711 --- /dev/null +++ b/EditorExtensions/Margin/MarkdownMargin.cs @@ -0,0 +1,150 @@ +using EnvDTE; +using EnvDTE80; +using MarkdownSharp; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; + +namespace MadsKristensen.EditorExtensions +{ + internal class MarkdownMargin : MarginBase + { + public const string MarginName = "MarkdownMargin"; + private Markdown _compiler; + private WebBrowser _browser; + private const string _stylesheet = "WE-Markdown.css"; + + public MarkdownMargin(string contentType, string source, bool showMargin, ITextDocument document) + : base(source, MarginName, contentType, showMargin, document) + { + } + + private void InitializeCompiler() + { + if (_compiler == null) + { + MarkdownOptions options = new MarkdownOptions(); + options.AutoHyperlink = true; + + _compiler = new Markdown(options); + } + } + + protected override void StartCompiler(string source) + { + InitializeCompiler(); + + string result = _compiler.Transform(source); + + string html = "" + + GetStylesheet() + + "" + + "" + result + ""; + + _browser.NavigateToString(html); + } + + public static string GetStylesheet() + { + string folder = ProjectHelpers.GetSolutionFolderPath(); + + if (!string.IsNullOrEmpty(folder)) + { + string file = Path.Combine(folder, _stylesheet); + + if (File.Exists(file)) + { + string linkFormat = ""; + return string.Format(linkFormat, file); + } + } + + return string.Empty; + } + + public static void CreateStylesheet() + { + string file = Path.Combine(ProjectHelpers.GetSolutionFolderPath(), _stylesheet); + + using (StreamWriter writer = new StreamWriter(file, false, new UTF8Encoding(true))) + { + writer.Write("body { background: yellow; }"); + } + + Solution2 solution = EditorExtensionsPackage.DTE.Solution as Solution2; + Project project = solution.Projects + .OfType() + .FirstOrDefault(p => p.Name.Equals(Settings._solutionFolder, StringComparison.OrdinalIgnoreCase)); + + if (project == null) + { + project = solution.AddSolutionFolder(Settings._solutionFolder); + } + + project.ProjectItems.AddFromFile(file); + } + + protected override void CreateControls(IWpfTextViewHost host, string source) + { + int width = WESettings.GetInt(_settingsKey); + width = width == -1 ? 400 : width; + + _browser = new WebBrowser(); + _browser.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; + + Grid grid = new Grid(); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Star) }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(5, GridUnitType.Pixel) }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(width) }); + grid.RowDefinitions.Add(new RowDefinition()); + + grid.Children.Add(_browser); + this.Children.Add(grid); + + Grid.SetColumn(_browser, 2); + Grid.SetRow(_browser, 0); + + GridSplitter splitter = new GridSplitter(); + splitter.Width = 5; + splitter.ResizeDirection = GridResizeDirection.Columns; + splitter.VerticalAlignment = System.Windows.VerticalAlignment.Stretch; + splitter.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; + splitter.DragCompleted += splitter_DragCompleted; + + grid.Children.Add(splitter); + Grid.SetColumn(splitter, 1); + Grid.SetRow(splitter, 0); + } + + void splitter_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e) + { + Settings.SetValue(_settingsKey, (int)this.ActualWidth); + Settings.Save(); + } + + public override void MinifyFile(string fileName, string source) + { + // Nothing to minify + } + + public override bool UseCompiledFolder + { + get { return false; } + } + + public override bool IsSaveFileEnabled + { + get { return false; } + } + + protected override bool CanWriteToDisk(string source) + { + return false; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/ScriptRunnerBase.cs b/EditorExtensions/Margin/ScriptRunnerBase.cs new file mode 100644 index 000000000..cfa9cea2d --- /dev/null +++ b/EditorExtensions/Margin/ScriptRunnerBase.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Windows.Threading; + +[ComVisible(true)] +public abstract class ScriptRunnerBase : IDisposable +{ + private WebBrowser _browser = new WebBrowser(); + private bool _disposed; + private Dispatcher _dispatcher; + + public ScriptRunnerBase(Dispatcher dispatcher) + { + _dispatcher = dispatcher; + } + + protected abstract string CreateHtml(string source, string state); + + public void Compile(string source, string state) + { + _dispatcher.BeginInvoke(new Action(() => + { + _browser.ObjectForScripting = this; + _browser.ScriptErrorsSuppressed = true; + _browser.DocumentText = CreateHtml(source, state); + + }), DispatcherPriority.ApplicationIdle, null); + } + + public void Execute(string result, string state) + { + OnCompleted(result, state); + } + + protected static string ReadResourceFile(string resourceFile) + { + using (Stream s = typeof(JsHintCompiler).Assembly.GetManifestResourceStream(resourceFile)) + using (var reader = new StreamReader(s)) + { + return reader.ReadToEnd(); + } + } + + public event EventHandler Completed; + + protected void OnCompleted(string message, string data) + { + if (Completed != null) + { + Completed(this, new CompilerEventArgs() { Result = message, State = data }); + } + } + + public void Dispose() + { + if (!_disposed) + { + Completed = null; + + if (_browser != null) + { + _browser.Dispose(); + } + + _browser = null; + _disposed = true; + } + } +} + +public class CompilerEventArgs : EventArgs +{ + public string Result { get; set; } + public string State { get; set; } +} \ No newline at end of file diff --git a/EditorExtensions/Margin/ScssMargin.cs b/EditorExtensions/Margin/ScssMargin.cs new file mode 100644 index 000000000..e16c0fb69 --- /dev/null +++ b/EditorExtensions/Margin/ScssMargin.cs @@ -0,0 +1,158 @@ +//using EnvDTE; +//using Microsoft.CSS.Core; +//using Microsoft.VisualStudio.Text; +//using SassAndCoffee.Ruby.Sass; +//using System; +//using System.IO; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace MadsKristensen.EditorExtensions +//{ +// /// +// /// A class detailing the margin's visual definition including both size and content. +// /// +// class ScssMargin : MarginBase +// { +// public const string MarginName = "ScssMargin"; +// private SassCompiler _compiler; + +// public ScssMargin() +// : base() +// { +// _compiler = new SassCompiler(); +// } + +// public ScssMargin(string contentType, string source, bool showMargin, ITextDocument document) +// : base(source, MarginName, contentType, showMargin, document) +// { +// _compiler = new SassCompiler(); +// } + +// public void CompileProject() +// { +// Project project = ProjectHelpers.GetActiveProject(); + +// if (project != null && !string.IsNullOrEmpty(project.FullName)) +// { +// Task.Run(() => +// { +// string dir = Path.GetDirectoryName(project.FullName); +// var files = Directory.GetFiles(dir, "*.scss", SearchOption.AllDirectories).Where(f => CanCompile(f)); + +// Parallel.ForEach(files, file => +// { +// EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: Compiling " + Path.GetFileName(file); +// string result = CompileFile(file); +// base.WriteCompiledFile(result, file); +// this.MinifyFile(file, result); +// }); + +// EditorExtensionsPackage.DTE.StatusBar.Clear(); +// }); +// } +// } + +// private static bool CanCompile(string fileName) +// { +// if (EditorExtensionsPackage.DTE.Solution.FindProjectItem(fileName) == null) +// return false; + +// if (Path.GetFileName(fileName).StartsWith("_")) +// return false; + +// string minFile = MarginBase.GetCompiledFileName(fileName, ".min.css", WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder)); +// if (File.Exists(minFile) && WESettings.GetBoolean(WESettings.Keys.LessMinify)) +// return true; + +// string cssFile = MarginBase.GetCompiledFileName(fileName, ".css", WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder)); +// if (!File.Exists(cssFile)) +// return false; + + +// return true; +// } + + +// protected override void StartCompiler(string source) +// { +// string fileName = GetCompiledFileName(Document.FilePath, ".css", UseCompiledFolder); + +// if (_isFirstRun && File.Exists(fileName)) +// { +// OnCompilationDone(File.ReadAllText(fileName), Document.FilePath); +// return; +// } +// else if (!Path.GetFileName(Document.FilePath).StartsWith("_")) +// { +// Task.Run(() => +// { +// Compile(Document.FilePath); +// }); +// } +// } + +// private void Compile(string fileName) +// { +// EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: Compiling " + Path.GetFileName(fileName); + +// string result = CompileFile(fileName); +// OnCompilationDone(result, Document.FilePath); + +// EditorExtensionsPackage.DTE.StatusBar.Clear(); +// } + +// private string CompileFile(string fileName) +// { +// try +// { +// string result = _compiler.Compile(fileName, false, null); + +// CssFormatter formatter = new CssFormatter(); +// result = formatter.Format(result); + +// return result; +// } +// catch (Exception ex) +// { +// return "ERROR: " + ex.Message; +// } +// } + +// public override void MinifyFile(string fileName, string source) +// { +// if (WESettings.GetBoolean(WESettings.Keys.ScssMinify)) +// { +// string content = MinifyFileMenu.MinifyString(".css", source); +// string minFile = GetCompiledFileName(fileName, ".min.css", UseCompiledFolder); +// bool fileExist = File.Exists(minFile); + +// ProjectHelpers.CheckOutFileFromSourceControl(minFile); +// File.WriteAllText(minFile, content); + +// if (!fileExist) +// AddFileToProject(Document.FilePath, minFile); +// } +// } + +// public override bool CanTakeFocus +// { +// get { return true; } +// } + +// public override bool IsSaveFileEnabled +// { +// get { return WESettings.GetBoolean(WESettings.Keys.GenerateCssFileFromScss) && !Path.GetFileName(Document.FilePath).StartsWith("_"); } +// } + +// public override bool UseCompiledFolder +// { +// get { return WESettings.GetBoolean(WESettings.Keys.ScssCompileToFolder); } +// } + +// protected override bool CanWriteToDisk(string source) +// { +// return !string.IsNullOrWhiteSpace(source); +// } +// } +//} \ No newline at end of file diff --git a/EditorExtensions/Margin/TypeScriptMargin.cs b/EditorExtensions/Margin/TypeScriptMargin.cs new file mode 100644 index 000000000..6d3e4fc53 --- /dev/null +++ b/EditorExtensions/Margin/TypeScriptMargin.cs @@ -0,0 +1,314 @@ +using Microsoft.Ajax.Utilities; +using Microsoft.VisualStudio.Text; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions +{ + internal class TypeScriptMargin : MarginBase + { + public const string MarginName = "TypeScriptMargin"; + private string _executablePath; + + public TypeScriptMargin(string contentType, string source, bool showMargin, ITextDocument document) + : base(source, MarginName, contentType, showMargin, document) + { + _executablePath = GetExecutablePath(); + } + + public TypeScriptMargin() + : base() + { + _executablePath = GetExecutablePath(); + } + + public void CompileProjectFiles(EnvDTE.Project project) + { + try + { + if (!File.Exists(_executablePath) || string.IsNullOrEmpty(project.FullName)) + return; + + string fullPath = project.Properties.Item("FullPath").Value.ToString(); + + if (project != null && !string.IsNullOrEmpty(fullPath)) + { + string dir = Path.GetDirectoryName(fullPath); + var files = Directory.GetFiles(dir, "*.ts", SearchOption.AllDirectories); + + Parallel.ForEach(files, file => + { + if (!file.EndsWith(".d.ts") && EditorExtensionsPackage.DTE.Solution.FindProjectItem(file) != null) + { + StartProcess(file, CompileProjectExited); + } + }); + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + + private void CompileProjectExited(object sender, EventArgs e) + { + Process p = (Process)sender; + string file = p.StartInfo.EnvironmentVariables["file"]; + + p.Exited -= CompileProjectExited; + p.Dispose(); + + string js = file.Replace(".ts", ".js"); + + if (File.Exists(js)) + { + try + { + string content = File.ReadAllText(js); + MinifyFile(file, content); + ResaveWithBom(js, content); + Logger.Log("TypeScript: Compiling " + Path.GetFileName(file)); + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptAddGeneratedFilesToProject)) + { + AddFileToProject(file); + } + } + + private void ResaveWithBom(string fileName, string content) + { + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptResaveWithUtf8BOM)) + { + using (StreamWriter writer = new StreamWriter(fileName, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + } + } + + public override void MinifyFile(string fileName, string source) + { + if (!WESettings.GetBoolean(WESettings.Keys.TypeScriptMinify)) + return; + + try + { + string filePath = fileName.Replace(".ts", ".js"); + if (File.Exists(filePath)) + { + Minifier minifier = new Minifier(); + CodeSettings settings = new CodeSettings() { EvalTreatment = EvalTreatment.MakeImmediateSafe, PreserveImportantComments = false }; + + string content = minifier.MinifyJavaScript(source, settings); + string minFile = fileName.Replace(".ts", ".min.js"); + bool fileExist = File.Exists(minFile); + + using (StreamWriter writer = new StreamWriter(minFile, false, new UTF8Encoding(true))) + { + writer.Write(content); + } + + if (!fileExist && WESettings.GetBoolean(WESettings.Keys.TypeScriptAddGeneratedFilesToProject)) + AddFileToProject(fileName, minFile); + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + + private static void AddFileToProject(string file) + { + string[] files = GetChildren(file); + + foreach (string generated in files) + { + if (EditorExtensionsPackage.DTE.Solution.FindProjectItem(generated) != null) + continue; + + if (File.Exists(generated)) + { + AddFileToProject(file, generated); + } + } + } + + private static string[] GetChildren(string file) + { + return new string[] { + file.Replace(".ts", ".js"), + file.Replace(".ts", ".min.js"), + file.Replace(".ts", ".js.map") + }; + } + + protected override void StartCompiler(string source) + { + string fileName = Document.FilePath.Replace(".ts", ".js"); + + if (_isFirstRun && File.Exists(fileName)) + { + OnCompilationDone(File.ReadAllText(fileName), Document.FilePath); + } + else if (!fileName.EndsWith(".d.ts") && WESettings.GetBoolean(WESettings.Keys.GenerateJsFileFromTypeScript)) + { + if (EditorExtensionsPackage.DTE.Solution.SolutionBuild.BuildState == EnvDTE.vsBuildState.vsBuildStateInProgress) + return; + + if (File.Exists(_executablePath)) + { + _isFirstRun = false; + System.Threading.Tasks.Task.Run(() => + { + StartProcess(Document.FilePath, CompilerExited); + }); + } + else + { + base.OnCompilationDone("ERROR: The TypeScript compiler couldn't be found. Download http://www.typescriptlang.org/#Download", Document.FilePath); + } + } + else + { + base.OnCompilationDone("// JavaScript generation is disabled in Tools -> Options", Document.FilePath); + } + } + + private static string GetExecutablePath() + { + string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + string path = Path.Combine(programFiles, @"Microsoft SDKs\TypeScript\tsc.exe"); + + if (!File.Exists(path)) + { + path = Path.Combine(programFiles, @"Microsoft SDKs\TypeScript\0.8.1.1\tsc.exe"); + } + + if (!File.Exists(path)) + { + path = Path.Combine(programFiles, @"Microsoft SDKs\TypeScript\0.8.1.0\tsc.exe"); + } + + if (!File.Exists(path)) + { + path = Path.Combine(programFiles, @"Microsoft SDKs\TypeScript\0.8.0.0\tsc.exe"); + } + + return path; + } + + private void StartProcess(string file, EventHandler eventHandler) + { + CheckOutChildren(file); + + Logger.Log("Compiling TypeScript..."); + + ProcessStartInfo start = new ProcessStartInfo(); + start.WindowStyle = ProcessWindowStyle.Hidden; + start.CreateNoWindow = true; + start.Arguments = "\"" + file + "\"" + GenerateArguments(); + start.FileName = _executablePath; + start.UseShellExecute = false; + start.EnvironmentVariables.Add("file", file); + start.RedirectStandardError = true; + + Process p = new Process(); + p.StartInfo = start; + p.EnableRaisingEvents = true; + p.Exited += eventHandler; + + p.Start(); + } + + private static void CheckOutChildren(string file) + { + var files = GetChildren(file).Where(f => File.Exists(f)); + + foreach (string child in files) + { + ProjectHelpers.CheckOutFileFromSourceControl(child); + } + } + + private static string GenerateArguments() + { + string args = string.Empty; + + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptUseAmdModule)) + args += " --module amd"; + + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptCompileES3)) + args += " --target ES3"; + else + args += " --target ES5"; + + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptProduceSourceMap)) + args += " -sourcemap"; + + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptKeepComments)) + args += " -c"; + + return args; + + } + + private void CompilerExited(object sender, EventArgs e) + { + Process p = (Process)sender; + + if (p.ExitCode == 0) + { + string fileName = Document.FilePath.Replace(".ts", ".js"); + + if (File.Exists(fileName)) + { + string content = File.ReadAllText(fileName); + + ResaveWithBom(fileName, content); + + if (WESettings.GetBoolean(WESettings.Keys.TypeScriptAddGeneratedFilesToProject)) + { + AddFileToProject(Document.FilePath); + } + + Logger.Log("TypeScript: Compiling " + Path.GetFileName(fileName)); + base.OnCompilationDone(content, Document.FilePath); + } + } + else + { + base.OnCompilationDone("ERROR: " + p.StandardError.ReadToEnd(), Document.FilePath); + } + + p.Exited -= CompilerExited; + p.Dispose(); + } + + public override bool IsSaveFileEnabled + { + get { return false; } + } + + public override bool UseCompiledFolder + { + get { return false; } + } + + protected override bool CanWriteToDisk(string source) + { + return false; + } + } +} diff --git a/EditorExtensions/MenuItems/BuildMenu.cs b/EditorExtensions/MenuItems/BuildMenu.cs new file mode 100644 index 000000000..b36afb26f --- /dev/null +++ b/EditorExtensions/MenuItems/BuildMenu.cs @@ -0,0 +1,145 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.IO; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class BuildMenu + { + private static DTE2 _dte; + private OleMenuCommandService _mcs; + + public BuildMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID cmdBundles = new CommandID(GuidList.guidBuildCmdSet, (int)PkgCmdIDList.cmdBuildBundles); + OleMenuCommand menuBundles = new OleMenuCommand((s, e) => UpdateBundleFiles(), cmdBundles); + _mcs.AddCommand(menuBundles); + + CommandID cmdLess = new CommandID(GuidList.guidBuildCmdSet, (int)PkgCmdIDList.cmdBuildLess); + OleMenuCommand menuLess = new OleMenuCommand((s, e) => BuildLess(), cmdLess); + _mcs.AddCommand(menuLess); + + //CommandID cmdTS = new CommandID(GuidList.guidBuildCmdSet, (int)PkgCmdIDList.cmdBuildTypeScript); + //OleMenuCommand menuTS = new OleMenuCommand((s, e) => BuildTypeScript(), cmdTS); + //_mcs.AddCommand(menuTS); + + CommandID cmdMinify = new CommandID(GuidList.guidBuildCmdSet, (int)PkgCmdIDList.cmdBuildMinify); + OleMenuCommand menuMinify = new OleMenuCommand((s, e) => Minify(), cmdMinify); + _mcs.AddCommand(menuMinify); + + CommandID cmdCoffee = new CommandID(GuidList.guidBuildCmdSet, (int)PkgCmdIDList.cmdBuildCoffeeScript); + OleMenuCommand menuCoffee = new OleMenuCommand((s, e) => BuildCoffeeScript(), cmdCoffee); + _mcs.AddCommand(menuCoffee); + } + + private void BuildCoffeeScript() + { + foreach (Project project in _dte.Solution.Projects) + { + CoffeeScriptMargin margin = new CoffeeScriptMargin(); + margin.CompileProject(project); + } + } + + private void UpdateBundleFiles() + { + //Logger.Log("Updating bundles..."); + BundleFilesMenu.UpdateBundles(null, true); + //Logger.Log("Bundles updated"); + } + + private void BuildLess() + { + foreach (Project project in _dte.Solution.Projects) + { + LessProjectCompiler.CompileProject(project); + } + } + + //private void BuildTypeScript() + //{ + // foreach (Project project in _dte.Solution.Projects) + // { + // new TypeScriptMargin().CompileProjectFiles(project); + // } + //} + + private void Minify() + { + _dte.StatusBar.Text = "Web Essentials: Minifying files..."; + var files = GetFiles(); + + foreach (string path in files) + { + string extension = Path.GetExtension(path); + string minPath = MinifyFileMenu.GetMinFileName(path, extension); + + if (!path.EndsWith(".min" + extension) && File.Exists(minPath) && _dte.Solution.FindProjectItem(path) != null) + { + if (extension.Equals(".js", StringComparison.OrdinalIgnoreCase)) + { + JavaScriptSaveListener.Minify(path, minPath, false); + } + else + { + CssSaveListener.Minify(path, minPath); + } + } + } + + _dte.StatusBar.Text = "Web Essentials: Files minified"; + } + + private IEnumerable GetFiles() + { + //Project project = ProjectHelpers.GetActiveProject(); + + foreach (Project project in _dte.Solution.Projects) + { + if (string.IsNullOrEmpty(project.FullName)) + continue; + + string dir = Path.GetDirectoryName(project.FullName); + + List list = new List(); + list.AddRange(Directory.GetFiles(dir, "*.css", SearchOption.AllDirectories)); + list.AddRange(Directory.GetFiles(dir, "*.js", SearchOption.AllDirectories)); + + foreach (string file in list.Where(f => !f.Contains(".min."))) + { + string extension = Path.GetExtension(file); + + if (extension == ".css") + { + if (!File.Exists(file.Replace(".css", ".less")) && + !File.Exists(file.Replace(".css", ".scss")) && + !File.Exists(file + ".bundle")) + + yield return file; + } + if (extension == ".js") + { + if (!File.Exists(file.Replace(".js", ".coffee")) && + !File.Exists(file.Replace(".js", ".ts")) && + !File.Exists(file + ".bundle")) + + yield return file; + } + } + } + + yield break; + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/BundleFiles.cs b/EditorExtensions/MenuItems/BundleFiles.cs new file mode 100644 index 000000000..0ce185c0b --- /dev/null +++ b/EditorExtensions/MenuItems/BundleFiles.cs @@ -0,0 +1,400 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Design; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Threading; +using System.Xml; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IWpfTextViewCreationListener))] + [ContentType("CSS")] + [ContentType("JavaScript")] + [ContentType("XML")] + [TextViewRole(PredefinedTextViewRoles.Document)] + internal class BundleFilesMenu : IWpfTextViewCreationListener + { + private static DTE2 _dte; + private OleMenuCommandService _mcs; + public const string _ext = ".bundle"; + + public BundleFilesMenu() + { + // Used by the IWpfTextViewCreationListener + _dte = EditorExtensionsPackage.DTE; + } + + public BundleFilesMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void TextViewCreated(IWpfTextView textView) + { + ITextDocument document; + textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document); + + if (document != null) + { + document.FileActionOccurred += document_FileActionOccurred; + } + } + + private void document_FileActionOccurred(object sender, TextDocumentFileActionEventArgs e) + { + if (e.FileActionType == FileActionTypes.ContentSavedToDisk) + { + string file = e.FilePath.EndsWith(_ext) ? null : e.FilePath; + + System.Threading.Tasks.Task.Run(() => + { + UpdateBundles(file, file == null); + }); + } + } + + public static void UpdateBundles(string changedFile, bool isBuild) + { + if (string.IsNullOrEmpty(changedFile)) + { + foreach (Project project in EditorExtensionsPackage.DTE.Solution.Projects) + { + if (project.ProjectItems.Count > 1) + { + UpdateBundle(project.ProjectItems.Item(project.ProjectItems.Count).FileNames[1], isBuild); + } + } + } + else + { + UpdateBundle(changedFile, isBuild); + } + } + + private static void UpdateBundle(string changedFile, bool isBuild) + { + string dir = ProjectHelpers.GetProjectFolder(changedFile); + + if (string.IsNullOrEmpty(dir)) + return; + + //if (dir.Contains(".")) + //{ + // dir = Path.GetDirectoryName(dir); + //} + + foreach (string file in Directory.GetFiles(dir, "*" + _ext, SearchOption.AllDirectories)) + { + if (file.IndexOf("\\app_data\\", StringComparison.OrdinalIgnoreCase) > -1) + continue; + + XmlDocument doc = GetXmlDocument(file); + bool enabled = false; + + if (doc != null) + { + XmlNode bundleNode = doc.SelectSingleNode("//bundle"); + if (bundleNode == null) + continue; + + XmlNodeList nodes = doc.SelectNodes("//file"); + foreach (XmlNode node in nodes) + { + string relative = node.InnerText; + string absolute = ProjectHelpers.ToAbsoluteFilePath(relative, dir).Replace("/", "\\").Replace("\\\\", "\\"); + + if (changedFile != null && absolute.Equals(changedFile.Replace("\\\\", "\\"), StringComparison.OrdinalIgnoreCase)) + { + enabled = true; + break; + } + } + + if (isBuild && bundleNode.Attributes["runOnBuild"] != null && bundleNode.Attributes["runOnBuild"].InnerText == "true") + { + enabled = true; + } + + if (enabled) + { + WriteBundleFile(file, doc); + } + } + } + } + + private static XmlDocument GetXmlDocument(string filePath) + { + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(File.ReadAllText(filePath)); + return doc; + } + catch (Exception ex) + { + Logger.Log(ex); + return null; + } + } + + public void SetupCommands() + { + CommandID commandCss = new CommandID(GuidList.guidBundleCmdSet, (int)PkgCmdIDList.BundleCss); + OleMenuCommand menuCommandCss = new OleMenuCommand((s, e) => CreateBundlefile(".css"), commandCss); + menuCommandCss.BeforeQueryStatus += (s, e) => { BeforeQueryStatus(s, ".css"); }; + _mcs.AddCommand(menuCommandCss); + + CommandID commandJs = new CommandID(GuidList.guidBundleCmdSet, (int)PkgCmdIDList.BundleJs); + OleMenuCommand menuCommandJs = new OleMenuCommand((s, e) => CreateBundlefile(".js"), commandJs); + menuCommandJs.BeforeQueryStatus += (s, e) => { BeforeQueryStatus(s, ".js"); }; + _mcs.AddCommand(menuCommandJs); + } + + private void BeforeQueryStatus(object sender, string extension) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + //_selectedItems = ProjectHelpers.GetSelectedItems().Where(p => Path.GetExtension(p.FileNames[1]) == extension); + + menuCommand.Enabled = GetSelectedItems(extension).Count() > 1; + } + + private IEnumerable GetSelectedItems(string extension) + { + return ProjectHelpers.GetSelectedItems().Where(p => Path.GetExtension(p.FileNames[1]) == extension); + } + + //private IEnumerable GetSelectedFilePaths(string extension) + //{ + // var raw = ProjectHelpers.GetSelectedItems().Where(p => Path.GetExtension(p.Properties.Item("FullPath").ToString()) == extension); + + // foreach (string file in raw) + // { + // //if (!file.EndsWith(".min" + extension)) + // //{ + // yield return file; + // //} + // } + //} + + private void CreateBundlefile(string extension) + { + //var selectedPaths = GetSelectedFilePaths(extension); + StringBuilder sb = new StringBuilder(); + string firstFile = null; + var items = GetSelectedItems(extension); + + foreach (ProjectItem item in items) + { + if (string.IsNullOrEmpty(firstFile)) + firstFile = item.FileNames[1]; + + string content = File.ReadAllText(item.FileNames[1]); + sb.AppendLine(content); + } + + if (firstFile != null) + { + string dir = Path.GetDirectoryName(firstFile); + + + dir = GetProjectRelativeFolder(items.ElementAt(0)); + + if (Directory.Exists(dir)) + { + string bundleFile = Microsoft.VisualBasic.Interaction.InputBox("Specify the name of the bundle", "Web Essentials", "bundle1"); + + if (!bundleFile.EndsWith(_ext, StringComparison.OrdinalIgnoreCase)) + bundleFile += extension + _ext; + + string bundlePath = Path.Combine(dir, bundleFile); + + if (File.Exists(bundlePath)) + { + MessageBox.Show("The file already exist", "Web Essentials", MessageBoxButton.OK, MessageBoxImage.Warning); + } + else + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => WriteFile(bundlePath, items, extension, bundleFile.Replace(_ext, string.Empty))), + DispatcherPriority.ApplicationIdle, null); + } + } + } + } + + private static string GetProjectRelativeFolder(ProjectItem item) + { + object parent = item.Collection.Parent; + ProjectItem folder = parent as ProjectItem; + Project project = parent as Project; + + if (folder != null) + { + return folder.FileNames[1]; + } + else if (project != null) + { + return project.FullName; + } + + return null; + } + + private void WriteFile(string filePath, IEnumerable files, string extension, string output) + { + string projectRoot = ProjectHelpers.GetProjectFolder(files.ElementAt(0).FileNames[1]); + StringBuilder sb = new StringBuilder(); + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Indent = true; + + using (XmlWriter writer = XmlWriter.Create(sb, settings)) + { + writer.WriteStartElement("bundle"); + writer.WriteAttributeString("minify", "true"); + writer.WriteAttributeString("runOnBuild", "true"); + writer.WriteAttributeString("output", output); + writer.WriteComment("The order of the elements determines the order of them when bundled."); + + foreach (ProjectItem item in files) + { + string relative = item.IsLink() ? item.FileNames[1] : "/" + FileHelpers.RelativePath(projectRoot, item.FileNames[1]); + writer.WriteElementString("file", relative); + } + + writer.WriteEndElement(); + } + + sb.Replace(Encoding.Unicode.WebName, Encoding.UTF8.WebName); + + ProjectHelpers.CheckOutFileFromSourceControl(filePath); + File.WriteAllText(filePath, sb.ToString()); + ProjectHelpers.AddFileToActiveProject(filePath, "None"); + + _dte.ItemOperations.OpenFile(filePath); + + XmlDocument doc = GetXmlDocument(filePath); + + if (doc != null) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => WriteBundleFile(filePath, doc)), DispatcherPriority.ApplicationIdle, null); + } + } + + private static void WriteBundleFile(string filePath, XmlDocument doc) + { + XmlNode bundleNode = doc.SelectSingleNode("//bundle"); + + if (bundleNode == null) + return; + + XmlNode outputAttr = bundleNode.Attributes["output"]; + + if (outputAttr != null && (outputAttr.InnerText.Contains("/") || outputAttr.InnerText.Contains("\\"))) + { + MessageBox.Show("The 'output' attribute is for file names only - not paths", "Web Essentials"); + return; + } + + Dictionary files = new Dictionary(); + string extension = Path.GetExtension(filePath.Replace(_ext, string.Empty)); + XmlNodeList nodes = doc.SelectNodes("//file"); + + foreach (XmlNode node in nodes) + { + string absolute = ProjectHelpers.ToAbsoluteFilePath(node.InnerText, ProjectHelpers.GetProjectFolder(filePath)).Replace("\\\\", "\\"); + + if (node.InnerText.Contains(":\\") || node.InnerText.StartsWith("\\\\")) + { + absolute = node.InnerText; + } + + if (File.Exists(absolute)) + { + if (!files.ContainsKey(absolute)) + files.Add(absolute, node.InnerText); + } + else + { + string error = string.Format("Bundle error: The file '{0}' doesn't exist", node.InnerText); + _dte.ItemOperations.OpenFile(filePath); + MessageBox.Show(error, "Web Essentials"); + return; + } + } + + string bundlePath = outputAttr != null ? Path.Combine(Path.GetDirectoryName(filePath), outputAttr.InnerText) : filePath.Replace(_ext, string.Empty); + StringBuilder sb = new StringBuilder(); + + foreach (string file in files.Keys) + { + //if (extension.Equals(".css", StringComparison.OrdinalIgnoreCase)) + //{ + // sb.AppendLine("/*#source " + files[file] + " */"); + //} + if (extension.Equals(".js", StringComparison.OrdinalIgnoreCase) && WESettings.GetBoolean(WESettings.Keys.GenerateJavaScriptSourceMaps)) + { + sb.AppendLine("///#source 1 1 " + files[file]); + } + + sb.AppendLine(File.ReadAllText(file)); + } + + if (!File.Exists(bundlePath) || File.ReadAllText(bundlePath) != sb.ToString()) + { + ProjectHelpers.CheckOutFileFromSourceControl(bundlePath); + using (StreamWriter writer = new StreamWriter(bundlePath, false, new UTF8Encoding(true))) + { + writer.Write(sb.ToString()); + Logger.Log("Updating bundle: " + Path.GetFileName(bundlePath)); + } + MarginBase.AddFileToProject(filePath, bundlePath); + + if (bundleNode.Attributes["minify"] != null || bundleNode.Attributes["minify"].InnerText == "true") + { + WriteMinFile(filePath, bundlePath, sb.ToString(), extension); + } + } + } + + private static void WriteMinFile(string filePath, string bundlePath, string content, string extension) + { + string minPath = bundlePath.Replace(Path.GetExtension(bundlePath), ".min" + Path.GetExtension(bundlePath)); + + if (extension.Equals(".js", StringComparison.OrdinalIgnoreCase)) + { + JavaScriptSaveListener.Minify(bundlePath, minPath, true); + MarginBase.AddFileToProject(filePath, minPath); + + if (WESettings.GetBoolean(WESettings.Keys.GenerateJavaScriptSourceMaps)) + { + MarginBase.AddFileToProject(filePath, minPath + ".map"); + } + } + else if (extension.Equals(".css", StringComparison.OrdinalIgnoreCase)) + { + string minContent = MinifyFileMenu.MinifyString(extension, content); + + ProjectHelpers.CheckOutFileFromSourceControl(minPath); + + using (StreamWriter writer = new StreamWriter(minPath, false, new UTF8Encoding(true))) + { + writer.Write(minContent); + } + MarginBase.AddFileToProject(filePath, minPath); + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/Diff.cs b/EditorExtensions/MenuItems/Diff.cs new file mode 100644 index 000000000..038baa05f --- /dev/null +++ b/EditorExtensions/MenuItems/Diff.cs @@ -0,0 +1,66 @@ +using System.ComponentModel.Design; +using System.Linq; +using System.Text; +using EnvDTE; +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Shell; +using System; +using System.Collections.Generic; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + internal class DiffMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + + public DiffMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID commandId = new CommandID(GuidList.guidDiffCmdSet, (int)PkgCmdIDList.cmdDiff); + OleMenuCommand menuCommand = new OleMenuCommand((s, e) => Sort(), commandId); + menuCommand.BeforeQueryStatus += menuCommand_BeforeQueryStatus; + _mcs.AddCommand(menuCommand); + } + + //private List list = new List() + //{ + // ".txt", ".cs", ".aspx", ".ascx", ".asmx", ".master", ".cshtml", ".vbhtml", ".js", ".coffee", ".css", ".less", ".sass", ".scss", ".xml" + //}; + + private List files; + + void menuCommand_BeforeQueryStatus(object sender, System.EventArgs e) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + files = new List(ProjectHelpers.GetSelectedItemPaths()); + + //if (files.Count == 2) + //{ + // if (list.Contains(Path.GetExtension(files[0]).ToLowerInvariant())) + // { + // if (list.Contains(Path.GetExtension(files[1]).ToLowerInvariant())) + // { + // menuCommand.Enabled = true; + // return; + // } + // } + //} + + menuCommand.Enabled = files.Count == 2; + } + + private void Sort() + { + if (files.Count == 2) + EditorExtensionsPackage.DTE.ExecuteCommand("Tools.DiffFiles \"" + files[0] + "\" \"" + files[1] + "\""); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/Encoding.cs b/EditorExtensions/MenuItems/Encoding.cs new file mode 100644 index 000000000..c3e58763e --- /dev/null +++ b/EditorExtensions/MenuItems/Encoding.cs @@ -0,0 +1,62 @@ +//using System; +//using System.ComponentModel.Design; +//using System.Web; +//using EnvDTE; +//using EnvDTE80; +//using Microsoft.VisualStudio.Shell; + +//namespace MadsKristensen.EditorExtensions +//{ +// internal class EncodingMenu +// { +// private DTE2 _dte; +// private OleMenuCommandService _mcs; +// private delegate string Replacement(string original); + +// public EncodingMenu(DTE2 dte, OleMenuCommandService mcs) +// { +// _dte = dte; +// _mcs = mcs; +// } + +// public void SetupCommands() +// { +// SetupCommand(PkgCmdIDList.htmlEncode, HttpUtility.HtmlEncode); +// SetupCommand(PkgCmdIDList.attrEncode, HttpUtility.HtmlAttributeEncode); +// SetupCommand(PkgCmdIDList.htmlDecode, HttpUtility.HtmlDecode); +// SetupCommand(PkgCmdIDList.urlEncode, HttpUtility.UrlEncode); +// SetupCommand(PkgCmdIDList.urlPathEncode, HttpUtility.UrlPathEncode); +// SetupCommand(PkgCmdIDList.urlDecode, HttpUtility.UrlDecode); +// SetupCommand(PkgCmdIDList.jsEncode, HttpUtility.JavaScriptStringEncode); +// } + +// private void SetupCommand(uint command, Replacement callback) +// { +// CommandID commandId = new CommandID(GuidList.guidEditorExtensionsCmdSet, (int)command); +// OleMenuCommand menuCommand = new OleMenuCommand((s, e) => Replace(callback), commandId); + +// menuCommand.BeforeQueryStatus += (s, e) => +// { +// string selection = GetTextDocument().Selection.Text; +// menuCommand.Enabled = selection.Length > 0 && callback(selection) != selection; +// }; + +// _mcs.AddCommand(menuCommand); +// } + +// private TextDocument GetTextDocument() +// { +// return _dte.ActiveDocument.Object("TextDocument") as TextDocument; +// } + +// private void Replace(Replacement callback) +// { +// TextDocument document = GetTextDocument(); +// string replacement = callback(document.Selection.Text); + +// _dte.UndoContext.Open(callback.Method.Name); +// document.Selection.Insert(replacement, 0); +// _dte.UndoContext.Close(); +// } +// } +//} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/JsHint.cs b/EditorExtensions/MenuItems/JsHint.cs new file mode 100644 index 000000000..9c9b6ec7a --- /dev/null +++ b/EditorExtensions/MenuItems/JsHint.cs @@ -0,0 +1,52 @@ +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.IO; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class JsHintMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + + public JsHintMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID commandId = new CommandID(GuidList.guidDiffCmdSet, (int)PkgCmdIDList.cmdJsHint); + OleMenuCommand menuCommand = new OleMenuCommand((s, e) => RunJsHint(), commandId); + menuCommand.BeforeQueryStatus += menuCommand_BeforeQueryStatus; + _mcs.AddCommand(menuCommand); + } + + private List files; + + void menuCommand_BeforeQueryStatus(object sender, System.EventArgs e) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + + var raw = MinifyFileMenu.GetSelectedFilePaths(_dte); + files = raw.Where(f => !JsHintRunner.ShouldIgnore(f)).ToList(); + + menuCommand.Enabled = files.Count > 0; + } + + private void RunJsHint() + { + JsHintRunner.Reset(); + + foreach (string file in files) + { + JsHintRunner runner = new JsHintRunner(file); + runner.RunCompiler(); + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/MarkdownStylesheet.cs b/EditorExtensions/MenuItems/MarkdownStylesheet.cs new file mode 100644 index 000000000..def2b71da --- /dev/null +++ b/EditorExtensions/MenuItems/MarkdownStylesheet.cs @@ -0,0 +1,45 @@ +using System.ComponentModel.Design; +using System.Linq; +using System.Text; +using EnvDTE; +using EnvDTE80; +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Shell; +using System; +using System.Collections.Generic; +using System.IO; + +namespace MadsKristensen.EditorExtensions +{ + internal class MarkdownStylesheetMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + + public MarkdownStylesheetMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID commandId = new CommandID(GuidList.guidDiffCmdSet, (int)PkgCmdIDList.cmdMarkdownStylesheet); + OleMenuCommand menuCommand = new OleMenuCommand((s, e) => AddStylesheet(), commandId); + menuCommand.BeforeQueryStatus += menuCommand_BeforeQueryStatus; + _mcs.AddCommand(menuCommand); + } + + void menuCommand_BeforeQueryStatus(object sender, System.EventArgs e) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + + menuCommand.Enabled = string.IsNullOrEmpty(MarkdownMargin.GetStylesheet()); + } + + private void AddStylesheet() + { + MarkdownMargin.CreateStylesheet(); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/MinifyFile.cs b/EditorExtensions/MenuItems/MinifyFile.cs new file mode 100644 index 000000000..036ee59fc --- /dev/null +++ b/EditorExtensions/MenuItems/MinifyFile.cs @@ -0,0 +1,224 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.Ajax.Utilities; +using Microsoft.VisualStudio.Shell; +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.IO; +using System.Linq; +using System.Windows; + +namespace MadsKristensen.EditorExtensions +{ + internal class MinifyFileMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + + public MinifyFileMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID commandCss = new CommandID(GuidList.guidMinifyCmdSet, (int)PkgCmdIDList.MinifyCss); + OleMenuCommand menuCommandCss = new OleMenuCommand((s, e) => MinifyFile(".css"), commandCss); + menuCommandCss.BeforeQueryStatus += (s, e) => { BeforeQueryStatus(s, ".css"); }; + _mcs.AddCommand(menuCommandCss); + + CommandID commandJs = new CommandID(GuidList.guidMinifyCmdSet, (int)PkgCmdIDList.MinifyJs); + OleMenuCommand menuCommandJs = new OleMenuCommand((s, e) => MinifyFile(".js"), commandJs); + menuCommandJs.BeforeQueryStatus += (s, e) => { BeforeQueryStatus(s, ".js"); }; + _mcs.AddCommand(menuCommandJs); + + //CommandID commandSelection = new CommandID(GuidList.guidMinifyCmdSet, (int)PkgCmdIDList.MinifySelection); + //OleMenuCommand menuCommandSelection = new OleMenuCommand((s, e) => MinifySelection(), commandSelection); + //menuCommandSelection.BeforeQueryStatus += menuCommandSelection_BeforeQueryStatus; + //_mcs.AddCommand(menuCommandSelection); + } + + private readonly string[] _supported = new[] { "CSS", "JAVASCRIPT" }; + + //void menuCommandSelection_BeforeQueryStatus(object sender, EventArgs e) + //{ + // OleMenuCommand menu = sender as OleMenuCommand; + // var view = ProjectHelpers.GetCurentTextView(); + + // if (view != null && view.Selection.SelectedSpans.Count > 0) + // { + // menu.Enabled = view.Selection.SelectedSpans[0].Length > 0; + // } + // else + // { + // menu.Enabled = false; + // } + //} + + void BeforeQueryStatus(object sender, string extension) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + var selectedPaths = GetSelectedFilePaths(_dte).Where(p => Path.GetExtension(p) == extension); + bool enabled = false; + + foreach (string path in selectedPaths) + { + string minFile = GetMinFileName(path, extension); + + if (!path.EndsWith(".min" + extension) && !File.Exists(minFile)) + { + enabled = true; + break; + } + } + + menuCommand.Enabled = enabled; + } + + //private void MinifySelection() + //{ + // var view = ProjectHelpers.GetCurentTextView(); + + // if (view != null) + // { + // _dte.UndoContext.Open("Minify"); + + // string content = view.Selection.SelectedSpans[0].GetText(); + // string extension = Path.GetExtension(_dte.ActiveDocument.FullName).ToLowerInvariant(); + // string result = MinifyString(extension, content); + + // view.TextBuffer.Replace(view.Selection.SelectedSpans[0].Span, result); + + // _dte.UndoContext.Close(); + // } + //} + + private void MinifyFile(string extension) + { + var selectedPaths = GetSelectedFilePaths(_dte); + + foreach (string path in selectedPaths.Where(p => p.EndsWith(extension, StringComparison.OrdinalIgnoreCase))) + { + string minPath = GetMinFileName(path, extension); + + if (!path.EndsWith(".min" + extension) && !File.Exists(minPath) && _dte.Solution.FindProjectItem(path) != null) + { + if (extension.Equals(".js", StringComparison.OrdinalIgnoreCase)) + { + JavaScriptSaveListener.Minify(path, minPath, false); + } + else + { + CssSaveListener.Minify(path, minPath); + } + + MarginBase.AddFileToProject(path, minPath); + } + } + + EnableSync(extension); + } + + private void EnableSync(string extension) + { + string message = string.Format("Do you also want to enable automatic minification when the source file changes?", extension); + + if (extension.Equals(".css", StringComparison.OrdinalIgnoreCase) && !WESettings.GetBoolean(WESettings.Keys.EnableCssMinification)) + { + var result = MessageBox.Show(message, "Web Essentials", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) + { + Settings.SetValue(WESettings.Keys.EnableCssMinification, true); + Settings.Save(); + } + } + else if (extension.Equals(".js", StringComparison.OrdinalIgnoreCase) && !WESettings.GetBoolean(WESettings.Keys.EnableJsMinification)) + { + var result = MessageBox.Show(message, "Web Essentials", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) + { + Settings.SetValue(WESettings.Keys.EnableJsMinification, true); + Settings.Save(); + } + } + } + + public static string GetMinFileName(string path, string extension) + { + return path.Insert(path.Length - extension.Length, ".min"); + } + + public static string MinifyString(string extension, string content) + { + if (extension == ".css") + { + Minifier minifier = new Minifier(); + CssSettings settings = new CssSettings(); + settings.CommentMode = CssComment.None; + + if (WESettings.GetBoolean(WESettings.Keys.KeepImportantComments)) + { + settings.CommentMode = CssComment.Important; + } + + return minifier.MinifyStyleSheet(content, settings); + } + else if (extension == ".js") + { + Minifier minifier = new Minifier(); + CodeSettings settings = new CodeSettings() + { + EvalTreatment = EvalTreatment.MakeImmediateSafe, + PreserveImportantComments = WESettings.GetBoolean(WESettings.Keys.KeepImportantComments) + }; + + return minifier.MinifyJavaScript(content, settings); + } + + return null; + } + + public static IEnumerable GetSelectedFilePaths(DTE2 dte) + { + var selectedPaths = GetSelectedItemPaths(dte); + List list = new List(); + + foreach (string path in selectedPaths) + { + string extension = Path.GetExtension(path); + + if (!string.IsNullOrEmpty(extension)) + { + // file + list.Add(path); + } + else + { + // Folder + if (Directory.Exists(path)) + { + list.AddRange(Directory.GetFiles(path)); + } + } + } + + return list; + } + + private static IEnumerable GetSelectedItemPaths(DTE2 dte) + { + var items = (Array)dte.ToolWindows.SolutionExplorer.SelectedItems; + foreach (UIHierarchyItem selItem in items) + { + var item = selItem.Object as ProjectItem; + if (item != null) + { + yield return item.Properties.Item("FullPath").Value.ToString(); + } + } + } + + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/ProjectSettings.cs b/EditorExtensions/MenuItems/ProjectSettings.cs new file mode 100644 index 000000000..03fb1f5c7 --- /dev/null +++ b/EditorExtensions/MenuItems/ProjectSettings.cs @@ -0,0 +1,95 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using System.ComponentModel.Design; +using System.IO; +using System.Windows.Forms; + +namespace MadsKristensen.EditorExtensions +{ + internal class ProjectSettingsMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + + public ProjectSettingsMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID commandSol = new CommandID(GuidList.guidDiffCmdSet, (int)PkgCmdIDList.cmdSolutionSettings); + OleMenuCommand menuCommandSol = new OleMenuCommand((s, e) => ApplySolutionSettings(), commandSol); + menuCommandSol.BeforeQueryStatus += SolutionBeforeQueryStatus; + _mcs.AddCommand(menuCommandSol); + + ProjectItemsEvents projectEvents = ((Events2)_dte.Events).ProjectItemsEvents; + projectEvents.ItemRemoved += ItemRemoved; + projectEvents.ItemRenamed += ItemRenamed; + + SolutionEvents solutionEvents = ((Events2)_dte.Events).SolutionEvents; + solutionEvents.ProjectRemoved += ProjectRemoved; + } + + private void SolutionBeforeQueryStatus(object sender, System.EventArgs e) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + bool settingsExist = Settings.SolutionSettingsExist; + + menuCommand.Enabled = !settingsExist; + } + + private void ApplySolutionSettings() + { + Settings.CreateSolutionSettings(); + } + + private void ItemRenamed(ProjectItem ProjectItem, string OldName) + { + if (OldName.EndsWith(Settings._fileName) || ProjectItem.Name == Settings._fileName) + Settings.UpdateCache(); + } + + private void ItemRemoved(ProjectItem ProjectItem) + { + if (ProjectItem.Name == Settings._fileName && + ProjectItem.ContainingProject != null && + ProjectItem.ContainingProject.Name == Settings._solutionFolder) + { + DeleteSolutionSettings(); + } + } + + private void ProjectRemoved(Project project) + { + if (project.Name == Settings._solutionFolder) + { + DeleteSolutionSettings(); + } + } + + private static void DeleteSolutionSettings() + { + string file = Settings.GetSolutionFilePath(); + + if (File.Exists(file)) + { + string text = "The Web Essentials setting file still exist in the solution folder.\r\n\r\nDo you want to delete it?"; + DialogResult result = MessageBox.Show(text, "Web Essentials", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + + if (result == DialogResult.Yes) + { + File.Delete(file); + Settings.UpdateCache(); + Settings.UpdateStatusBar("applied"); + } + else + { + Settings.UpdateStatusBar("still applies. The settings file still exist in the solution folder."); + } + } + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/SolutionColors.cs b/EditorExtensions/MenuItems/SolutionColors.cs new file mode 100644 index 000000000..769bbbc19 --- /dev/null +++ b/EditorExtensions/MenuItems/SolutionColors.cs @@ -0,0 +1,39 @@ +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using System.ComponentModel.Design; + +namespace MadsKristensen.EditorExtensions +{ + internal class SolutionColorsMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + + public SolutionColorsMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + CommandID commandSol = new CommandID(GuidList.guidDiffCmdSet, (int)PkgCmdIDList.cmdSolutionColors); + OleMenuCommand menuCommandSol = new OleMenuCommand((s, e) => ApplySolutionSettings(), commandSol); + menuCommandSol.BeforeQueryStatus += SolutionBeforeQueryStatus; + _mcs.AddCommand(menuCommandSol); + } + + private void SolutionBeforeQueryStatus(object sender, System.EventArgs e) + { + OleMenuCommand menuCommand = sender as OleMenuCommand; + bool settingsExist = XmlColorPaletteProvider.SolutionColorsExist; + + menuCommand.Enabled = !settingsExist; + } + + private void ApplySolutionSettings() + { + XmlColorPaletteProvider.CreateSolutionColors(); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/MenuItems/Transform.cs b/EditorExtensions/MenuItems/Transform.cs new file mode 100644 index 000000000..3212ce1f9 --- /dev/null +++ b/EditorExtensions/MenuItems/Transform.cs @@ -0,0 +1,99 @@ +using System; +using System.Security.Cryptography; +using System.Linq; +using System.ComponentModel.Design; +using System.Web; +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using System.Globalization; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + internal class TransformMenu + { + private DTE2 _dte; + private OleMenuCommandService _mcs; + private delegate string Replacement(string original); + + public TransformMenu(DTE2 dte, OleMenuCommandService mcs) + { + _dte = dte; + _mcs = mcs; + } + + public void SetupCommands() + { + SetupCommand(PkgCmdIDList.upperCaseTransform, new Replacement(x => x.ToUpperInvariant())); + SetupCommand(PkgCmdIDList.lowerCaseTransform, new Replacement(x => x.ToLowerInvariant())); + SetupCommand(PkgCmdIDList.titleCaseTransform, new Replacement(x => CultureInfo.InvariantCulture.TextInfo.ToTitleCase(x))); + SetupCommand(PkgCmdIDList.reverseTransform, new Replacement(x => new string(x.Reverse().ToArray()))); + SetupCommand(PkgCmdIDList.normalizeTransform, new Replacement(x => RemoveDiacritics(x))); + SetupCommand(PkgCmdIDList.md5Transform, new Replacement(x => Hash(x, new MD5CryptoServiceProvider()))); + SetupCommand(PkgCmdIDList.sha1Transform, new Replacement(x => Hash(x, new SHA1CryptoServiceProvider()))); + SetupCommand(PkgCmdIDList.sha256Transform, new Replacement(x => Hash(x, new SHA256CryptoServiceProvider()))); + SetupCommand(PkgCmdIDList.sha384Transform, new Replacement(x => Hash(x, new SHA384CryptoServiceProvider()))); + SetupCommand(PkgCmdIDList.sha512Transform, new Replacement(x => Hash(x, new SHA512CryptoServiceProvider()))); + } + + public static string RemoveDiacritics(string s) + { + string stFormD = s.Normalize(NormalizationForm.FormD); + StringBuilder sb = new StringBuilder(); + + for (int ich = 0; ich < stFormD.Length; ich++) + { + UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]); + if (uc != UnicodeCategory.NonSpacingMark) + { + sb.Append(stFormD[ich]); + } + } + + return (sb.ToString().Normalize(NormalizationForm.FormC)); + } + + private static string Hash(string original, HashAlgorithm algorithm) + { + byte[] hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(original)); + StringBuilder sb = new StringBuilder(); + + foreach (byte b in hash) + { + sb.Append(b.ToString("x2").ToLowerInvariant()); + } + + return sb.ToString(); + } + + private void SetupCommand(uint command, Replacement callback) + { + CommandID commandId = new CommandID(GuidList.guidEditorExtensionsCmdSet, (int)command); + OleMenuCommand menuCommand = new OleMenuCommand((s, e) => Replace(callback), commandId); + + menuCommand.BeforeQueryStatus += (s, e) => + { + string selection = GetTextDocument().Selection.Text; + menuCommand.Enabled = selection.Length > 0 && callback(selection) != selection; + }; + + _mcs.AddCommand(menuCommand); + } + + private TextDocument GetTextDocument() + { + return _dte.ActiveDocument.Object("TextDocument") as TextDocument; + } + + private void Replace(Replacement callback) + { + TextDocument document = GetTextDocument(); + string replacement = callback(document.Selection.Text); + + _dte.UndoContext.Open(callback.Method.Name); + document.Selection.Insert(replacement, 0); + _dte.UndoContext.Close(); + } + } +} \ No newline at end of file diff --git a/EditorExtensions/NavigateTo/GoToLineProviderFactory.cs b/EditorExtensions/NavigateTo/GoToLineProviderFactory.cs new file mode 100644 index 000000000..006d903dd --- /dev/null +++ b/EditorExtensions/NavigateTo/GoToLineProviderFactory.cs @@ -0,0 +1,189 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Language.NavigateTo.Interfaces; +using Microsoft.VisualStudio.PlatformUI; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Text.Outlining; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(INavigateToItemProviderFactory))] + internal sealed class GoToLineProviderFactory : INavigateToItemProviderFactory, INavigateToItemDisplayFactory + { + [Import] + internal IEditorOperationsFactoryService EditorOperationsFactoryService = null; + + [Import] + internal IOutliningManagerService OutliningManagerService = null; + + public bool TryCreateNavigateToItemProvider(IServiceProvider serviceProvider, out INavigateToItemProvider provider) + { + provider = new GoToLineProvider(this); + return true; + } + + public INavigateToItemDisplay CreateItemDisplay(NavigateToItem item) + { + return item.Tag as INavigateToItemDisplay; + } + } + + internal sealed class GoToLineProvider : DisposableObject, INavigateToItemProvider + { + private readonly GoToLineProviderFactory _owner; + + public GoToLineProvider(GoToLineProviderFactory owner) + { + _owner = owner; + } + + public void StartSearch(INavigateToCallback callback, string searchValue) + { + CssParser parser = new CssParser(); + var state = new Tuple(parser, searchValue, callback); + + System.Threading.ThreadPool.QueueUserWorkItem(DoWork, state); + } + + public void DoWork(object state) + { + var tuple = (Tuple)state; + var parser = tuple.Item1; + var searchValue = tuple.Item2; + var callback = tuple.Item3; + + try + { + IEnumerable files = GetFiles(); + + Parallel.For(0, files.Count(), i => + { + string file = files.ElementAt(i); + + IEnumerable items = GetItems(file, parser, searchValue); + + foreach (ParseItem sel in items) + { + callback.AddItem(new NavigateToItem(searchValue, NavigateToItemKind.Field, null, searchValue, new GoToLineTag(sel, file), MatchKind.Exact, _owner)); + } + + callback.ReportProgress(i, files.Count()); + }); + } + catch { } + finally + { + callback.Done(); + } + } + + public void StopSearch() + { + } + + private IEnumerable GetItems(string file, CssParser parser, string searchValue) + { + StyleSheet ss = parser.Parse(File.ReadAllText(file), true); + + var visitorClass = new CssItemCollector(true); + ss.Accept(visitorClass); + + var classes = from c in visitorClass.Items + where c.Text.Contains(searchValue) + select c; + + var visitorIDs = new CssItemCollector(true); + ss.Accept(visitorIDs); + + var ids = from c in visitorIDs.Items + where c.Text.Contains(searchValue) + select c; + + List list = new List(); + list.AddRange(classes); + list.AddRange(ids); + + return list; + } + + private IEnumerable GetFiles() + { + string[] files = Directory.GetFiles(ProjectHelpers.GetRootFolder(), "*.css", SearchOption.AllDirectories); + + foreach (string file in files) + { + if (!file.Contains(".min.") && !file.Contains(".bundle.")) + yield return file; + } + } + } + + internal class GoToLineTag : INavigateToItemDisplay + { + private ParseItem _selector; + private string _file; + + public GoToLineTag(ParseItem selector, string file) + { + _selector = selector; + _file = file; + } + + public string AdditionalInformation + { + get + { + return "CSS selector - " + Path.GetFileName(_file); + } + } + + public string Description + { + get + { + return _selector.Text; + } + } + + public System.Collections.ObjectModel.ReadOnlyCollection DescriptionItems + { + get { return null; } + } + + public System.Drawing.Icon Glyph + { + get { return null; } + } + + public string Name + { + get { return _selector.FindType().Text; } + } + + public void NavigateTo() + { + EditorExtensionsPackage.DTE.ItemOperations.OpenFile(_file); + + Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => + { + var view = ProjectHelpers.GetCurentTextView(); + var textBuffer = ProjectHelpers.GetCurentTextBuffer(); + var span = new SnapshotSpan(textBuffer.CurrentSnapshot, _selector.Start, _selector.Length); + var point = new SnapshotPoint(textBuffer.CurrentSnapshot, _selector.Start + _selector.Length); + + view.ViewScroller.EnsureSpanVisible(span); + view.Caret.MoveTo(point); + view.Selection.Select(span, false); + + + }), DispatcherPriority.ApplicationIdle, null); + } + } +} diff --git a/EditorExtensions/Options/CoffeeScript.cs b/EditorExtensions/Options/CoffeeScript.cs new file mode 100644 index 000000000..1974c3575 --- /dev/null +++ b/EditorExtensions/Options/CoffeeScript.cs @@ -0,0 +1,72 @@ +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class CoffeeScriptOptions : DialogPage + { + public CoffeeScriptOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.GenerateJsFileFromCoffeeScript, GenerateJsFileFromCoffeeScript); + Settings.SetValue(WESettings.Keys.ShowCoffeeScriptPreviewWindow, ShowCoffeeScriptPreviewWindow); + Settings.SetValue(WESettings.Keys.WrapCoffeeScriptClosure, WrapCoffeeScriptClosure); + Settings.SetValue(WESettings.Keys.CoffeeScriptMinify, CoffeeScriptMinify); + Settings.SetValue(WESettings.Keys.EnableIcedCoffeeScript, EnableIcedCoffeeScript); + Settings.SetValue(WESettings.Keys.CoffeeScriptCompileToFolder, CoffeeScriptCompileToFolder); + Settings.SetValue(WESettings.Keys.CoffeeScriptCompileOnBuild, CoffeeScriptCompileOnBuild); + + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + GenerateJsFileFromCoffeeScript = WESettings.GetBoolean(WESettings.Keys.GenerateJsFileFromCoffeeScript); + ShowCoffeeScriptPreviewWindow = WESettings.GetBoolean(WESettings.Keys.ShowCoffeeScriptPreviewWindow); + WrapCoffeeScriptClosure = WESettings.GetBoolean(WESettings.Keys.WrapCoffeeScriptClosure); + CoffeeScriptMinify = WESettings.GetBoolean(WESettings.Keys.CoffeeScriptMinify); + EnableIcedCoffeeScript = WESettings.GetBoolean(WESettings.Keys.EnableIcedCoffeeScript); + CoffeeScriptCompileToFolder = WESettings.GetBoolean(WESettings.Keys.CoffeeScriptCompileToFolder); + CoffeeScriptCompileOnBuild = WESettings.GetBoolean(WESettings.Keys.CoffeeScriptCompileOnBuild); + } + + [LocDisplayName("Generate JavaScript file on save")] + [Description("Generate JavaScript file when CoffeeScript file is saved")] + [Category("CoffeeScript")] + public bool GenerateJsFileFromCoffeeScript { get; set; } + + [LocDisplayName("Show preview window")] + [Description("Show the preview window when editing a CoffeeScript file.")] + [Category("CoffeeScript")] + public bool ShowCoffeeScriptPreviewWindow { get; set; } + + [LocDisplayName("Wrap generated JavaScript")] + [Description("Wrap the generated JavaScript in an anonymous function.")] + [Category("CoffeeScript")] + public bool WrapCoffeeScriptClosure { get; set; } + + [LocDisplayName("Enable Iced CoffeeScript")] + [Description("Switches to use the Iced CoffeeScript compiler.")] + [Category("CoffeeScript")] + public bool EnableIcedCoffeeScript { get; set; } + + [LocDisplayName("Minify generated JavaScript")] + [Description("Creates a minified version of the compiled JavaScript file (file.min.js)")] + [Category("CoffeeScript")] + public bool CoffeeScriptMinify { get; set; } + + [LocDisplayName("Compile to 'js' folder")] + [Description("Compiles all CoffeeScript files into a folder called 'js' in the same directory as the .coffee file")] + [Category("CoffeeScript")] + public bool CoffeeScriptCompileToFolder { get; set; } + + [LocDisplayName("Compile on build")] + [Description("Compiles all CoffeeScript files in the project that has a corresponding .js file.")] + [Category("CoffeeScript")] + public bool CoffeeScriptCompileOnBuild { get; set; } + } +} diff --git a/EditorExtensions/Options/Css.cs b/EditorExtensions/Options/Css.cs new file mode 100644 index 000000000..eaa25b74e --- /dev/null +++ b/EditorExtensions/Options/Css.cs @@ -0,0 +1,135 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class CssOptions : DialogPage + { + public CssOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.EnableCssSelectorHighligting, EnableCssSelectorHighligting); + Settings.SetValue(WESettings.Keys.AutoCloseCurlyBraces, AutoCloseCurlyBraces); + Settings.SetValue(WESettings.Keys.EnableCssMinification, EnableCssMinification); + Settings.SetValue(WESettings.Keys.ValidateStarSelector, ValidateStarSelector); + Settings.SetValue(WESettings.Keys.ValidateOverQualifiedSelector, ValidateOverQualifiedSelector); + Settings.SetValue(WESettings.Keys.CssErrorLocation, (int)CssErrorLocation); + Settings.SetValue(WESettings.Keys.OnlyW3cAllowed, OnlyW3cAllowed); + Settings.SetValue(WESettings.Keys.SyncVendorValues, SyncVendorValues); + Settings.SetValue(WESettings.Keys.ShowInitialInherit, ShowInitialInherit); + Settings.SetValue(WESettings.Keys.ShowUnsupported, ShowUnsupported); + Settings.SetValue(WESettings.Keys.ShowBrowserTooltip, ShowBrowserTooltip); + Settings.SetValue(WESettings.Keys.ValidateZeroUnit, ValidateZeroUnit); + Settings.SetValue(WESettings.Keys.ValidateVendorSpecifics, ValidateVendorSpecifics); + Settings.SetValue(WESettings.Keys.EnableSpeedTyping, EnableSpeedTyping); + + OnChanged(); + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + EnableCssSelectorHighligting = WESettings.GetBoolean(WESettings.Keys.EnableCssSelectorHighligting); + AutoCloseCurlyBraces = WESettings.GetBoolean(WESettings.Keys.AutoCloseCurlyBraces); + EnableCssMinification = WESettings.GetBoolean(WESettings.Keys.EnableCssMinification); + ValidateStarSelector = WESettings.GetBoolean(WESettings.Keys.ValidateStarSelector); + ValidateOverQualifiedSelector = WESettings.GetBoolean(WESettings.Keys.ValidateOverQualifiedSelector); + CssErrorLocation = (WESettings.Keys.ErrorLocation)WESettings.GetInt(WESettings.Keys.CssErrorLocation); + OnlyW3cAllowed = WESettings.GetBoolean(WESettings.Keys.OnlyW3cAllowed); + SyncVendorValues = WESettings.GetBoolean(WESettings.Keys.SyncVendorValues); + ShowInitialInherit = WESettings.GetBoolean(WESettings.Keys.ShowInitialInherit); + ShowUnsupported = WESettings.GetBoolean(WESettings.Keys.ShowUnsupported); + ValidateEmbedImages = WESettings.GetBoolean(WESettings.Keys.ValidateEmbedImages); + ShowBrowserTooltip = WESettings.GetBoolean(WESettings.Keys.ShowBrowserTooltip); + ValidateZeroUnit = WESettings.GetBoolean(WESettings.Keys.ValidateZeroUnit); + ValidateVendorSpecifics = WESettings.GetBoolean(WESettings.Keys.ValidateVendorSpecifics); + EnableSpeedTyping = WESettings.GetBoolean(WESettings.Keys.EnableSpeedTyping); + } + + protected void OnChanged() + { + CssSchemaManager.SchemaManager.ReloadSchemas(); + } + + [LocDisplayName("Enable selector highlighting")] + [Description("Highlight matching simple selectors when cursor position changes")] + [Category("Misc")] + public bool EnableCssSelectorHighligting { get; set; } + + [LocDisplayName("Auto-close curly braces")] + [Description("when a open curly brace is typed, the closing curly is inserted automatically and type-through is enabled.")] + [Category("Misc")] + public bool AutoCloseCurlyBraces { get; set; } + + [LocDisplayName("Minify CSS files on save")] + [Description("When a .css file (foo.css) is saved and a minified version (foo.min.css) exist, the minified file will be updated. Right-click any .css file to generate .min.css file")] + [Category("Misc")] + public bool EnableCssMinification { get; set; } + + [LocDisplayName("Enable Speed Typing")] + [Description("Speed Typing makes it easier to write CSS by eliminating the need for typing curlies, colons and semi-colons.")] + [Category("Misc")] + public bool EnableSpeedTyping { get; set; } + + [LocDisplayName("Disallow universal selector")] + [Description("Disallow the universal, also known as the star selector")] + [Category("Performance")] + public bool ValidateStarSelector { get; set; } + + [LocDisplayName("Disallow over qualified ID selector")] + [Description("Disallow the use of over qualifed ID selectors.")] + [Category("Performance")] + public bool ValidateOverQualifiedSelector { get; set; } + + [LocDisplayName("Small images should be inlined")] + [Description("Small images should be base64 encoded and embedded directly into the stylesheet as dataURIs.")] + [Category("Performance")] + public bool ValidateEmbedImages { get; set; } + + [LocDisplayName("Validation location")] + [Description("Controls where errors are located. To use the 'Errors' output window, select 'Warnings' and change the Visual Studio CSS settings to use 'Errors'")] + [Category("Validation")] + public WESettings.Keys.ErrorLocation CssErrorLocation { get; set; } + + [LocDisplayName("Only allow W3C values")] + [Description("Ensures that the stylesheet only uses properties, @-directives, pseudos and values defined by the W3C.")] + [Category("Validation")] + public bool OnlyW3cAllowed { get; set; } + + [LocDisplayName("Validate vendor specifics")] + [Description("Validates vendor specific properties, psuedos and @-directives.")] + [Category("Validation")] + public bool ValidateVendorSpecifics { get; set; } + + [LocDisplayName("Sync vendor specific values")] + [Description("Syncronizes vendor specific property values when the standard property is being modified")] + [Category("Intellisense")] + public bool SyncVendorValues { get; set; } + + [LocDisplayName("Show initial/inherit")] + [Description("Shows or hides the global property values 'initial' and 'inherit'. They are still valid to use.")] + [Category("Intellisense")] + public bool ShowInitialInherit { get; set; } + + [LocDisplayName("Show unsupported")] + [Description("Shows the property names, values and pseudos that aren't supported by any browser yet.")] + [Category("Intellisense")] + public bool ShowUnsupported { get; set; } + + [LocDisplayName("Show browser support")] + [Description("Shows the browser support when the mouse is hovering over any CSS property.")] + [Category("Intellisense")] + public bool ShowBrowserTooltip { get; set; } + + [LocDisplayName("Disallow units for 0 values")] + [Description("The value of 0 works without specifying units in all situations where numbers with units or percentages are allowed")] + [Category("Performance")] + public bool ValidateZeroUnit { get; set; } + } +} \ No newline at end of file diff --git a/EditorExtensions/Options/General.cs b/EditorExtensions/Options/General.cs new file mode 100644 index 000000000..738588d4d --- /dev/null +++ b/EditorExtensions/Options/General.cs @@ -0,0 +1,45 @@ +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class GeneralOptions : DialogPage + { + public GeneralOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.EnableMustache, EnableMustache); + Settings.SetValue(WESettings.Keys.EnableHtmlZenCoding, EnableHtmlZenCoding); + Settings.SetValue(WESettings.Keys.KeepImportantComments, KeepImportantComments); + + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + EnableMustache = WESettings.GetBoolean(WESettings.Keys.EnableMustache); + EnableHtmlZenCoding = WESettings.GetBoolean(WESettings.Keys.EnableHtmlZenCoding); + KeepImportantComments = WESettings.GetBoolean(WESettings.Keys.KeepImportantComments); + } + + // MISC + [LocDisplayName("Enable Mustache/Handlebars")] + [Description("Enable colorization Mustache/Handlebars syntax in the HTML editor")] + [Category("Misc")] + public bool EnableMustache { get; set; } + + [LocDisplayName("Enable HTML ZenCoding")] + [Description("Enables ZenCoding in the HTML editor")] + [Category("Misc")] + public bool EnableHtmlZenCoding { get; set; } + + [LocDisplayName("Keep important comments")] + [Description("Don't strip important comments when minifying JS and CSS. Important comments follows this pattern: /*! text */")] + [Category("Minification")] + public bool KeepImportantComments { get; set; } + } +} diff --git a/EditorExtensions/Options/JavaScript.cs b/EditorExtensions/Options/JavaScript.cs new file mode 100644 index 000000000..f2c61f47b --- /dev/null +++ b/EditorExtensions/Options/JavaScript.cs @@ -0,0 +1,59 @@ +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class JavaScriptOptions : DialogPage + { + public JavaScriptOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.EnableJavascriptRegions, EnableJavascriptRegions); + Settings.SetValue(WESettings.Keys.EnableJsMinification, EnableJsMinification); + Settings.SetValue(WESettings.Keys.GenerateJavaScriptSourceMaps, GenerateJavaScriptSourceMaps); + Settings.SetValue(WESettings.Keys.JavaScriptAutoCloseBraces, JavaScriptAutoCloseBraces); + Settings.SetValue(WESettings.Keys.JavaScriptOutlining, JavaScriptOutlining); + + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + EnableJavascriptRegions = WESettings.GetBoolean(WESettings.Keys.EnableJavascriptRegions); + EnableJsMinification = WESettings.GetBoolean(WESettings.Keys.EnableJsMinification); + GenerateJavaScriptSourceMaps = WESettings.GetBoolean(WESettings.Keys.GenerateJavaScriptSourceMaps); + JavaScriptAutoCloseBraces = WESettings.GetBoolean(WESettings.Keys.JavaScriptAutoCloseBraces); + JavaScriptOutlining = WESettings.GetBoolean(WESettings.Keys.JavaScriptOutlining); + } + + + [LocDisplayName("Enable JavaScript regions")] + [Description("Enable regions using this syntax: '//#region Name' followed by '//#endregion'")] + [Category("JavaScript")] + public bool EnableJavascriptRegions { get; set; } + + [LocDisplayName("Minify JavaScript files on save")] + [Description("When a .js file (foo.js) is saved and a minified version (foo.min.js) exist, the minified file will be updated. Right-click any .js file to generate .min.js file")] + [Category("JavaScript")] + public bool EnableJsMinification { get; set; } + + [LocDisplayName("Generate source maps (.map)")] + [Description("When minification is enabled, a source map file (*.min.js.map) is generated.")] + [Category("JavaScript")] + public bool GenerateJavaScriptSourceMaps { get; set; } + + [LocDisplayName("Auto-close braces")] + [Description("Automatically inserts closing braces as provisional text. Braces are: ], ) and }")] + [Category("JavaScript")] + public bool JavaScriptAutoCloseBraces { get; set; } + + [LocDisplayName("Enable outlining/folding")] + [Description("Enables outlining for any non-function structures. Enabling can collide with other extensions.")] + [Category("JavaScript")] + public bool JavaScriptOutlining { get; set; } + } +} diff --git a/EditorExtensions/Options/JsHint.cs b/EditorExtensions/Options/JsHint.cs new file mode 100644 index 000000000..edad031f2 --- /dev/null +++ b/EditorExtensions/Options/JsHint.cs @@ -0,0 +1,466 @@ +using Microsoft.VisualStudio.Shell; +using System; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class JsHintOptions : DialogPage + { + public JsHintOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.JsHint_maxerr, JsHint_maxerr); + Settings.SetValue(WESettings.Keys.RunJsHintOnBuild, RunJsHintOnBuild); + Settings.SetValue(WESettings.Keys.EnableJsHint, EnableJsHint); + Settings.SetValue(WESettings.Keys.JsHintErrorLocation, (int)ErrorLocation); + + Settings.SetValue(WESettings.Keys.JsHint_bitwise, JsHint_bitwise); + Settings.SetValue(WESettings.Keys.JsHint_camelcase, JsHint_camelcase); + Settings.SetValue(WESettings.Keys.JsHint_curly, JsHint_curly); + Settings.SetValue(WESettings.Keys.JsHint_eqeqeq, JsHint_eqeqeq); + Settings.SetValue(WESettings.Keys.JsHint_forin, JsHint_forin); + Settings.SetValue(WESettings.Keys.JsHint_immed, JsHint_immed); + Settings.SetValue(WESettings.Keys.JsHint_indent, JsHint_indent); + Settings.SetValue(WESettings.Keys.JsHint_latedef, JsHint_latedef); + Settings.SetValue(WESettings.Keys.JsHint_newcap, JsHint_newcap); + Settings.SetValue(WESettings.Keys.JsHint_noarg, JsHint_noarg); + Settings.SetValue(WESettings.Keys.JsHint_noempty, JsHint_noempty); + Settings.SetValue(WESettings.Keys.JsHint_nonew, JsHint_nonew); + Settings.SetValue(WESettings.Keys.JsHint_plusplus, JsHint_plusplus); + Settings.SetValue(WESettings.Keys.JsHint_quotmark, JsHint_quotmark); + Settings.SetValue(WESettings.Keys.JsHint_regexp, JsHint_regexp); + Settings.SetValue(WESettings.Keys.JsHint_undef, JsHint_undef); + Settings.SetValue(WESettings.Keys.JsHint_unused, JsHint_unused); + Settings.SetValue(WESettings.Keys.JsHint_strict, JsHint_strict); + Settings.SetValue(WESettings.Keys.JsHint_trailing, JsHint_trailing); + + Settings.SetValue(WESettings.Keys.JsHint_asi, JsHint_asi); + Settings.SetValue(WESettings.Keys.JsHint_boss, JsHint_boss); + Settings.SetValue(WESettings.Keys.JsHint_debug, JsHint_debug); + Settings.SetValue(WESettings.Keys.JsHint_eqnull, JsHint_eqnull); + Settings.SetValue(WESettings.Keys.JsHint_es5, JsHint_es5); + Settings.SetValue(WESettings.Keys.JsHint_esnext, JsHint_esnext); + Settings.SetValue(WESettings.Keys.JsHint_evil, JsHint_evil); + Settings.SetValue(WESettings.Keys.JsHint_expr, JsHint_expr); + Settings.SetValue(WESettings.Keys.JsHint_funcscope, JsHint_funcscope); + Settings.SetValue(WESettings.Keys.JsHint_globalstrict, JsHint_globalstrict); + Settings.SetValue(WESettings.Keys.JsHint_iterator, JsHint_iterator); + Settings.SetValue(WESettings.Keys.JsHint_lastsemic, JsHint_lastsemic); + Settings.SetValue(WESettings.Keys.JsHint_laxbreak, JsHint_laxbreak); + Settings.SetValue(WESettings.Keys.JsHint_laxcomma, JsHint_laxcomma); + Settings.SetValue(WESettings.Keys.JsHint_loopfunc, JsHint_loopfunc); + Settings.SetValue(WESettings.Keys.JsHint_multistr, JsHint_multistr); + Settings.SetValue(WESettings.Keys.JsHint_onecase, JsHint_onecase); + Settings.SetValue(WESettings.Keys.JsHint_proto, JsHint_proto); + Settings.SetValue(WESettings.Keys.JsHint_regexdash, JsHint_regexdash); + Settings.SetValue(WESettings.Keys.JsHint_scripturl, JsHint_scripturl); + Settings.SetValue(WESettings.Keys.JsHint_smarttabs, JsHint_smarttabs); + Settings.SetValue(WESettings.Keys.JsHint_shadow, JsHint_shadow); + Settings.SetValue(WESettings.Keys.JsHint_sub, JsHint_sub); + Settings.SetValue(WESettings.Keys.JsHint_supernew, JsHint_supernew); + Settings.SetValue(WESettings.Keys.JsHint_validthis, JsHint_validthis); + + Settings.SetValue(WESettings.Keys.JsHint_browser, JsHint_browser); + Settings.SetValue(WESettings.Keys.JsHint_couch, JsHint_couch); + Settings.SetValue(WESettings.Keys.JsHint_devel, JsHint_devel); + Settings.SetValue(WESettings.Keys.JsHint_dojo, JsHint_dojo); + Settings.SetValue(WESettings.Keys.JsHint_mootools, JsHint_mootools); + Settings.SetValue(WESettings.Keys.JsHint_node, JsHint_node); + Settings.SetValue(WESettings.Keys.JsHint_nonstandard, JsHint_nonstandard); + Settings.SetValue(WESettings.Keys.JsHint_prototypejs, JsHint_prototypejs); + Settings.SetValue(WESettings.Keys.JsHint_rhino, JsHint_rhino); + Settings.SetValue(WESettings.Keys.JsHint_worker, JsHint_worker); + Settings.SetValue(WESettings.Keys.JsHint_wsh, JsHint_wsh); + + OnChanged(); + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + EnableJsHint = WESettings.GetBoolean(WESettings.Keys.EnableJsHint); + RunJsHintOnBuild = WESettings.GetBoolean(WESettings.Keys.RunJsHintOnBuild); + ErrorLocation = (WESettings.Keys.FullErrorLocation)WESettings.GetInt(WESettings.Keys.JsHintErrorLocation); + JsHint_maxerr = WESettings.GetInt(WESettings.Keys.JsHint_maxerr); + + JsHint_bitwise = WESettings.GetBoolean(WESettings.Keys.JsHint_bitwise); + JsHint_camelcase = WESettings.GetBoolean(WESettings.Keys.JsHint_camelcase); + JsHint_curly = WESettings.GetBoolean(WESettings.Keys.JsHint_curly); + JsHint_eqeqeq = WESettings.GetBoolean(WESettings.Keys.JsHint_eqeqeq); + JsHint_forin = WESettings.GetBoolean(WESettings.Keys.JsHint_forin); + JsHint_immed = WESettings.GetBoolean(WESettings.Keys.JsHint_immed); + JsHint_indent = WESettings.GetInt(WESettings.Keys.JsHint_indent); + JsHint_latedef = WESettings.GetBoolean(WESettings.Keys.JsHint_latedef); + JsHint_newcap = WESettings.GetBoolean(WESettings.Keys.JsHint_newcap); + JsHint_noarg = WESettings.GetBoolean(WESettings.Keys.JsHint_noarg); + JsHint_noempty = WESettings.GetBoolean(WESettings.Keys.JsHint_noempty); + JsHint_nonew = WESettings.GetBoolean(WESettings.Keys.JsHint_nonew); + JsHint_plusplus = WESettings.GetBoolean(WESettings.Keys.JsHint_plusplus); + JsHint_quotmark = WESettings.GetBoolean(WESettings.Keys.JsHint_quotmark); + JsHint_regexp = WESettings.GetBoolean(WESettings.Keys.JsHint_regexp); + JsHint_undef = WESettings.GetBoolean(WESettings.Keys.JsHint_undef); + JsHint_unused = WESettings.GetBoolean(WESettings.Keys.JsHint_unused); + JsHint_strict = WESettings.GetBoolean(WESettings.Keys.JsHint_strict); + JsHint_trailing = WESettings.GetBoolean(WESettings.Keys.JsHint_trailing); + + JsHint_asi = WESettings.GetBoolean(WESettings.Keys.JsHint_asi); + JsHint_boss = WESettings.GetBoolean(WESettings.Keys.JsHint_boss); + JsHint_debug = WESettings.GetBoolean(WESettings.Keys.JsHint_debug); + JsHint_eqnull = WESettings.GetBoolean(WESettings.Keys.JsHint_eqnull); + JsHint_es5 = WESettings.GetBoolean(WESettings.Keys.JsHint_es5); + JsHint_esnext = WESettings.GetBoolean(WESettings.Keys.JsHint_esnext); + JsHint_evil = WESettings.GetBoolean(WESettings.Keys.JsHint_evil); + JsHint_expr = WESettings.GetBoolean(WESettings.Keys.JsHint_expr); + JsHint_funcscope = WESettings.GetBoolean(WESettings.Keys.JsHint_funcscope); + JsHint_globalstrict = WESettings.GetBoolean(WESettings.Keys.JsHint_globalstrict); + JsHint_iterator = WESettings.GetBoolean(WESettings.Keys.JsHint_iterator); + JsHint_lastsemic = WESettings.GetBoolean(WESettings.Keys.JsHint_lastsemic); + JsHint_laxbreak = WESettings.GetBoolean(WESettings.Keys.JsHint_laxbreak); + JsHint_laxcomma = WESettings.GetBoolean(WESettings.Keys.JsHint_laxcomma); + JsHint_loopfunc = WESettings.GetBoolean(WESettings.Keys.JsHint_loopfunc); + JsHint_multistr = WESettings.GetBoolean(WESettings.Keys.JsHint_multistr); + JsHint_onecase = WESettings.GetBoolean(WESettings.Keys.JsHint_onecase); + JsHint_proto = WESettings.GetBoolean(WESettings.Keys.JsHint_proto); + JsHint_regexdash = WESettings.GetBoolean(WESettings.Keys.JsHint_regexdash); + JsHint_scripturl = WESettings.GetBoolean(WESettings.Keys.JsHint_scripturl); + JsHint_smarttabs = WESettings.GetBoolean(WESettings.Keys.JsHint_smarttabs); + JsHint_shadow = WESettings.GetBoolean(WESettings.Keys.JsHint_shadow); + JsHint_sub = WESettings.GetBoolean(WESettings.Keys.JsHint_sub); + JsHint_supernew = WESettings.GetBoolean(WESettings.Keys.JsHint_supernew); + JsHint_validthis = WESettings.GetBoolean(WESettings.Keys.JsHint_validthis); + + JsHint_browser = WESettings.GetBoolean(WESettings.Keys.JsHint_browser); + JsHint_couch = WESettings.GetBoolean(WESettings.Keys.JsHint_couch); + JsHint_devel = WESettings.GetBoolean(WESettings.Keys.JsHint_devel); + JsHint_dojo = WESettings.GetBoolean(WESettings.Keys.JsHint_dojo); + JsHint_jquery = WESettings.GetBoolean(WESettings.Keys.JsHint_jquery); + JsHint_mootools = WESettings.GetBoolean(WESettings.Keys.JsHint_mootools); + JsHint_node = WESettings.GetBoolean(WESettings.Keys.JsHint_node); + JsHint_nonstandard = WESettings.GetBoolean(WESettings.Keys.JsHint_nonstandard); + JsHint_prototypejs = WESettings.GetBoolean(WESettings.Keys.JsHint_prototypejs); + JsHint_rhino = WESettings.GetBoolean(WESettings.Keys.JsHint_rhino); + JsHint_worker = WESettings.GetBoolean(WESettings.Keys.JsHint_worker); + JsHint_wsh = WESettings.GetBoolean(WESettings.Keys.JsHint_wsh); + } + + public static event EventHandler Changed; + + protected void OnChanged() + { + if (Changed != null) + { + Changed(this, EventArgs.Empty); + } + } + + [LocDisplayName("Maximum number of errors")] + [Description("This option suppresses warnings about mixed tabs and spaces when the latter are used for alignmnent only.")] + [Category("Common")] + public int JsHint_maxerr { get; set; } + + [LocDisplayName("Enable JSHint")] + [Description("Runs JSHint in any open .js file when saved.")] + [Category("Common")] + public bool EnableJsHint { get; set; } + + [LocDisplayName("Run on build")] + [Description("Runs JSHint on all .js files in the active project on build")] + [Category("Common")] + public bool RunJsHintOnBuild { get; set; } + + [LocDisplayName("Error location")] + [Description("Determins where to output the JSHint errors")] + [Category("Common")] + public WESettings.Keys.FullErrorLocation ErrorLocation { get; set; } + + // Enforcing Options + + [LocDisplayName("Disallow bitwise operators")] + [Description("[bitwise] This option prohibits the use of bitwise operators such as ^ (XOR), | (OR) and others. Bitwise operators are very rare in JavaScript programs and very often & is simply a mistyped &&&&.")] + [Category("Enforcing Options")] + public bool JsHint_bitwise { get; set; } + + [LocDisplayName("Require camelcasing")] + [Description("[camelcase] This option allows you to force all variable names to use either camelCase style or UPPER_CASE with underscores.")] + [Category("Enforcing Options")] + public bool JsHint_camelcase { get; set; } + + [LocDisplayName("Enforce curly braces")] + [Description("[curly] This option requires you to always put curly braces around blocks in loops and conditionals. JavaScript allows you to omit curly braces when the block consists of only one statement.")] + [Category("Enforcing Options")] + public bool JsHint_curly { get; set; } + + [LocDisplayName("Disallow == and !=")] + [Description("[eqeqeq] This options prohibits the use of == and != in favor of === and !==.")] + [Category("Enforcing Options")] + public bool JsHint_eqeqeq { get; set; } + + [LocDisplayName("Filter for-in loops")] + [Description("[forin] This option requires all for in loops to filter object's items.")] + [Category("Enforcing Options")] + public bool JsHint_forin { get; set; } + + [LocDisplayName("Enforce invocation parentheses")] + [Description("[immed] This option prohibits the use of immediate function invocations without wrapping them in parentheses.")] + [Category("Enforcing Options")] + public bool JsHint_immed { get; set; } + + [LocDisplayName("Enforce indent size (-1 to disable)")] + [Description("[indent] This option enforces specific tab width for your code.")] + [Category("Enforcing Options")] + public int JsHint_indent { get; set; } + + [LocDisplayName("Declare param before use")] + [Description("[latedef] This option prohibits the use of a variable before it was defined.")] + [Category("Enforcing Options")] + public bool JsHint_latedef { get; set; } + + [LocDisplayName("Capitalize constructor functions")] + [Description("[newcap] This option requires you to capitalize names of constructor functions.")] + [Category("Enforcing Options")] + public bool JsHint_newcap { get; set; } + + [LocDisplayName("Disallow arguments.caller/callee")] + [Description("[noarg] This option prohibits the use of arguments.caller and arguments.callee.")] + [Category("Enforcing Options")] + public bool JsHint_noarg { get; set; } + + [LocDisplayName("No empty code blocks")] + [Description("[noempty] This option warns when you have an empty block in your code.")] + [Category("Enforcing Options")] + public bool JsHint_noempty { get; set; } + + [LocDisplayName("Disallow constructor functions")] + [Description("[nonew] This option prohibits the use of constructor functions for side-effects.")] + [Category("Enforcing Options")] + public bool JsHint_nonew { get; set; } + + [LocDisplayName("Disallow ++ and -- operators")] + [Description("[plusplus] This option prohibits the use of unary increment and decrement operators.")] + [Category("Enforcing Options")] + public bool JsHint_plusplus { get; set; } + + [LocDisplayName("Use consistant quotation")] + [Description("[quotmark] This option enforces the consistency of quotation marks used throughout your code.")] + [Category("Enforcing Options")] + public bool JsHint_quotmark { get; set; } + + [LocDisplayName("Disallow . in regex")] + [Description("[regexp] This option prohibits the use of unsafe . in regular expressions.")] + [Category("Enforcing Options")] + public bool JsHint_regexp { get; set; } + + [LocDisplayName("Disallow use of undeclared var")] + [Description("[undef] This option prohibits the use of explicitly undeclared variables. This option is very useful for spotting leaking and mistyped variables.")] + [Category("Enforcing Options")] + public bool JsHint_undef { get; set; } + + [LocDisplayName("Disallow unused variables")] + [Description("[unused] This option warns when you define and never use your variables. It is very useful for general code cleanup, especially when used in addition to undef.")] + [Category("Enforcing Options")] + public bool JsHint_unused { get; set; } + + [LocDisplayName("Require 'strict mode'")] + [Description("[strict] This option requires all functions to run in EcmaScript 5's strict mode.")] + [Category("Enforcing Options")] + public bool JsHint_strict { get; set; } + + [LocDisplayName("Disallow trailing whitespace")] + [Description("[trailing] This option makes it an error to leave a trailing whitespace in your code. Trailing whitespaces can be source of nasty bugs with multi-line strings.")] + [Category("Enforcing Options")] + public bool JsHint_trailing { get; set; } + + // Relaxing Options + + [LocDisplayName("Allow missing semicolons")] + [Description("[asi] This option suppresses warnings about missing semicolons.")] + [Category("Relaxing Options")] + public bool JsHint_asi { get; set; } + + [LocDisplayName("Allow assignments")] + [Description("[boss] This option suppresses warnings about the use of assignments in cases where comparisons are expected.")] + [Category("Relaxing Options")] + public bool JsHint_boss { get; set; } + + [LocDisplayName("Allow debugger statements")] + [Description("[debug] This option suppresses warnings about the debugger statements in your code.")] + [Category("Relaxing Options")] + public bool JsHint_debug { get; set; } + + [LocDisplayName("Allow == null")] + [Description("[eqnull] This option suppresses warnings about == null comparisons.")] + [Category("Relaxing Options")] + public bool JsHint_eqnull { get; set; } + + [LocDisplayName("Use EcmaScript 5")] + [Description("[es5] This option tells JSHint that your code uses ECMAScript 5 specific features such as getters and setters.")] + [Category("Relaxing Options")] + public bool JsHint_es5 { get; set; } + + [LocDisplayName("Allow ES.next features")] + [Description("[esnext] This option tells JSHint that your code uses ES.next specific features such as const.")] + [Category("Relaxing Options")] + public bool JsHint_esnext { get; set; } + + [LocDisplayName("Allow 'eval'")] + [Description("[evil] This option suppresses warnings about the use of eval.")] + [Category("Relaxing Options")] + public bool JsHint_evil { get; set; } + + [LocDisplayName("Allow expressions")] + [Description("[expr] This option suppresses warnings about the use of expressions where normally you would expect to see assignments or function calls.")] + [Category("Relaxing Options")] + public bool JsHint_expr { get; set; } + + [LocDisplayName("Allow variable scoping mismatch")] + [Description("[funcscope] This option suppresses warnings about declaring variables inside of control structures while accessing them later from the outside.")] + [Category("Relaxing Options")] + public bool JsHint_funcscope { get; set; } + + [LocDisplayName("Allow global strict mode")] + [Description("[globalstrict] This option suppresses warnings about the use of global strict mode.")] + [Category("Relaxing Options")] + public bool JsHint_globalstrict { get; set; } + + [LocDisplayName("Allow '__iterator__'")] + [Description("[iterator] This option suppresses warnings about the __iterator__ property.")] + [Category("Relaxing Options")] + public bool JsHint_iterator { get; set; } + + [LocDisplayName("Allow omitting last semicolon")] + [Description("[lastsemic] This option suppresses warnings about missing semicolons, but only when the semicolon is omitted for the last statement in a one-line block.")] + [Category("Relaxing Options")] + public bool JsHint_lastsemic { get; set; } + + [LocDisplayName("Allow unsafe line breaks")] + [Description("[laxbreak] This option suppresses most of the warnings about possibly unsafe line breakings in your code. It doesn't suppress warnings about comma-first coding style.")] + [Category("Relaxing Options")] + public bool JsHint_laxbreak { get; set; } + + [LocDisplayName("Allow comma first")] + [Description("[laxcomma] This option suppresses warnings about comma-first coding style.")] + [Category("Relaxing Options")] + public bool JsHint_laxcomma { get; set; } + + [LocDisplayName("Allow functions inside loops")] + [Description("[loopfunc] This option suppresses warnings about functions inside of loops.")] + [Category("Relaxing Options")] + public bool JsHint_loopfunc { get; set; } + + [LocDisplayName("Allow multiline strings")] + [Description("[multistr] This option suppresses warnings about multi-line strings. Multi-line strings can be dangerous in JavaScript because all hell breaks loose if you accidentally put a whitespace in between the escape character (\\) and a new line.")] + [Category("Relaxing Options")] + public bool JsHint_multistr { get; set; } + + [LocDisplayName("Allow on-case switches")] + [Description("[onecase] This option suppresses warnings about switches with just one case.")] + [Category("Relaxing Options")] + public bool JsHint_onecase { get; set; } + + [LocDisplayName("Allow '__proto__'")] + [Description("[proto] This option suppresses warnings about the __proto__ property. This property is deprecated and not supported by all browsers.")] + [Category("Relaxing Options")] + public bool JsHint_proto { get; set; } + + [LocDisplayName("Allow unescaped '-' in regex")] + [Description("[regexdash] This option suppresses warnings about unescaped - in the end of regular expressions.")] + [Category("Relaxing Options")] + public bool JsHint_regexdash { get; set; } + + [LocDisplayName("Allow 'javascript:' URLs")] + [Description("[scripturl] This option suppresses warnings about the use of script-targeted URLs—such as javascript:")] + [Category("Relaxing Options")] + public bool JsHint_scripturl { get; set; } + + [LocDisplayName("Allow mixed tabs/spaces")] + [Description("[smarttabs] This option suppresses warnings about mixed tabs and spaces when the latter are used for alignmnent only.")] + [Category("Relaxing Options")] + public bool JsHint_smarttabs { get; set; } + + [LocDisplayName("Allow variable shadowing")] + [Description("[shadow] This option suppresses warnings about variable shadowing i.e. declaring a variable that had been already declared somewhere in the outer scope.")] + [Category("Relaxing Options")] + public bool JsHint_shadow { get; set; } + + [LocDisplayName("Allow object['member']")] + [Description("[sub] This option suppresses warnings about using [] notation when it can be expressed in dot notation: person['name'] vs. person.name.")] + [Category("Relaxing Options")] + public bool JsHint_sub { get; set; } + + [LocDisplayName("Allow weird constructions")] + [Description("[supernew] This option suppresses warnings about 'weird' constructions like new function () { ... } and new Object;.")] + [Category("Relaxing Options")] + public bool JsHint_supernew { get; set; } + + [LocDisplayName("Allow strict mode violations")] + [Description("[validthis] This option suppresses warnings about possible strict violations when the code is running in strict mode and you use this in a non-constructor function.")] + [Category("Relaxing Options")] + public bool JsHint_validthis { get; set; } + + // Environment + + [LocDisplayName("Assume browser")] + [Description("[browser] This option defines globals exposed by modern browsers: all the way from good ol' document and navigator to the HTML5 FileReader and other new developments in the browser world.")] + [Category("Environment")] + public bool JsHint_browser { get; set; } + + [LocDisplayName("Assume CouchDB")] + [Description("[couch] This option defines globals exposed by CouchDB. CouchDB is a document-oriented database that can be queried and indexed in a MapReduce fashion using JavaScript.")] + [Category("Environment")] + public bool JsHint_couch { get; set; } + + [LocDisplayName("Allow console, alert etc.")] + [Description("[devel] This option defines globals that are usually used for logging poor-man's debugging: console, alert, etc.")] + [Category("Environment")] + public bool JsHint_devel { get; set; } + + [LocDisplayName("Assume Dojo")] + [Description("[dojo] This option defines globals exposed by the Dojo Toolkit.")] + [Category("Environment")] + public bool JsHint_dojo { get; set; } + + [LocDisplayName("Assume jQuery")] + [Description("[jquery] This option defines globals exposed by the jQuery JavaScript library.")] + [Category("Environment")] + public bool JsHint_jquery { get; set; } + + [LocDisplayName("Assume MooTools")] + [Description("[mootools] This option defines globals exposed by the MooTools JavaScript framework.")] + [Category("Environment")] + public bool JsHint_mootools { get; set; } + + [LocDisplayName("Assume NodeJS")] + [Description("[node] This option defines globals available when your code is running inside of the Node runtime environment.")] + [Category("Environment")] + public bool JsHint_node { get; set; } + + [LocDisplayName("Allow non-standards")] + [Description("[nonstandard] This option defines non-standard but widely adopted globals such as escape and unescape.")] + [Category("Environment")] + public bool JsHint_nonstandard { get; set; } + + [LocDisplayName("Assume Prototype.js")] + [Description("[prototypejs] This option defines globals exposed by the Prototype JavaScript framework.")] + [Category("Environment")] + public bool JsHint_prototypejs { get; set; } + + [LocDisplayName("Assume Rhino")] + [Description("[rhino] This option defines globals available when your code is running inside of the Rhino runtime environment.")] + [Category("Environment")] + public bool JsHint_rhino { get; set; } + + [LocDisplayName("Allow Web Workers")] + [Description("[worker] This option defines globals available when your code is running inside of a Web Worker.")] + [Category("Environment")] + public bool JsHint_worker { get; set; } + + [LocDisplayName("Assume Windows Script Host")] + [Description("[wsh] This option defines globals available when your code is running as a script for the Windows Script Host.")] + [Category("Environment")] + public bool JsHint_wsh { get; set; } + } +} diff --git a/EditorExtensions/Options/Less.cs b/EditorExtensions/Options/Less.cs new file mode 100644 index 000000000..e0537ed34 --- /dev/null +++ b/EditorExtensions/Options/Less.cs @@ -0,0 +1,58 @@ +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class LessOptions : DialogPage + { + public LessOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.GenerateCssFileFromLess, GenerateCssFileFromLess); + Settings.SetValue(WESettings.Keys.ShowLessPreviewWindow, ShowLessPreviewWindow); + Settings.SetValue(WESettings.Keys.LessMinify, LessMinify); + Settings.SetValue(WESettings.Keys.LessCompileOnBuild, LessCompileOnBuild); + Settings.SetValue(WESettings.Keys.LessCompileToFolder, LessCompileToFolder); + + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + GenerateCssFileFromLess = WESettings.GetBoolean(WESettings.Keys.GenerateCssFileFromLess); + ShowLessPreviewWindow = WESettings.GetBoolean(WESettings.Keys.ShowLessPreviewWindow); + LessMinify = WESettings.GetBoolean(WESettings.Keys.LessMinify); + LessCompileOnBuild = WESettings.GetBoolean(WESettings.Keys.LessCompileOnBuild); + LessCompileToFolder = WESettings.GetBoolean(WESettings.Keys.LessCompileToFolder); + } + + [LocDisplayName("Generate CSS file on save")] + [Description("Generate CSS file when LESS file is saved")] + [Category("LESS")] + public bool GenerateCssFileFromLess { get; set; } + + [LocDisplayName("Generate min file on save")] + [Description("Creates a minified version of the compiled CSS file (file.min.css)")] + [Category("LESS")] + public bool LessMinify { get; set; } + + [LocDisplayName("Show preview window")] + [Description("Show the preview window when editing a LESS file.")] + [Category("LESS")] + public bool ShowLessPreviewWindow { get; set; } + + [LocDisplayName("Compile on build")] + [Description("Compiles all LESS files in the project that has a corresponding .css file.")] + [Category("LESS")] + public bool LessCompileOnBuild { get; set; } + + [LocDisplayName("Compile to 'css' folder")] + [Description("Compiles all LESS files into a folder called 'css' in the same directory as the .less file")] + [Category("LESS")] + public bool LessCompileToFolder { get; set; } + } +} diff --git a/EditorExtensions/Options/ProjectSettingsStore.cs b/EditorExtensions/Options/ProjectSettingsStore.cs new file mode 100644 index 000000000..07cfaad2a --- /dev/null +++ b/EditorExtensions/Options/ProjectSettingsStore.cs @@ -0,0 +1,349 @@ +using EnvDTE; +using EnvDTE80; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using Keys = MadsKristensen.EditorExtensions.WESettings.Keys; + +namespace MadsKristensen.EditorExtensions +{ + internal class Settings + { + public const string _fileName = "WE-settings.xml"; + public const string _solutionFolder = "Solution Items"; + + private static SortedDictionary _cache = DefaultSettings(); + private static bool _inProgress; + private static object _syncFileRoot = new object(); + private static object _syncCacheRoot = new object(); + + public Settings() + { + UpdateCache(); + } + + public static bool SolutionSettingsExist + { + get { return File.Exists(GetSolutionFilePath()); } + } + + public static float Version { get; private set; } + + public static object GetValue(string propertyName) + { + lock (_syncCacheRoot) + { + if (_cache.ContainsKey(propertyName)) + return _cache[propertyName]; + } + + return null; + } + + public static void SetValue(string propertyName, object value) + { + lock (_syncCacheRoot) + { + string v = value.ToString().ToLowerInvariant(); + _cache[propertyName] = v; + } + } + + public static void Save(string file = null) + { + //_dispatcher.BeginInvoke(new Action(() => + //{ + Task.Run(() => + { + SaveToDisk(file); + UpdateStatusBar("updated"); + }); + + //}), DispatcherPriority.ApplicationIdle, null); + } + + internal static void CreateSolutionSettings() + { + string path = GetSolutionFilePath(); + + if (!File.Exists(path)) + { + lock (_syncFileRoot) + { + File.WriteAllText(path, string.Empty); + } + + Save(path); + + Solution2 solution = EditorExtensionsPackage.DTE.Solution as Solution2; + Project project = solution.Projects + .OfType() + .FirstOrDefault(p => p.Name.Equals(_solutionFolder, StringComparison.OrdinalIgnoreCase)); + + if (project == null) + { + project = solution.AddSolutionFolder(_solutionFolder); + } + + project.ProjectItems.AddFromFile(path); + //EditorExtensionsPackage.DTE.ItemOperations.OpenFile(path); + UpdateStatusBar("applied"); + } + } + + public static void UpdateCache() + { + try + { + string path = GetFilePath(); + + if (File.Exists(path)) + { + XmlDocument doc = LoadXmlDocument(path); + + if (doc != null) + { + + XmlNode settingsNode = doc.SelectSingleNode("webessentials/settings"); + + if (settingsNode != null) + { + XmlAttribute versionAttr = settingsNode.Attributes["version"]; + if (versionAttr != null) + { + float version; + + if (float.TryParse(versionAttr.InnerText, out version)) + { + Version = version; + } + } + + lock (_syncCacheRoot) + { + _cache.Clear(); + + foreach (XmlNode node in settingsNode.ChildNodes) + { + _cache[node.Name] = node.InnerText; + } + } + + OnUpdated(); + } + } + } + } + catch + { } + } + + private static void SaveToDisk(string file) + { + if (!_inProgress) + { + _inProgress = true; + string path = file ?? GetFilePath(); + + lock (_syncFileRoot) + { + string xml = GenerateXml(); + + ProjectHelpers.CheckOutFileFromSourceControl(path); + File.WriteAllText(path, xml); + } + + _inProgress = false; + } + } + + private static string GenerateXml() + { + StringBuilder sb = new StringBuilder(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Indent = true; + + using (XmlWriter writer = XmlWriter.Create(sb, settings)) + { + writer.WriteStartElement("webessentials"); + writer.WriteAttributeString("version", "1.9"); + + writer.WriteStartElement("settings"); + + lock (_syncCacheRoot) + { + foreach (string property in _cache.Keys) + { + string value = _cache[property].ToString(); + writer.WriteElementString(property, value); + } + } + + writer.WriteEndElement();// settings + writer.WriteEndElement();// webessentials + } + + sb.Replace(Encoding.Unicode.WebName, Encoding.UTF8.WebName); + + return sb.ToString(); + } + + private static XmlDocument LoadXmlDocument(string path) + { + try + { + lock (_syncFileRoot) + { + XmlDocument doc = new XmlDocument(); + doc.Load(path); + return doc; + } + } + catch + { + return null; + } + } + + private static string GetFilePath() + { + string path = GetSolutionFilePath(); + + if (!File.Exists(path)) + { + path = GetUserFilePath(); + } + + return path; + } + + public static string GetSolutionFilePath() + { + EnvDTE.Solution solution = EditorExtensionsPackage.DTE.Solution; + + if (solution == null || string.IsNullOrEmpty(solution.FullName)) + return null; + + return Path.Combine(Path.GetDirectoryName(solution.FullName), _fileName); + } + + private static string GetUserFilePath() + { + string user = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + string folder = Path.Combine(user, "Web Essentials"); + + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + return Path.Combine(folder, _fileName); + } + + private static SortedDictionary DefaultSettings() + { + var dic = new SortedDictionary(); + + // MISC + dic.Add(Keys.EnableMustache, true); + dic.Add(Keys.EnableJavascriptRegions, true); + + // LESS + dic.Add(Keys.GenerateCssFileFromLess, true); + dic.Add(Keys.ShowLessPreviewWindow, true); + dic.Add(Keys.LessMinify, true); + + // SCSS + dic.Add(Keys.GenerateCssFileFromScss, true); + dic.Add(Keys.ShowScssPreviewWindow, true); + dic.Add(Keys.ScssMinify, true); + + // CoffeeScript + dic.Add(Keys.GenerateJsFileFromCoffeeScript, true); + dic.Add(Keys.ShowCoffeeScriptPreviewWindow, true); + + // CSS + dic.Add(Keys.CssErrorLocation, (int)Keys.ErrorLocation.Messages); + dic.Add(Keys.SyncVendorValues, true); + dic.Add(Keys.EnableCssSelectorHighligting, true); + dic.Add(Keys.ShowUnsupported, true); + dic.Add(Keys.AutoCloseCurlyBraces, true); + + //JSHint + dic.Add(Keys.EnableJsHint, true); + dic.Add(Keys.JsHintErrorLocation, (int)Keys.FullErrorLocation.Messages); + dic.Add(Keys.JsHint_bitwise, true); + dic.Add(Keys.JsHint_browser, true); + dic.Add(Keys.JsHint_devel, true); + dic.Add(Keys.JsHint_eqeqeq, true); + dic.Add(Keys.JsHint_es5, true); + dic.Add(Keys.JsHint_expr, true); + dic.Add(Keys.JsHint_debug, true); + dic.Add(Keys.JsHint_jquery, true); + dic.Add(Keys.JsHint_laxbreak, true); + dic.Add(Keys.JsHint_laxcomma, true); + dic.Add(Keys.JsHint_maxerr, 50); + dic.Add(Keys.JsHint_regexdash, true); + dic.Add(Keys.JsHint_smarttabs, true); + + // MISC + dic.Add(Keys.ShowBrowserTooltip, true); + dic.Add(Keys.WrapCoffeeScriptClosure, true); + + // TypeScript + //dic.Add(Keys.ShowTypeScriptPreviewWindow, true); + //dic.Add(Keys.GenerateJsFileFromTypeScript, true); + //dic.Add(Keys.TypeScriptAddGeneratedFilesToProject, true); + + // Minification + dic.Add(Keys.EnableCssMinification, true); + dic.Add(Keys.EnableJsMinification, true); + + // Minification + dic.Add(Keys.CoffeeScriptMinify, true); + //dic.Add(Keys.TypeScriptMinify, true); + + dic.Add(Keys.GenerateJavaScriptSourceMaps, true); + dic.Add(Keys.EnableHtmlZenCoding, true); + + dic.Add(Keys.JavaScriptAutoCloseBraces, true); + dic.Add(Keys.JavaScriptOutlining, true); + + return dic; + } + + public static event EventHandler Updated; + + private static void OnUpdated() + { + if (Updated != null) + { + Updated(null, EventArgs.Empty); + } + } + + public static void UpdateStatusBar(string action) + { + try + { + if (SolutionSettingsExist) + { + EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: Solution settings " + action; + } + else + { + EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: Global settings " + action; + } + } + catch + { + Logger.Log("Error updating status bar"); + } + } + } +} diff --git a/EditorExtensions/Options/ProjectSettingsTextViewListener.cs b/EditorExtensions/Options/ProjectSettingsTextViewListener.cs new file mode 100644 index 000000000..8b5861154 --- /dev/null +++ b/EditorExtensions/Options/ProjectSettingsTextViewListener.cs @@ -0,0 +1,36 @@ +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; +using System.Threading.Tasks; + +namespace MadsKristensen.EditorExtensions.Options +{ + [Export(typeof(IWpfTextViewCreationListener))] + [ContentType("XML")] + [TextViewRole(PredefinedTextViewRoles.Document)] + internal class ProjectSettingsTextViewListener : IWpfTextViewCreationListener + { + public void TextViewCreated(IWpfTextView textView) + { + ITextDocument document; + textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document); + + if (document != null) + { + document.FileActionOccurred += document_FileActionOccurred; + } + } + + private void document_FileActionOccurred(object sender, TextDocumentFileActionEventArgs e) + { + if (e.FileActionType == FileActionTypes.ContentSavedToDisk && e.FilePath.EndsWith(Settings._fileName)) + { + Task.Run(() => + { + Settings.UpdateCache(); + }); + } + } + } +} diff --git a/EditorExtensions/Options/Scss.cs b/EditorExtensions/Options/Scss.cs new file mode 100644 index 000000000..c92b300c5 --- /dev/null +++ b/EditorExtensions/Options/Scss.cs @@ -0,0 +1,58 @@ +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class ScssOptions : DialogPage + { + public ScssOptions() + { + Settings.Updated += delegate { LoadSettingsFromStorage(); }; + } + + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.GenerateCssFileFromScss, GenerateCssFileFromScss); + Settings.SetValue(WESettings.Keys.ShowScssPreviewWindow, ShowScssPreviewWindow); + Settings.SetValue(WESettings.Keys.ScssMinify, ScssMinify); + Settings.SetValue(WESettings.Keys.ScssCompileOnBuild, ScssCompileOnBuild); + Settings.SetValue(WESettings.Keys.ScssCompileToFolder, ScssCompileToFolder); + + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + GenerateCssFileFromScss = WESettings.GetBoolean(WESettings.Keys.GenerateCssFileFromScss); + ShowScssPreviewWindow = WESettings.GetBoolean(WESettings.Keys.ShowScssPreviewWindow); + ScssMinify = WESettings.GetBoolean(WESettings.Keys.ScssMinify); + ScssCompileOnBuild = WESettings.GetBoolean(WESettings.Keys.ScssCompileOnBuild); + ScssCompileToFolder = WESettings.GetBoolean(WESettings.Keys.ScssCompileToFolder); + } + + [LocDisplayName("Generate CSS file on save")] + [Description("Generate CSS file when Scss file is saved")] + [Category("Scss")] + public bool GenerateCssFileFromScss { get; set; } + + [LocDisplayName("Generate min file on save")] + [Description("Creates a minified version of the compiled CSS file (file.min.css)")] + [Category("Scss")] + public bool ScssMinify { get; set; } + + [LocDisplayName("Show preview window")] + [Description("Show the preview window when editing a Scss file.")] + [Category("Scss")] + public bool ShowScssPreviewWindow { get; set; } + + [LocDisplayName("Compile on build")] + [Description("Compiles all Scss files in the project that has a corresponding .css file.")] + [Category("Scss")] + public bool ScssCompileOnBuild { get; set; } + + [LocDisplayName("Compile to 'css' folder")] + [Description("Compiles all SCSS files into a folder called 'css' in the same directory as the .scss file")] + [Category("Scss")] + public bool ScssCompileToFolder { get; set; } + } +} diff --git a/EditorExtensions/Options/TypeScript.cs b/EditorExtensions/Options/TypeScript.cs new file mode 100644 index 000000000..b04e4206a --- /dev/null +++ b/EditorExtensions/Options/TypeScript.cs @@ -0,0 +1,88 @@ +using Microsoft.VisualStudio.Shell; +using System.ComponentModel; + +namespace MadsKristensen.EditorExtensions +{ + class TypeScriptOptions : DialogPage + { + public override void SaveSettingsToStorage() + { + Settings.SetValue(WESettings.Keys.GenerateJsFileFromTypeScript, GenerateJsFileFromTypeScript); + Settings.SetValue(WESettings.Keys.ShowTypeScriptPreviewWindow, ShowTypeScriptPreviewWindow); + Settings.SetValue(WESettings.Keys.CompileTypeScriptOnBuild, CompileTypeScriptOnBuild); + Settings.SetValue(WESettings.Keys.TypeScriptKeepComments, TypeScriptKeepComments); + Settings.SetValue(WESettings.Keys.TypeScriptUseAmdModule, TypeScriptUseAmdModule); + Settings.SetValue(WESettings.Keys.TypeScriptCompileES3, TypeScriptCompileES3); + Settings.SetValue(WESettings.Keys.TypeScriptProduceSourceMap, TypeScriptProduceSourceMap); + Settings.SetValue(WESettings.Keys.TypeScriptMinify, TypeScriptMinify); + Settings.SetValue(WESettings.Keys.TypeScriptAddGeneratedFilesToProject, TypeScriptAddGeneratedFilesToProject); + Settings.SetValue(WESettings.Keys.TypeScriptResaveWithUtf8BOM, TypeScriptResaveWithUtf8BOM); + + Settings.Save(); + } + + public override void LoadSettingsFromStorage() + { + GenerateJsFileFromTypeScript = WESettings.GetBoolean(WESettings.Keys.GenerateJsFileFromTypeScript); + ShowTypeScriptPreviewWindow = WESettings.GetBoolean(WESettings.Keys.ShowTypeScriptPreviewWindow); + CompileTypeScriptOnBuild = WESettings.GetBoolean(WESettings.Keys.CompileTypeScriptOnBuild); + TypeScriptKeepComments = WESettings.GetBoolean(WESettings.Keys.TypeScriptKeepComments); + TypeScriptUseAmdModule = WESettings.GetBoolean(WESettings.Keys.TypeScriptUseAmdModule); + TypeScriptCompileES3 = WESettings.GetBoolean(WESettings.Keys.TypeScriptCompileES3); + TypeScriptProduceSourceMap = WESettings.GetBoolean(WESettings.Keys.TypeScriptProduceSourceMap); + TypeScriptMinify = WESettings.GetBoolean(WESettings.Keys.TypeScriptMinify); + TypeScriptAddGeneratedFilesToProject = WESettings.GetBoolean(WESettings.Keys.TypeScriptAddGeneratedFilesToProject); + TypeScriptResaveWithUtf8BOM = WESettings.GetBoolean(WESettings.Keys.TypeScriptResaveWithUtf8BOM); + } + + [LocDisplayName("Compile TypeScript on save")] + [Description("Generate JavaScript file when TypeScript file is saved")] + [Category("TypeScript")] + public bool GenerateJsFileFromTypeScript { get; set; } + + [LocDisplayName("Show preview window")] + [Description("Show the preview window when editing a TypeScript file.")] + [Category("TypeScript")] + public bool ShowTypeScriptPreviewWindow { get; set; } + + [LocDisplayName("Add generated files to project")] + [Description("Includes the generated .js, .min.js and .map files to the current project, nested under the .ts file.")] + [Category("TypeScript")] + public bool TypeScriptAddGeneratedFilesToProject { get; set; } + + [LocDisplayName("Compile all TypeScript files on build")] + [Description("Runs the compiler on all TypeScript files in your project on build")] + [Category("TypeScript")] + public bool CompileTypeScriptOnBuild { get; set; } + + [LocDisplayName("Minify generated JavaScript")] + [Description("Creates a minified version of the compiled JavaScript file (file.min.js)")] + [Category("TypeScript")] + public bool TypeScriptMinify { get; set; } + + [LocDisplayName("Re-save JS with UTF8 BOM")] + [Description("Re-saves the compiled output with a UTF-8 BOM")] + [Category("TypeScript")] + public bool TypeScriptResaveWithUtf8BOM { get; set; } + + [LocDisplayName("Use the AMD module")] + [Description("Sets the '--module AMD' flag on the compiler")] + [Category("Compiler flags")] + public bool TypeScriptUseAmdModule { get; set; } + + [LocDisplayName("Compile to EcmaScript 3")] + [Description("Sets the '--target ES3' flag on the compiler. Default is EcmaScript 5")] + [Category("Compiler flags")] + public bool TypeScriptCompileES3 { get; set; } + + [LocDisplayName("Generate Source Map")] + [Description("Sets the '-sourcemap' flag on the compiler.")] + [Category("Compiler flags")] + public bool TypeScriptProduceSourceMap { get; set; } + + [LocDisplayName("Keep comments")] + [Description("Keeps the comments in the generated JavaScript files by setting the '-c' flag on the compiler.")] + [Category("Compiler flags")] + public bool TypeScriptKeepComments { get; set; } + } +} diff --git a/EditorExtensions/Options/WebEssentialsSettings.cs b/EditorExtensions/Options/WebEssentialsSettings.cs new file mode 100644 index 000000000..97380dc83 --- /dev/null +++ b/EditorExtensions/Options/WebEssentialsSettings.cs @@ -0,0 +1,185 @@ + +namespace MadsKristensen.EditorExtensions +{ + static class WESettings + { + public class Keys + { + // General + public const string EnableHtmlZenCoding = "HtmlEnableZenCoding"; + public const string EnableMustache = "HtmlEnableMustache"; + public const string KeepImportantComments = "KeepImportantComments"; + + // LESS + public const string GenerateCssFileFromLess = "LessGenerateCssFile"; + public const string ShowLessPreviewWindow = "LessShowPreviewWindow"; + public const string LessMinify = "LessMinify"; + public const string LessCompileOnBuild = "LessCompileOnBuild"; + public const string LessCompileToFolder = "LessCompileToFolder"; + + // SCSS + public const string GenerateCssFileFromScss = "ScssGenerateCssFile"; + public const string ShowScssPreviewWindow = "ScssShowPreviewWindow"; + public const string ScssMinify = "ScssMinify"; + public const string ScssCompileOnBuild = "ScssCompileOnBuild"; + public const string ScssCompileToFolder = "ScssCompileToFolder"; + + // CoffeeScript + public const string GenerateJsFileFromCoffeeScript = "CoffeeScriptGenerateJsFile"; + public const string ShowCoffeeScriptPreviewWindow = "CoffeeScriptShowPreviewWindow"; + public const string CoffeeScriptMinify = "CoffeeScriptMinify"; + public const string WrapCoffeeScriptClosure = "CoffeeScriptWrapClosure"; + public const string EnableIcedCoffeeScript = "CoffeeScriptEnableIced"; + public const string CoffeeScriptCompileToFolder = "CoffeeScriptCompileToFolder"; + public const string CoffeeScriptCompileOnBuild = "CoffeeScriptCompileOnBuild"; + + // CSS + public const string ValidateStarSelector = "CssValidateStarSelector"; + public const string ValidateOverQualifiedSelector = "CSSValidateOverQualifiedSelector"; + public const string CssErrorLocation = "CssErrorLocation"; + public const string EnableCssSelectorHighligting = "CssEnableSelectorHighligting"; + public const string ValidateEmbedImages = "CssValidateEmbedImages"; + public const string AutoCloseCurlyBraces = "CssAutoCloseCurlyBraces"; + public const string ShowBrowserTooltip = "CssShowBrowserTooltip"; + public const string SyncVendorValues = "CssSyncVendorValues"; + public const string ShowInitialInherit = "CssShowInitialInherit"; + public const string ShowUnsupported = "CssShowUnsupported"; + public const string EnableCssMinification = "CssEnableMinification"; + public const string ValidateZeroUnit = "CssValidateZeroUnit"; + public const string OnlyW3cAllowed = "CssOnlyW3cAllowed"; + public const string ValidateVendorSpecifics = "ValidateVendorSpecifics"; + public const string EnableSpeedTyping = "EnableSpeedTyping"; + + // JavaScript + public const string EnableJavascriptRegions = "JavascriptEnableRegions"; + public const string EnableJsMinification = "JavaScriptEnableMinification"; + public const string JavaScriptAutoCloseBraces = "JavaScriptAutoCloseBraces"; + public const string JavaScriptOutlining = "JavaScriptOutlining"; + public const string GenerateJavaScriptSourceMaps = "JavaScriptGenerateSourceMaps"; + + // TypeScript + //public const string GenerateJsFileFromTypeScript = "TypeScriptGenerateJsFile"; + //public const string ShowTypeScriptPreviewWindow = "TypeScriptShowPreviewWindow"; + //public const string CompileTypeScriptOnBuild = "TypeScriptCompileOnBuild"; + //public const string TypeScriptKeepComments = "TypeScriptKeepComments"; + //public const string TypeScriptUseAmdModule = "TypeScriptUseAmdModule"; + //public const string TypeScriptCompileES3 = "TypeScriptCompileES3"; + //public const string TypeScriptProduceSourceMap = "TypeScriptProduceSourceMap"; + //public const string TypeScriptMinify = "TypeScriptMinify"; + //public const string TypeScriptAddGeneratedFilesToProject = "TypeScriptAddGeneratedFilesToProject"; + //public const string TypeScriptResaveWithUtf8BOM = "TypeScriptResaveWithUtf8BOM"; + + // JSHint + public const string EnableJsHint = "JsHintEnable"; + public const string RunJsHintOnBuild = "JsHintRunOnBuild"; + public const string JsHintErrorLocation = "JsHintErrorLocation"; + public const string JsHint_eqeqeq = "JsHint_eqeqeq"; + public const string JsHint_bitwise = "JsHint_bitwise"; + public const string JsHint_maxerr = "JsHint_maxerr"; // int + public const string JsHint_camelcase = "JsHint_camelcase"; + public const string JsHint_curly = "JsHint_curly"; + public const string JsHint_forin = "JsHint_forin"; + public const string JsHint_immed = "JsHint_immed"; + public const string JsHint_indent = "JsHint_indent"; // int + public const string JsHint_latedef = "JsHint_latedef"; + public const string JsHint_newcap = "JsHint_newcap"; + public const string JsHint_noarg = "JsHint_noarg"; + public const string JsHint_noempty = "JsHint_noempty"; + public const string JsHint_nonew = "JsHint_nonew"; + public const string JsHint_plusplus = "JsHint_plusplus"; + public const string JsHint_quotmark = "JsHint_quotmark"; + public const string JsHint_regexp = "JsHint_regexp"; + public const string JsHint_undef = "JsHint_undef"; + public const string JsHint_unused = "JsHint_unused"; + public const string JsHint_strict = "JsHint_strict"; + public const string JsHint_trailing = "JsHint_trailing"; + + // Relaxing + public const string JsHint_asi = "JsHint_asi"; + public const string JsHint_boss = "JsHint_boss"; + public const string JsHint_debug = "JsHint_debug"; + public const string JsHint_eqnull = "JsHint_eqnull"; + public const string JsHint_es5 = "JsHint_es5"; + public const string JsHint_esnext = "JsHint_esnext"; + public const string JsHint_evil = "JsHint_evil"; + public const string JsHint_expr = "JsHint_expr"; + public const string JsHint_funcscope = "JsHint_funcscope"; + public const string JsHint_globalstrict = "JsHint_globalstrict"; + public const string JsHint_iterator = "JsHint_iterator"; + public const string JsHint_lastsemic = "JsHint_lastsemic"; + public const string JsHint_laxbreak = "JsHint_laxbreak"; + public const string JsHint_laxcomma = "JsHint_laxcomma"; + public const string JsHint_loopfunc = "JsHint_loopfunc"; + public const string JsHint_multistr = "JsHint_multistr"; + public const string JsHint_onecase = "JsHint_onecase"; + public const string JsHint_proto = "JsHint_proto"; + public const string JsHint_regexdash = "JsHint_regexdash"; + public const string JsHint_scripturl = "JsHint_scripturl"; + public const string JsHint_smarttabs = "JsHint_smarttabs"; + public const string JsHint_shadow = "JsHint_shadow"; + public const string JsHint_sub = "JsHint_sub"; + public const string JsHint_supernew = "JsHint_supernew"; + public const string JsHint_validthis = "JsHint_validthis"; + + // Environment + public const string JsHint_browser = "JsHint_browser"; + public const string JsHint_devel = "JsHint_devel"; + public const string JsHint_jquery = "JsHint_jquery"; + public const string JsHint_couch = "JsHint_couch"; + public const string JsHint_dojo = "JsHint_dojo"; + public const string JsHint_mootools = "JsHint_mootools"; + public const string JsHint_node = "JsHint_node"; + public const string JsHint_nonstandard = "JsHint_nonstandard"; + public const string JsHint_prototypejs = "JsHint_prototypejs"; + public const string JsHint_rhino = "JsHint_rhino"; + public const string JsHint_worker = "JsHint_worker"; + public const string JsHint_wsh = "JsHint_wsh"; + + public enum ErrorLocation + { + Warnings = 0, + Messages = 1, + } + + public enum FullErrorLocation + { + Errors = 0, + Warnings = 1, + Messages = 2, + } + } + + private static Settings _projectStore; + + static WESettings() + { + _projectStore = new Settings(); + } + + public static bool GetBoolean(string propertyName) + { + bool result; + object value = Settings.GetValue(propertyName); + + if (value != null && bool.TryParse(value.ToString(), out result)) + { + return result; + } + + return false; + } + + public static int GetInt(string propertyName) + { + int result; + object value = Settings.GetValue(propertyName); + + if (value != null && int.TryParse(value.ToString(), out result)) + { + return result; + } + + return -1; + } + } +} diff --git a/EditorExtensions/PkgCmdID.cs b/EditorExtensions/PkgCmdID.cs new file mode 100644 index 000000000..6347b3362 --- /dev/null +++ b/EditorExtensions/PkgCmdID.cs @@ -0,0 +1,58 @@ + +namespace MadsKristensen.EditorExtensions +{ + static class PkgCmdIDList + { + public const uint myCommand = 0x100; + public const uint htmlEncode = 0x102; + public const uint htmlDecode = 0x103; + public const uint urlEncode = 0x106; + public const uint urlDecode = 0x107; + public const uint jsEncode = 0x108; + public const uint attrEncode = 0x109; + public const uint urlPathEncode = 0x110; + public const uint upperCaseTransform = 0x111; + public const uint lowerCaseTransform = 0x114; + public const uint titleCaseTransform = 0x115; + public const uint reverseTransform = 0x116; + public const uint normalizeTransform = 0x118; + public const uint md5Transform = 0x120; + public const uint sha1Transform = 0x121; + public const uint sha256Transform = 0x122; + public const uint sha384Transform = 0x123; + public const uint sha512Transform = 0x124; + public const uint sortCssProperties = 0x125; + public const uint addMissingVendor = 0x127; + public const uint addMissingStandard = 0x128; + public const uint cssRemoveDuplicates = 0x129; + public const uint cssHideUnsupported = 0x1033; + public const uint cssHideInheritInitial = 0x1035; + public const uint addNewFeature = 0x334; + public const uint SurroundWith = 0x334; + public const uint ExpandSelection = 0x335; + public const uint ContractSelection = 0x336; + public const uint cmdDiff = 0x1041; + public const uint cmdJsHint = 0x1042; + public const uint cmdProjectSettings = 0x1043; + public const uint cmdSolutionSettings = 0x1044; + public const uint cmdSolutionColors = 0x1045; + public const uint cmdMarkdownStylesheet = 0x1046; + public const uint CssIntellisenseSubMenu = 0x1031; + public const uint MinifyCss = 0x1051; + public const uint MinifyJs = 0x1052; + public const uint MinifySelection = 0x1053; + public const uint ExtractSelection = 0x1054; + public const uint SelectBrowsers = 0x1055; + public const uint ExtractVariable = 0x1056; + public const uint ExtractMixin = 0x1057; + public const uint BundleCss = 0x1071; + public const uint BundleJs = 0x1072; + + // Build + public const uint cmdBuildBundles = 0x1083; + public const uint cmdBuildLess = 0x1084; + //public const uint cmdBuildTypeScript = 0x1085; + public const uint cmdBuildMinify = 0x1086; + public const uint cmdBuildCoffeeScript = 0x1087; + }; +} diff --git a/EditorExtensions/Properties/AssemblyInfo.cs b/EditorExtensions/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..570631b1f --- /dev/null +++ b/EditorExtensions/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Web Essentials 2013")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Mads Kristensen")] +[assembly: AssemblyProduct("Web Essentials 2013")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: CLSCompliant(false)] +[assembly: NeutralResourcesLanguage("en-US")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.5.0.0")] +[assembly: AssemblyFileVersion("1.5.0.0")] + + + diff --git a/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfo.cs b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfo.cs new file mode 100644 index 000000000..9453c4d44 --- /dev/null +++ b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfo.cs @@ -0,0 +1,293 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Intellisense; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace MadsKristensen.EditorExtensions +{ + internal class DeclarationQuickInfo : IQuickInfoSource + { + private DeclarationQuickInfoSourceProvider _provider; + private ITextBuffer _buffer; + private CssTree _tree; + private static readonly string[] browserAbbr = new[] { "C", "FF", "IE", "O", "S" }; + private ICssSchemaInstance _rootSchema; + + public DeclarationQuickInfo(DeclarationQuickInfoSourceProvider provider, ITextBuffer buffer) + { + _provider = provider; + _buffer = buffer; + _rootSchema = CssSchemaManager.SchemaManager.GetSchemaRootForBuffer(buffer); + } + + public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiContent, out ITrackingSpan applicableToSpan) + { + applicableToSpan = null; + + if (!EnsureTreeInitialized() || session == null || qiContent == null || qiContent.Count > 0 || !WESettings.GetBoolean(WESettings.Keys.ShowBrowserTooltip)) + return; + + SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); + if (!point.HasValue) + return; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(point.Value.Position); + if (item == null || !item.IsValid) + return; + + ParseItem theOne = null; + ICssCompletionListEntry entry = null; + ICssSchemaInstance schema = CssSchemaManager.SchemaManager.GetSchemaForItem(_rootSchema, item); + + // Declaration + Declaration dec = item.FindType(); + if (dec != null && dec.PropertyName != null && dec.PropertyName.ContainsRange(point.Value.Position, 1)) + { + entry = schema.GetProperty(dec.PropertyName.Text); + theOne = dec.PropertyName; + } + else if (dec != null && dec.IsValid && dec.Values.TextStart <= point.Value.Position && dec.Values.TextAfterEnd >= point.Value.Position) + { + entry = schema.GetProperty(dec.PropertyName.Text); + if (entry != null) + { + var list = schema.GetPropertyValues(entry.DisplayText); + theOne = dec.StyleSheet.ItemFromRange(point.Value.Position, 0); + entry = list.SingleOrDefault(r => r.DisplayText.Equals(theOne.Text, StringComparison.OrdinalIgnoreCase)); + } + } + + // Pseudo class + if (entry == null) + { + PseudoClassSelector pseudoClass = item.FindType(); + if (pseudoClass != null) + { + entry = schema.GetPseudo(pseudoClass.Text); + theOne = pseudoClass; + } + } + + // Pseudo class function + if (entry == null) + { + PseudoClassFunctionSelector pseudoClassFunction = item.FindType(); + if (pseudoClassFunction != null) + { + entry = schema.GetPseudo(pseudoClassFunction.Text); + theOne = pseudoClassFunction; + } + } + + // Pseudo element + if (entry == null) + { + PseudoElementSelector pseudoElement = item.FindType(); + if (pseudoElement != null) + { + entry = schema.GetPseudo(pseudoElement.Text); + theOne = pseudoElement; + } + } + + // Pseudo element function + if (entry == null) + { + PseudoElementFunctionSelector pseudoElementFunction = item.FindType(); + if (pseudoElementFunction != null) + { + entry = schema.GetPseudo(pseudoElementFunction.Text); + theOne = pseudoElementFunction; + } + } + + // @-directive + if (entry == null) + { + AtDirective atDirective = item.Parent as AtDirective; + if (atDirective != null && atDirective.Keyword != null) + { + entry = schema.GetAtDirective("@" + atDirective.Keyword.Text); + theOne = atDirective.Keyword; + } + } + + if (entry != null) + { + applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(theOne.Start, theOne.Length, SpanTrackingMode.EdgeNegative); + + string syntax = entry.GetSyntax(schema.Version); + string b = entry.GetAttribute("browsers"); + + if (string.IsNullOrEmpty(b) && theOne.Parent != null && theOne.Parent is Declaration) + { + b = schema.GetProperty(((Declaration)theOne.Parent).PropertyName.Text).GetAttribute("browsers"); + if (string.IsNullOrEmpty(syntax)) + syntax = theOne.Text; + } + + if (!string.IsNullOrEmpty(syntax)) + { + //var example = CreateExample(syntax); + qiContent.Add("Example: " + syntax); + } + + Dictionary browsers = GetBrowsers(b); + qiContent.Add(CreateBrowserList(browsers)); + } + } + + public static Dictionary GetBrowsers(string browsersRaw) + { + Dictionary dic = new Dictionary(); + if (!string.IsNullOrEmpty(browsersRaw)) + { + string[] array = browsersRaw.Split(','); + + foreach (string browserString in array) + { + var browser = GetBrowserVersion(browserString); + if (!dic.ContainsKey(browser.Key)) + dic.Add(browser.Key, browser.Value); + } + } + else + { + foreach (string name in browserAbbr) + { + dic.Add(name, "all"); + } + } + + return dic; + } + + private static KeyValuePair GetBrowserVersion(string browserString) + { + var nameChars = browserString.Where(b => char.IsLetter(b)).ToArray(); + + string name = string.Join(string.Empty, nameChars); + string value = "all"; + + if (nameChars.Length < browserString.Length) + value = browserString.Substring(nameChars.Length); + + int index = value.IndexOf('-'); + if (index > -1) + value = value.Substring(0, index); + + //if (value.StartsWith("1") || value.StartsWith("2") || value.StartsWith("3")) + // value = "all"; + + return new KeyValuePair(name, value); + } + + //private static UIElement CreateExample(string example) + //{ + // StackPanel panel = new StackPanel(); + // panel.Orientation = Orientation.Horizontal; + // panel.Margin = new Thickness(0, 0, 0, 5); + + // TextBlock label = new TextBlock(); + // label.Text = "Example: "; + // label.FontWeight = FontWeights.Bold; + // label.FontSize = 11; + // label.FontFamily = new FontFamily("Consolas"); + // panel.Children.Add(label); + + // TextBlock value = new TextBlock(); + // value.Text = example; + // value.FontSize = 11; + // value.FontFamily = new FontFamily("Consolas"); + // panel.Children.Add(value); + + // return panel; + //} + + private static UIElement CreateBrowserList(Dictionary browsers) + { + StackPanel panel = new System.Windows.Controls.StackPanel(); + panel.Orientation = Orientation.Horizontal; + + foreach (string name in browserAbbr) + { + StackPanel p = new StackPanel(); + p.Orientation = Orientation.Vertical; + p.Margin = new Thickness(5, 0, 5, 0); + p.HorizontalAlignment = HorizontalAlignment.Right; + + Image image = new Image(); + image.Height = 24; + image.Width = 24; + p.Children.Add(image); + + TextBlock block = new TextBlock(); + block.TextAlignment = TextAlignment.Center; + block.Background = new SolidColorBrush(Brushes.WhiteSmoke.Color); + block.Background.Opacity = 0.6; + block.Margin = new Thickness(0, -7, 0, 0); + block.HorizontalAlignment = HorizontalAlignment.Right; + block.FontSize = 11; + block.FontFamily = new FontFamily("Consolas"); + + if (!browsers.ContainsKey(name) && !browsers.ContainsKey("all")) + { + image.Opacity = 0.4; + image.Source = BitmapFrame.Create(new Uri("pack://application:,,,/WebEssentials2013;component/Resources/Browsers/" + name + "_gray.png", UriKind.RelativeOrAbsolute)); + } + else + { + block.Text = browsers.ContainsKey("all") ? string.Empty : browsers[name]; + image.Source = BitmapFrame.Create(new Uri("pack://application:,,,/WebEssentials2013;component/Resources/Browsers/" + name + ".png", UriKind.RelativeOrAbsolute)); + } + + if (block.Text != "all") + p.Children.Add(block); + + panel.Children.Add(p); + } + + return panel; + } + + /// + /// This must be delayed so that the TextViewConnectionListener + /// has a chance to initialize the WebEditor host. + /// + public bool EnsureTreeInitialized() + { + if (_tree == null)// && WebEditor.GetHost(CssContentTypeDefinition.CssContentType) != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + } + catch (Exception) + { + } + } + + return _tree != null; + } + + private bool m_isDisposed; + public void Dispose() + { + if (!m_isDisposed) + { + GC.SuppressFinalize(this); + m_isDisposed = true; + } + } + } +} diff --git a/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoController.cs b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoController.cs new file mode 100644 index 000000000..9639c3ede --- /dev/null +++ b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoController.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace MadsKristensen.EditorExtensions +{ + internal class DeclarationQuickInfoController : IIntellisenseController + { + private ITextView m_textView; + private IList m_subjectBuffers; + private DeclarationQuickInfoControllerProvider m_provider; + private IQuickInfoSession m_session; + + internal DeclarationQuickInfoController(ITextView textView, IList subjectBuffers, DeclarationQuickInfoControllerProvider provider) + { + m_textView = textView; + m_subjectBuffers = subjectBuffers; + m_provider = provider; + + m_textView.MouseHover += this.OnTextViewMouseHover; + } + + private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) + { + //find the mouse position by mapping down to the subject buffer + SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch + (new SnapshotPoint(m_textView.TextSnapshot, e.Position), + PointTrackingMode.Positive, + snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer), + PositionAffinity.Predecessor); + + if (point != null) + { + ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive); + + if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView)) + { + m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true); + } + } + } + + public void Detach(ITextView textView) + { + if (m_textView == textView) + { + m_textView.MouseHover -= this.OnTextViewMouseHover; + m_textView = null; + } + } + + public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + + public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + } +} diff --git a/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoControllerProvider.cs b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoControllerProvider.cs new file mode 100644 index 000000000..7273d8759 --- /dev/null +++ b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoControllerProvider.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IIntellisenseControllerProvider))] + [Name("Declaration QuickInfo Controller")] + [ContentType("CSS")] + internal class DeclarationQuickInfoControllerProvider : IIntellisenseControllerProvider + { + [Import] + internal IQuickInfoBroker QuickInfoBroker { get; set; } + + public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList subjectBuffers) + { + return new DeclarationQuickInfoController(textView, subjectBuffers, this); + } + } +} diff --git a/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoSourceProvider.cs b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoSourceProvider.cs new file mode 100644 index 000000000..aff37b206 --- /dev/null +++ b/EditorExtensions/QuickInfo/Declaration/DeclarationQuickInfoSourceProvider.cs @@ -0,0 +1,26 @@ +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IQuickInfoSourceProvider))] + [Name("Declaration QuickInfo Source")] + [Order(Before = "Selector QuickInfo Source")] + [ContentType("CSS")] + internal class DeclarationQuickInfoSourceProvider : IQuickInfoSourceProvider + { + [Import] + internal ITextStructureNavigatorSelectorService NavigatorService { get; set; } + + [Import] + internal ITextBufferFactoryService TextBufferFactoryService { get; set; } + + public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) + { + return new DeclarationQuickInfo(this, textBuffer); + } + } +} diff --git a/EditorExtensions/QuickInfo/Font/FontQuickInfo.cs b/EditorExtensions/QuickInfo/Font/FontQuickInfo.cs new file mode 100644 index 000000000..cc9e8aed9 --- /dev/null +++ b/EditorExtensions/QuickInfo/Font/FontQuickInfo.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Drawing.Text; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; + +namespace MadsKristensen.EditorExtensions +{ + internal class FontQuickInfo : IQuickInfoSource + { + private FontQuickInfoSourceProvider _provider; + private ITextBuffer _buffer; + private static InstalledFontCollection fonts = new InstalledFontCollection(); + private CssTree _tree; + private List _allowed = new List() { "FONT", "FONT-FAMILY" }; + + public FontQuickInfo(FontQuickInfoSourceProvider provider, ITextBuffer subjectBuffer) + { + _provider = provider; + _buffer = subjectBuffer; + } + + public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiContent, out ITrackingSpan applicableToSpan) + { + applicableToSpan = null; + + if (!EnsureTreeInitialized() || session == null || qiContent == null) + return; + + // Map the trigger point down to our buffer. + SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); + if (!point.HasValue) + return; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(point.Value.Position); + if (item == null || !item.IsValid) + return; + + Declaration dec = item.FindType(); + if (dec == null || !dec.IsValid || !_allowed.Contains(dec.PropertyName.Text.ToUpperInvariant())) + return; + + string fontName = item.Text.Trim('\'', '"'); + + if (fonts.Families.SingleOrDefault(f => f.Name.Equals(fontName, StringComparison.OrdinalIgnoreCase)) != null) + { + FontFamily font = new FontFamily(fontName); + + applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(item.Start, item.Length, SpanTrackingMode.EdgeNegative); + qiContent.Add(CreateFontPreview(font, 10)); + qiContent.Add(CreateFontPreview(font, 11)); + qiContent.Add(CreateFontPreview(font, 12)); + qiContent.Add(CreateFontPreview(font, 14)); + qiContent.Add(CreateFontPreview(font, 25)); + qiContent.Add(CreateFontPreview(font, 40)); + } + } + + /// + /// This must be delayed so that the TextViewConnectionListener + /// has a chance to initialize the WebEditor host. + /// + public bool EnsureTreeInitialized() + { + if (_tree == null)// && WebEditor.GetHost(CssContentTypeDefinition.CssContentType) != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + } + catch (Exception) + { + } + } + + return _tree != null; + } + + private static UIElement CreateFontPreview(FontFamily font, double size) + { + return new TextBlock() + { + Text = font.Source + " (" + size + "px)", + FontFamily = font, + FontSize = size, + }; + } + + private bool m_isDisposed; + public void Dispose() + { + if (!m_isDisposed) + { + GC.SuppressFinalize(this); + m_isDisposed = true; + } + } + } +} diff --git a/EditorExtensions/QuickInfo/Font/FontQuickInfoController.cs b/EditorExtensions/QuickInfo/Font/FontQuickInfoController.cs new file mode 100644 index 000000000..67a913537 --- /dev/null +++ b/EditorExtensions/QuickInfo/Font/FontQuickInfoController.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace MadsKristensen.EditorExtensions +{ + internal class FontQuickInfoController : IIntellisenseController + { + private ITextView m_textView; + private IList m_subjectBuffers; + private FontQuickInfoControllerProvider m_provider; + private IQuickInfoSession m_session; + + internal FontQuickInfoController(ITextView textView, IList subjectBuffers, FontQuickInfoControllerProvider provider) + { + m_textView = textView; + m_subjectBuffers = subjectBuffers; + m_provider = provider; + + m_textView.MouseHover += this.OnTextViewMouseHover; + } + + private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) + { + //find the mouse position by mapping down to the subject buffer + SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch + (new SnapshotPoint(m_textView.TextSnapshot, e.Position), + PointTrackingMode.Positive, + snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer), + PositionAffinity.Predecessor); + + if (point != null) + { + ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, + PointTrackingMode.Positive); + + if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView)) + { + m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true); + } + } + } + + public void Detach(ITextView textView) + { + if (m_textView == textView) + { + m_textView.MouseHover -= this.OnTextViewMouseHover; + m_textView = null; + } + } + + public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + + public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + } +} diff --git a/EditorExtensions/QuickInfo/Font/FontQuickInfoControllerProvider.cs b/EditorExtensions/QuickInfo/Font/FontQuickInfoControllerProvider.cs new file mode 100644 index 000000000..d322b049c --- /dev/null +++ b/EditorExtensions/QuickInfo/Font/FontQuickInfoControllerProvider.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IIntellisenseControllerProvider))] + [Name("Font QuickInfo Controller")] + [ContentType("css")] + internal class FontQuickInfoControllerProvider : IIntellisenseControllerProvider + { + [Import] + internal IQuickInfoBroker QuickInfoBroker { get; set; } + + public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList subjectBuffers) + { + return new FontQuickInfoController(textView, subjectBuffers, this); + } + } +} diff --git a/EditorExtensions/QuickInfo/Font/FontQuickInfoSourceProvider.cs b/EditorExtensions/QuickInfo/Font/FontQuickInfoSourceProvider.cs new file mode 100644 index 000000000..890c865ed --- /dev/null +++ b/EditorExtensions/QuickInfo/Font/FontQuickInfoSourceProvider.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IQuickInfoSourceProvider))] + [Name("Font QuickInfo Source")] + [Order(Before = "Default Quick Info Presenter")] + [ContentType("CSS")] + internal class FontQuickInfoSourceProvider : IQuickInfoSourceProvider + { + [Import] + internal ITextStructureNavigatorSelectorService NavigatorService { get; set; } + + [Import] + internal ITextBufferFactoryService TextBufferFactoryService { get; set; } + + public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) + { + return new FontQuickInfo(this, textBuffer); + } + } +} diff --git a/EditorExtensions/QuickInfo/Image/ImageQuickInfo.cs b/EditorExtensions/QuickInfo/Image/ImageQuickInfo.cs new file mode 100644 index 000000000..6997bacb9 --- /dev/null +++ b/EditorExtensions/QuickInfo/Image/ImageQuickInfo.cs @@ -0,0 +1,159 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System; +using System.Collections.Generic; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; + +namespace MadsKristensen.EditorExtensions +{ + internal class ImageQuickInfo : IQuickInfoSource + { + private ITextBuffer _buffer; + private CssTree _tree; + private static List _imageExtensions = new List() { ".png", ".jpg", "gif", ".jpeg", ".bmp", ".tif", ".tiff" }; + + public ImageQuickInfo(ITextBuffer subjectBuffer) + { + _buffer = subjectBuffer; + } + + public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiContent, out ITrackingSpan applicableToSpan) + { + applicableToSpan = null; + + if (!EnsureTreeInitialized() || session == null || qiContent == null) + return; + + SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); + if (!point.HasValue) + return; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(point.Value.Position); + if (item == null || !item.IsValid) + return; + + UrlItem urlItem = item.FindType(); + + if (urlItem != null && urlItem.UrlString != null && urlItem.UrlString.IsValid) + { + string url = GetFileName(urlItem.UrlString.Text.Trim('\'', '"')); + if (!string.IsNullOrEmpty(url)) + { + applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(point.Value.Position, 1, SpanTrackingMode.EdgeNegative); + var image = CreateImage(url); + if (image != null && image.Source != null) + { + qiContent.Add(image); + qiContent.Add(Math.Round(image.Source.Width) + "x" + Math.Round(image.Source.Height)); + } + } + } + } + + /// + /// This must be delayed so that the TextViewConnectionListener + /// has a chance to initialize the WebEditor host. + /// + public bool EnsureTreeInitialized() + { + if (_tree == null)// && WebEditor.GetHost(CssContentTypeDefinition.CssContentType) != null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + } + catch (Exception) + { + } + } + + return _tree != null; + } + + public static string GetFileName(string text) + { + if (!string.IsNullOrEmpty(text)) + { + if (text.StartsWith("data:", StringComparison.Ordinal)) + return text; + + string imageUrl = text.Trim(new[] { '\'', '"' }); + //if (!_imageExtensions.Contains(Path.GetExtension(imageUrl))) + // return null; + + string filePath = string.Empty; + + if (text.StartsWith("//", StringComparison.Ordinal)) + text = "http:" + text; + + if (text.StartsWith("http://", StringComparison.Ordinal) || text.Contains(";base64,")) + { + return text; + } + else if (imageUrl.StartsWith("/", StringComparison.Ordinal)) + { + string root = ProjectHelpers.GetProjectFolder(EditorExtensionsPackage.DTE.ActiveDocument.FullName); + if (root.Contains("://")) + return root + imageUrl; + else if (!string.IsNullOrEmpty(root)) + filePath = root + imageUrl;// new FileInfo(root).Directory + imageUrl; + } + else if (EditorExtensionsPackage.DTE.ActiveDocument != null) + { + FileInfo fi = new FileInfo(EditorExtensionsPackage.DTE.ActiveDocument.FullName); + DirectoryInfo dir = fi.Directory; + while (imageUrl.Contains("../")) + { + imageUrl = imageUrl.Remove(imageUrl.IndexOf("../", StringComparison.Ordinal), 3); + dir = dir.Parent; + } + + filePath = Path.Combine(dir.FullName, imageUrl.Replace("/", "\\")); + } + + return File.Exists(filePath) ? filePath : "pack://application:,,,/WebEssentials2013;component/Resources/nopreview.png"; + } + + return null; + } + + public static Image CreateImage(string file) + { + try + { + var image = new Image(); + + if (file.StartsWith("data:", StringComparison.Ordinal)) + { + int index = file.IndexOf("base64,", StringComparison.Ordinal) + 7; + byte[] imageBytes = Convert.FromBase64String(file.Substring(index)); + + using (MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length)) + { + image.Source = BitmapFrame.Create(ms, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); + } + } + else if (File.Exists(file)) + { + image.Source = BitmapFrame.Create(new Uri(file), BitmapCreateOptions.None, BitmapCacheOption.OnLoad); + } + + return image; + } + catch (Exception) + { + return null; + } + } + + public void Dispose() + { + // Nothing to dispose + } + } +} diff --git a/EditorExtensions/QuickInfo/Image/ImageQuickInfoController.cs b/EditorExtensions/QuickInfo/Image/ImageQuickInfoController.cs new file mode 100644 index 000000000..779ffe691 --- /dev/null +++ b/EditorExtensions/QuickInfo/Image/ImageQuickInfoController.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions.QuickInfo +{ + internal class ImageQuickInfoController : IIntellisenseController + { + private ITextView m_textView; + private IList m_subjectBuffers; + private ImageQuickInfoControllerProvider m_provider; + + internal ImageQuickInfoController(ITextView textView, IList subjectBuffers, ImageQuickInfoControllerProvider provider) + { + m_textView = textView; + m_subjectBuffers = subjectBuffers; + m_provider = provider; + + m_textView.MouseHover += this.OnTextViewMouseHover; + } + + private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) + { + //find the mouse position by mapping down to the subject buffer + SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch + (new SnapshotPoint(m_textView.TextSnapshot, e.Position), + PointTrackingMode.Positive, + snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer), + PositionAffinity.Predecessor); + + if (point != null) + { + ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, + PointTrackingMode.Positive); + + if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView)) + { + m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true); + } + } + } + + public void Detach(ITextView textView) + { + if (m_textView == textView) + { + m_textView.MouseHover -= this.OnTextViewMouseHover; + m_textView = null; + } + } + + + public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + + public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + } +} diff --git a/EditorExtensions/QuickInfo/Image/ImageQuickInfoControllerProvider.cs b/EditorExtensions/QuickInfo/Image/ImageQuickInfoControllerProvider.cs new file mode 100644 index 000000000..6ea93cd0b --- /dev/null +++ b/EditorExtensions/QuickInfo/Image/ImageQuickInfoControllerProvider.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions.QuickInfo +{ + [Export(typeof(IIntellisenseControllerProvider))] + [Name("Image QuickInfo Controller")] + [ContentType("CSS")] + internal class ImageQuickInfoControllerProvider : IIntellisenseControllerProvider + { + [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IQuickInfoBroker QuickInfoBroker { get; set; } + + public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList subjectBuffers) + { + return new ImageQuickInfoController(textView, subjectBuffers, this); + } + } +} diff --git a/EditorExtensions/QuickInfo/Image/ImageQuickInfoSourceProvider.cs b/EditorExtensions/QuickInfo/Image/ImageQuickInfoSourceProvider.cs new file mode 100644 index 000000000..6d75be576 --- /dev/null +++ b/EditorExtensions/QuickInfo/Image/ImageQuickInfoSourceProvider.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions.QuickInfo +{ + [Export(typeof(IQuickInfoSourceProvider))] + [Name("Image QuickInfo Source")] + [Order(Before = "Default Quick Info Presenter")] + [ContentType("CSS")] + internal class ImageQuickInfoSourceProvider : IQuickInfoSourceProvider + { + public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) + { + return new ImageQuickInfo(textBuffer); + } + } +} diff --git a/EditorExtensions/QuickInfo/Selector/SelectorQuickInfo.cs b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfo.cs new file mode 100644 index 000000000..08e21c6e1 --- /dev/null +++ b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfo.cs @@ -0,0 +1,94 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System; +using System.Collections.Generic; +using System.Text; + +namespace MadsKristensen.EditorExtensions +{ + internal class SelectorQuickInfo : IQuickInfoSource + { + private SelectorQuickInfoSourceProvider _provider; + private ITextBuffer _buffer; + private CssTree _tree; + + public SelectorQuickInfo(SelectorQuickInfoSourceProvider provider, ITextBuffer subjectBuffer) + { + _provider = provider; + _buffer = subjectBuffer; + } + + public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiContent, out ITrackingSpan applicableToSpan) + { + applicableToSpan = null; + + if (!EnsureTreeInitialized() || session == null || qiContent == null) + return; + + // Map the trigger point down to our buffer. + SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); + if (!point.HasValue) + return; + + ParseItem item = _tree.StyleSheet.ItemBeforePosition(point.Value.Position); + if (item == null || !item.IsValid) + return; + + Selector sel = item.FindType(); + if (sel == null) + return; + + applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(item.Start, item.Length, SpanTrackingMode.EdgeNegative); + + string content = GenerateContent(sel); + qiContent.Add(content); + } + + private static string GenerateContent(Selector sel) + { + SelectorSpecificity specificity = new SelectorSpecificity(sel); + + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Selector specificity:\t\t" + specificity.ToString()); + //sb.AppendLine(" - IDs:\t\t\t\t" + specificity.IDs); + //sb.AppendLine(" - Classes:\t\t\t" + (specificity.Classes + specificity.PseudoClasses)); + //sb.AppendLine(" - Attributes:\t\t" + specificity.Attributes); + //sb.AppendLine(" - Elements:\t\t" + (specificity.Elements + specificity.PseudoElements)); + + return sb.ToString().Trim(); + } + + /// + /// This must be delayed so that the TextViewConnectionListener + /// has a chance to initialize the WebEditor host. + /// + public bool EnsureTreeInitialized() + { + if (_tree == null) + { + try + { + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + _tree = document.Tree; + } + catch (Exception) + { + } + } + + return _tree != null; + } + + private bool m_isDisposed; + public void Dispose() + { + if (!m_isDisposed) + { + GC.SuppressFinalize(this); + m_isDisposed = true; + } + } + } +} diff --git a/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoController.cs b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoController.cs new file mode 100644 index 000000000..41c26cfb3 --- /dev/null +++ b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoController.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace MadsKristensen.EditorExtensions +{ + internal class SelectorQuickInfoController : IIntellisenseController + { + private ITextView m_textView; + private IList m_subjectBuffers; + private SelectorQuickInfoControllerProvider m_provider; + private IQuickInfoSession m_session; + + internal SelectorQuickInfoController(ITextView textView, IList subjectBuffers, SelectorQuickInfoControllerProvider provider) + { + m_textView = textView; + m_subjectBuffers = subjectBuffers; + m_provider = provider; + + m_textView.MouseHover += this.OnTextViewMouseHover; + } + + private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) + { + //find the mouse position by mapping down to the subject buffer + SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch + (new SnapshotPoint(m_textView.TextSnapshot, e.Position), + PointTrackingMode.Positive, + snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer), + PositionAffinity.Predecessor); + + if (point != null) + { + ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, + PointTrackingMode.Positive); + + if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView)) + { + m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true); + } + } + } + + public void Detach(ITextView textView) + { + if (m_textView == textView) + { + m_textView.MouseHover -= this.OnTextViewMouseHover; + m_textView = null; + } + } + + public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + + public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) + { + } + } +} diff --git a/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoControllerProvider.cs b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoControllerProvider.cs new file mode 100644 index 000000000..aec2896d2 --- /dev/null +++ b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoControllerProvider.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IIntellisenseControllerProvider))] + [Name("Selector QuickInfo Controller")] + [ContentType("CSS")] + internal class SelectorQuickInfoControllerProvider : IIntellisenseControllerProvider + { + [Import] + internal IQuickInfoBroker QuickInfoBroker { get; set; } + + public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList subjectBuffers) + { + return new SelectorQuickInfoController(textView, subjectBuffers, this); + } + } +} diff --git a/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoSourceProvider.cs b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoSourceProvider.cs new file mode 100644 index 000000000..7deff2334 --- /dev/null +++ b/EditorExtensions/QuickInfo/Selector/SelectorQuickInfoSourceProvider.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Utilities; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(IQuickInfoSourceProvider))] + [Name("Selector QuickInfo Source")] + [Order(Before = "Default Quick Info Presenter")] + [ContentType("CSS")] + internal class SelectorQuickInfoSourceProvider : IQuickInfoSourceProvider + { + [Import] + internal ITextStructureNavigatorSelectorService NavigatorService { get; set; } + + [Import] + internal ITextBufferFactoryService TextBufferFactoryService { get; set; } + + public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) + { + return new SelectorQuickInfo(this, textBuffer); + } + } +} diff --git a/EditorExtensions/QuickInfo/Selector/SelectorSpecificity.cs b/EditorExtensions/QuickInfo/Selector/SelectorSpecificity.cs new file mode 100644 index 000000000..43b6846fb --- /dev/null +++ b/EditorExtensions/QuickInfo/Selector/SelectorSpecificity.cs @@ -0,0 +1,84 @@ +using Microsoft.CSS.Core; +using System.Linq; + +namespace MadsKristensen.EditorExtensions +{ + internal class SelectorSpecificity + { + private Selector _selector; + + public SelectorSpecificity(Selector selector) + { + _selector = selector; + Calculate(); + } + + public int IDs { get; set; } + public int Classes { get; set; } + public int Elements { get; set; } + public int PseudoClasses { get; set; } + public int PseudoElements { get; set; } + public int Attributes { get; set; } + //public int Total { get; set; } + + public override string ToString() + { + return IDs + ", " + (Classes + PseudoClasses + Attributes) + ", " + (Elements + PseudoElements); + } + + private void Calculate() + { + // IDs + var visitorIDs = new CssItemCollector(); + _selector.Accept(visitorIDs); + + if (visitorIDs.Items.Count > 0) + IDs = visitorIDs.Items.Count;// *100; + + // Classes + var visitorClasses = new CssItemCollector(); + _selector.Accept(visitorClasses); + + if (visitorClasses.Items.Count > 0) + Classes = visitorClasses.Items.Count;// *10; + + // Attributes + var visitorAttribute = new CssItemCollector(); + _selector.Accept(visitorAttribute); + + if (visitorAttribute.Items.Count > 0) + Attributes = visitorAttribute.Items.Count;// *10; + + // Elements + var visitorElements = new CssItemCollector(); + _selector.Accept(visitorElements); + Elements = visitorElements.Items.Where(i => i.Text != "*" && i.FindType() == null).Count(); + + // Pseudo Elements + var visitorPseudoElementSelector = new CssItemCollector(); + _selector.Accept(visitorPseudoElementSelector); + + var visitorPseudoElementFunctionSelector = new CssItemCollector(); + _selector.Accept(visitorPseudoElementFunctionSelector); + + PseudoElements = visitorPseudoElementSelector.Items.Count + visitorPseudoElementFunctionSelector.Items.Count; + + // Pseudo Classes + var visitorPseudoClassSelector = new CssItemCollector(); + _selector.Accept(visitorPseudoClassSelector); + + var visitorPseudoClassFunctionSelector = new CssItemCollector(true); + _selector.Accept(visitorPseudoClassFunctionSelector); + + int pseudoClases = visitorPseudoClassSelector.Items.Count(p => !p.IsPseudoElement()); + pseudoClases += visitorPseudoClassFunctionSelector.Items.Where(p => !p.Text.StartsWith(":not(") && !p.Text.StartsWith(":matches(")).Count(); + Elements += visitorPseudoClassSelector.Items.Count(p => p.IsPseudoElement()); + + if (pseudoClases > 0) + PseudoClasses = pseudoClases;// *10; + + // Total + //Total = IDs + Classes + Attributes + Elements + PseudoElements + PseudoClasses; + } + } +} diff --git a/EditorExtensions/QuickInfo/ValueOrder/RemoveCssSignatureHelpSource.cs b/EditorExtensions/QuickInfo/ValueOrder/RemoveCssSignatureHelpSource.cs new file mode 100644 index 000000000..56b2a1c7a --- /dev/null +++ b/EditorExtensions/QuickInfo/ValueOrder/RemoveCssSignatureHelpSource.cs @@ -0,0 +1,63 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System; +using System.Collections.Generic; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal class RemoveCssSignatureHelpSource : ISignatureHelpSource + { + private ITextBuffer _buffer; + + public RemoveCssSignatureHelpSource(ITextBuffer buffer) + { + _buffer = buffer; + } + + public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList signatures) + { + SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); + if (!point.HasValue) + return; + + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + ParseItem item = document.StyleSheet.ItemBeforePosition(point.Value.Position); + + if (item == null) + return; + + Declaration dec = item.FindType(); + if (dec == null || dec.PropertyName == null || dec.Colon == null) + return; + + foreach (ISignature signature in signatures) + { + if (signature is ValueOrderSignature) + { + signatures.RemoveAt(signatures.Count - 1); + break; + } + } + } + + public ISignature GetBestMatch(ISignatureHelpSession session) + { + return (session.Signatures != null && session.Signatures.Count > 0) + ? session.Signatures[0] + : null; + } + + private bool m_isDisposed; + public void Dispose() + { + if (!m_isDisposed) + { + GC.SuppressFinalize(this); + m_isDisposed = true; + } + } + } +} diff --git a/EditorExtensions/QuickInfo/ValueOrder/ValueOrderFactory.cs b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderFactory.cs new file mode 100644 index 000000000..fb2d206d0 --- /dev/null +++ b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderFactory.cs @@ -0,0 +1,204 @@ +using Microsoft.CSS.Core; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System.Collections.Generic; + +namespace MadsKristensen.EditorExtensions +{ + internal static class ValueOrderFactory + { + public delegate void AddSignatures(ISignatureHelpSession session, IList signatures, Declaration dec, ITrackingSpan span); + + public static AddSignatures GetMethod(Declaration dec) + { + switch (dec.PropertyName.Text.ToLowerInvariant()) + { + case "margin": + case "padding": + case "border-width": + case "outline-width": + return Margins; + + case "border-radius": + return Corners; + + case "border": + return Borders; + + case "font": + return Fonts; + + case "columns": + return Columns; + } + + return null; + } + + private static void Margins(ISignatureHelpSession session, IList signatures, Declaration dec, ITrackingSpan span) + { + string value1 = "3px"; + string value2 = "4px"; + string value3 = "5px"; + string value4 = "6px"; + + if (dec.Values.Count > 0) + { + value1 = dec.Values[0].Text; + value2 = dec.Values.Count > 1 ? dec.Values[1].Text : value2; + value3 = dec.Values.Count > 2 ? dec.Values[2].Text : value3; + value4 = dec.Values.Count > 3 ? dec.Values[3].Text : value4; + } + + ValueOrderSignature signature1 = new ValueOrderSignature( + string.Format("div {{ {0}: {1} {2} {3} {4}; }} ", dec.PropertyName.Text, value1, value2, value3, value4), + string.Format("[top={0}] [right={1}] [bottom={2}] [left={3}]", value1, value2, value3, value4), + span, session); + + ValueOrderSignature signature2 = new ValueOrderSignature( + string.Format("div {{ {0}: {1} {2} {3}; }} ", dec.PropertyName.Text, value1, value2, value3), + string.Format("[top={0}] [right and left={1}] [bottom={2}]", value1, value2, value3), + span, session); + + ValueOrderSignature signature3 = new ValueOrderSignature( + string.Format("div {{ {0}: {1} {2}; }} ", dec.PropertyName.Text, value1, value2), + string.Format("[top and bottom={0}] [right and left={1}]", value1, value2), + span, session); + + ValueOrderSignature signature4 = new ValueOrderSignature( + string.Format("div {{ {0}: {1}; }} ", dec.PropertyName.Text, value1), + string.Format("[top and right and bottom and left={0}]", value1), + span, session); + + signatures.Add(signature1); + signatures.Add(signature2); + signatures.Add(signature3); + signatures.Add(signature4); + } + + private static void Corners(ISignatureHelpSession session, IList signatures, Declaration dec, ITrackingSpan span) + { + string value1 = "3px"; + string value2 = "4px"; + string value3 = "5px"; + string value4 = "6px"; + + if (dec.Values.Count > 0) + { + value1 = dec.Values[0].Text; + value2 = dec.Values.Count > 1 ? dec.Values[1].Text : value2; + value3 = dec.Values.Count > 2 ? dec.Values[2].Text : value3; + value4 = dec.Values.Count > 3 ? dec.Values[3].Text : value4; + + } + ValueOrderSignature signature1 = new ValueOrderSignature( + string.Format("div {{ {0}: {1} {2} {3} {4}; }} ", dec.PropertyName.Text, value1, value2, value3, value4), + string.Format("[top-left={0}] [top-right={1}] [bottom-right={2}] [bottom-left={3}]", value1, value2, value3, value4), + span, session); + + ValueOrderSignature signature2 = new ValueOrderSignature( + string.Format("div {{ {0}: {1} {2} {3}; }} ", dec.PropertyName.Text, value1, value2, value3), + string.Format("[top-left={0}] [top-right and bottom-left={1}] [bottom-right={2}]", value1, value2, value3), + span, session); + + ValueOrderSignature signature3 = new ValueOrderSignature( + string.Format("div {{ {0}: {1} {2}; }} ", dec.PropertyName.Text, value1, value2), + string.Format("[top-left and bottom-right={0}] [top-right and bottom-left={1}]", value1, value2), + span, session); + + ValueOrderSignature signature4 = new ValueOrderSignature( + string.Format("div {{ {0}: {1}; }} ", dec.PropertyName.Text, value1), + string.Format("[top-left and top-right and bottom-right and bottom-left={0}]", value1), + span, session); + + signatures.Add(signature1); + signatures.Add(signature2); + signatures.Add(signature3); + signatures.Add(signature4); + } + + private static void Borders(ISignatureHelpSession session, IList signatures, Declaration dec, ITrackingSpan span) + { + ValueOrderSignature signature1 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": 1px solid red; } ", + "[border-width=1px] [border-style=solid] [border-color=red]", + span, session); + + ValueOrderSignature signature2 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": 1px solid; } ", + "[border-width=1px] [border-style=solid] [border-color='color']", + span, session); + + ValueOrderSignature signature3 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": solid; } ", + "[border-width=3px] [border-style=solid] [border-color='color']", + span, session); + + signatures.Add(signature1); + signatures.Add(signature2); + signatures.Add(signature3); + } + + private static void Fonts(ISignatureHelpSession session, IList signatures, Declaration dec, ITrackingSpan span) + { + ValueOrderSignature signature1 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": italic small-caps bold 13px/150% Arial; } ", + "[font-style=italic] [font-variant=small-caps] [font-weight=bold] [font-size=12px]/[line-height=150%] [font-family=Arial]", + span, session); + + ValueOrderSignature signature2 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": small-caps bold 13px/150% Arial; } ", + "[font-variant=small-caps] [font-weight=bold] [font-size=12px]/[line-height=150%] [font-family=Arial]", + span, session); + + ValueOrderSignature signature3 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": bold 13px/150% Arial; } ", + "[font-weight=bold] [font-size=12px]/[line-height=150%] [font-family=Arial]", + span, session); + + ValueOrderSignature signature4 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": 13px/150% Arial; } ", + "[font-size=12px]/[line-height=150%] [font-family=Arial]", + span, session); + + ValueOrderSignature signature5 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": 13px Arial; } ", + "[font-size=13px] [font-family=Arial]", + span, session); + + signatures.Add(signature5); + signatures.Add(signature4); + signatures.Add(signature3); + signatures.Add(signature2); + signatures.Add(signature1); + } + + private static void Columns(ISignatureHelpSession session, IList signatures, Declaration dec, ITrackingSpan span) + { + ValueOrderSignature signature1 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": 12em; } ", + "[column-width=12em] [column-count=auto]", + span, session); + + ValueOrderSignature signature2 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": auto 12em; } ", + "[column-width=12em] [column-count=auto]", + span, session); + + ValueOrderSignature signature3 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": auto; } ", + "[column-width=auto] [column-count=auto]", + span, session); + + ValueOrderSignature signature4 = new ValueOrderSignature( + "div { " + dec.PropertyName.Text + ": 2; } ", + "[column-width=auto] [column-count=2]", + span, session); + + signatures.Add(signature1); + signatures.Add(signature2); + signatures.Add(signature3); + signatures.Add(signature4); + } + } +} diff --git a/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignature.cs b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignature.cs new file mode 100644 index 000000000..853f52478 --- /dev/null +++ b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignature.cs @@ -0,0 +1,199 @@ +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; + +namespace MadsKristensen.EditorExtensions +{ + public class ValueOrderSignature : ISignature + { + private string _propertyName; + private string _syntax; + private string _description; + private string _content; + private CssPropertyNameParameter _nameParam; + private IParameter _currentParam; + private ITrackingSpan _trackingSpan; + private ISignatureHelpSession _session; + + public event EventHandler CurrentParameterChanged; + + public ValueOrderSignature( + string syntax, + string description, + ITrackingSpan trackingSpan, + ISignatureHelpSession session) + { + + _propertyName = "Syntax"; + _syntax = syntax ?? string.Empty; + _description = description; + _trackingSpan = trackingSpan; + + _content = string.Format(CultureInfo.InvariantCulture, "{0}: {1}", _propertyName, _syntax); + _nameParam = new CssPropertyNameParameter(this); + _currentParam = _nameParam; + + _session = session; + + // In order to dismiss this tip at the appropriate time, I need to listen + // to changes in the text buffer + if (_trackingSpan != null && _session != null) + { + _session.Dismissed += OnSessionDismissed; + _trackingSpan.TextBuffer.Changed += OnTextBufferChanged; + } + } + + public ITrackingSpan ApplicableToSpan + { + get { return _trackingSpan; } + } + + public string PropertyName + { + get { return _propertyName; } + } + + public string Content + { + get { return _content; } + } + + public IParameter CurrentParameter + { + get { return _nameParam; } + + set + { + if (value != _currentParam) + { + IParameter oldParam = _currentParam; + _currentParam = value; + + if (CurrentParameterChanged != null) + { + CurrentParameterChanged(this, new CurrentParameterChangedEventArgs(oldParam, _currentParam)); + } + } + } + } + + public string Documentation + { + get { return _description; } + } + + public ReadOnlyCollection Parameters + { + get + { + IList parameters = new List(); + parameters.Add(_nameParam); + + return new ReadOnlyCollection(parameters); + } + } + + /// + /// This is called when there isn't enough room on the screen to show the normal content + /// + public string PrettyPrintedContent + { + get { return Content; } + } + + /// + /// I'm about to be destroyed, so stop listening to events + /// + private void OnSessionDismissed(object sender, System.EventArgs eventArgs) + { + if (_trackingSpan != null) + { + _trackingSpan.TextBuffer.Changed -= OnTextBufferChanged; + } + + if (_session != null) + { + _session.Dismissed -= OnSessionDismissed; + _session = null; + } + } + + /// + /// Check if the property name in the text buffer has changed. + /// If so, then dismiss the syntax help tip. + /// + private void OnTextBufferChanged(object sender, TextContentChangedEventArgs eventArgs) + { + if (_trackingSpan != null && _session != null) + { + ITextSnapshot snapshot = _trackingSpan.TextBuffer.CurrentSnapshot; + SnapshotPoint startPoint = _trackingSpan.GetStartPoint(snapshot); + bool propertyNameStillValid = false; + + if (startPoint.Position + _propertyName.Length <= snapshot.Length) + { + // Get the current text at the beginning of the tracking span. + + string text = snapshot.GetText(startPoint.Position, _propertyName.Length); + + char afterText = (startPoint.Position + _propertyName.Length < snapshot.Length) + ? snapshot.GetText(startPoint.Position + _propertyName.Length, 1)[0] + : '\0'; + + if (string.Equals(text, _propertyName, StringComparison.OrdinalIgnoreCase) && + !char.IsLetterOrDigit(afterText) && + afterText != '-') + { + // The correct property name is still in the code + propertyNameStillValid = true; + } + } + + if (!propertyNameStillValid) + { + _session.Dismiss(); + } + } + } + } + + internal class CssPropertyNameParameter : IParameter + { + private ValueOrderSignature _signature; + + public CssPropertyNameParameter(ValueOrderSignature signature) + { + _signature = signature; + } + + public string Documentation + { + get { return null; } + } + + public Span Locus + { + get { return new Span(0, _signature.PropertyName.Length); } + } + + public string Name + { + get { return _signature.PropertyName; } + } + + public Span PrettyPrintedLocus + { + get { return Locus; } + } + + public ISignature Signature + { + get { return _signature; } + } + } + +} diff --git a/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignatureHelpSource.cs b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignatureHelpSource.cs new file mode 100644 index 000000000..422a018bc --- /dev/null +++ b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignatureHelpSource.cs @@ -0,0 +1,83 @@ +using Microsoft.CSS.Core; +using Microsoft.CSS.Editor; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using System; +using System.Collections.Generic; +using System.Windows.Threading; + +namespace MadsKristensen.EditorExtensions +{ + internal class ValueOrderSignatureHelpSource : ISignatureHelpSource + { + private ITextBuffer _buffer; + + public ValueOrderSignatureHelpSource(ITextBuffer buffer) + { + _buffer = buffer; + } + + public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList signatures) + { + SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); + if (!point.HasValue) + return; + + CssEditorDocument document = CssEditorDocument.FromTextBuffer(_buffer); + ParseItem item = document.StyleSheet.ItemBeforePosition(point.Value.Position); + + if (item == null) + return; + + Declaration dec = item.FindType(); + if (dec == null || dec.PropertyName == null || dec.Colon == null) + return; + + var span = _buffer.CurrentSnapshot.CreateTrackingSpan(dec.Colon.Start, dec.Length - dec.PropertyName.Length, SpanTrackingMode.EdgeNegative); + + ValueOrderFactory.AddSignatures method = ValueOrderFactory.GetMethod(dec); + + if (method != null) + { + signatures.Clear(); + method(session, signatures, dec, span); + + Dispatcher.CurrentDispatcher.BeginInvoke( + new Action(() => { + session.Properties.AddProperty("dec", dec); + session.Match(); + }), + DispatcherPriority.Normal, null); + } + } + + public ISignature GetBestMatch(ISignatureHelpSession session) + { + int number = 0; + + if (session.Properties.ContainsProperty("dec")) + { + Declaration dec = session.Properties["dec"] as Declaration; + string methodName = ValueOrderFactory.GetMethod(dec).Method.Name; + if (dec.Values.Count > 0 && (methodName == "Margins" || methodName == "Corners")) + { + number = 4 - dec.Values.Count; + } + } + + return (session.Signatures != null && session.Signatures.Count > number && number > -1) + ? session.Signatures[number] + : null; + } + + private bool m_isDisposed; + public void Dispose() + { + if (!m_isDisposed) + { + GC.SuppressFinalize(this); + m_isDisposed = true; + } + } + } +} diff --git a/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignatureHelpSourceProvider.cs b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignatureHelpSourceProvider.cs new file mode 100644 index 000000000..bdd32630b --- /dev/null +++ b/EditorExtensions/QuickInfo/ValueOrder/ValueOrderSignatureHelpSourceProvider.cs @@ -0,0 +1,32 @@ +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Utilities; +using Microsoft.Web.Editor; +using System.ComponentModel.Composition; + +namespace MadsKristensen.EditorExtensions +{ + [Export(typeof(ISignatureHelpSourceProvider))] + [Name("Value Order Signature Help Source")] + [Order(Before = "CSS Signature Help Source")] + [ContentType(CssContentTypeDefinition.CssContentType)] + internal class ValueOrderSignatureHelpSourceProvider : ISignatureHelpSourceProvider + { + public ISignatureHelpSource TryCreateSignatureHelpSource(ITextBuffer textBuffer) + { + return new ValueOrderSignatureHelpSource(textBuffer); + } + } + + [Export(typeof(ISignatureHelpSourceProvider))] + [Name("Value Order Signature Help Source2")] + [Order(After = "Default")] + [ContentType(CssContentTypeDefinition.CssContentType)] + internal class RemoveCssSignatureHelpSourceProvider : ISignatureHelpSourceProvider + { + public ISignatureHelpSource TryCreateSignatureHelpSource(ITextBuffer textBuffer) + { + return new RemoveCssSignatureHelpSource(textBuffer); + } + } +} diff --git a/EditorExtensions/QuickLaunch/Nuget/NugetSearchProvider.cs b/EditorExtensions/QuickLaunch/Nuget/NugetSearchProvider.cs new file mode 100644 index 000000000..fc4565d59 --- /dev/null +++ b/EditorExtensions/QuickLaunch/Nuget/NugetSearchProvider.cs @@ -0,0 +1,86 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Media.Imaging; +using Microsoft.Internal.VisualStudio.PlatformUI; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.MSDNSearch +{ + /// + /// Search Provider for MSDN Library + /// GUID uniquely identifies and differentiates MSDN search from other QuickLaunch searches + /// + [Guid("042C2B4B-C7F7-49DB-B7A2-402EB8DC7891")] + public class NugetSearchProvider : IVsSearchProvider + { + // Defines all string variables like Description(Hover over Search Heading), Search Heading text, Category Shortcut + private const string _description = "search through Nuget gallery"; + private const string _displayText = "Nuget Gallery"; + private const string _categoryShortcut = "nuget"; + + public Guid Category + { + get { return GetType().GUID; } + } + + public IVsSearchTask CreateSearch(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchProviderCallback pSearchCallback) + { + if (dwCookie == VSConstants.VSCOOKIE_NIL) + { + return null; + } + + return new NugetSearchTask(this, dwCookie, pSearchQuery, pSearchCallback); + } + + public IVsSearchItemResult CreateItemResult(string lpszPersistenceData) + { + char[] delim = { '|' }; + string[] strArr = lpszPersistenceData.Split(delim); + string displayText = strArr[0]; + string url = strArr[1]; + + return new NugetSearchResult(displayText, url, this); + } + + public string DisplayText + { + get { return _displayText; } + } + + public string Description + { + get + { + return _description; + } + } + + public void ProvideSearchSettings(IVsUIDataSource pSearchOptions) + { + } + + public string Shortcut + { + get + { + return _categoryShortcut; + } + } + + public string Tooltip + { + get { return null; } //no additional tooltip + } + + public IVsUIObject Icon + { + get + { + var image = BitmapFrame.Create(new Uri("pack://application:,,,/EditorExtensions;component/Resources/nuget.png", UriKind.RelativeOrAbsolute)); + return WpfPropertyValue.CreateIconObject(image); + } + } + } +} diff --git a/EditorExtensions/QuickLaunch/Nuget/NugetSearchResult.cs b/EditorExtensions/QuickLaunch/Nuget/NugetSearchResult.cs new file mode 100644 index 000000000..f4adab104 --- /dev/null +++ b/EditorExtensions/QuickLaunch/Nuget/NugetSearchResult.cs @@ -0,0 +1,68 @@ +using System; +using System.Diagnostics; +using System.Windows.Media.Imaging; +using Microsoft.Internal.VisualStudio.PlatformUI; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.MSDNSearch +{ + public class NugetSearchResult : IVsSearchItemResult + { + private string url; + + public NugetSearchResult(string displaytext, string url, NugetSearchProvider provider) + { + this.DisplayText = displaytext; + this.SearchProvider = provider; + this.url = url; + this.PersistenceData = displaytext + "|" + url; + this.Icon = provider.Icon; + } + + public VisualStudio.OLE.Interop.IDataObject DataObject + { + get { return null; } + } + + public string Description + { + get; + private set; + } + + public string DisplayText + { + get; + private set; + } + + public IVsUIObject Icon + { + get; + private set; + } + + public void InvokeAction() + { + Process.Start(this.url); + } + + public string PersistenceData + { + get; + private set; + } + + public IVsSearchProvider SearchProvider + { + get; + private set; + } + + public string Tooltip + { + get; + private set; + } + } +} diff --git a/EditorExtensions/QuickLaunch/Nuget/NugetSearchTask.cs b/EditorExtensions/QuickLaunch/Nuget/NugetSearchTask.cs new file mode 100644 index 000000000..0ef816247 --- /dev/null +++ b/EditorExtensions/QuickLaunch/Nuget/NugetSearchTask.cs @@ -0,0 +1,99 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using System.Xml; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.MSDNSearch +{ + public class NugetSearchTask : VsSearchTask + { + private NugetSearchProvider provider; + + public NugetSearchTask(NugetSearchProvider provider, uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchProviderCallback pSearchCallback) + : base(dwCookie, pSearchQuery, pSearchCallback) + { + this.provider = provider; + } + + // Startes the search by sending Query to MSDN + protected override void OnStartSearch() + { + var webQuery = this.GetWebQuery(this.SearchQuery); + + try + { + //parser code to parse through RSS results + var xmlDocument = new XmlDocument(); + xmlDocument.Load(webQuery); + var root = xmlDocument.DocumentElement; + + //each item/entry is a unique result + var entries = root.GetElementsByTagName("item"); + if (entries.Count == 0) + entries = root.GetElementsByTagName("entry"); + + foreach (var node in entries) + { + var entry = node as XmlElement; + if (entry != null) + { + string title = null; + string url = null; + + //title tag provides result title + var titleNodes = entry.GetElementsByTagName("title"); + if (titleNodes.Count > 0) + { + title = (titleNodes[0] as XmlElement).InnerText; + } + + //link / url / id tag provides the URL linking the result string to its page + var linkNodes = entry.GetElementsByTagName("link"); + if (linkNodes.Count == 0) + linkNodes = entry.GetElementsByTagName("url"); + if (linkNodes.Count == 0) + linkNodes = entry.GetElementsByTagName("id"); + + if (linkNodes.Count > 0) + { + url = (linkNodes[0] as XmlElement).Attributes["href"].InnerText; + } + + if (title != null && url != null) + { + var result = new NugetSearchResult(title, url, this.provider); + + this.SearchCallback.ReportResult(this, result); + } + } + } + + this.SearchCallback.ReportComplete(this, (uint)entries.Count); + } + catch (Exception) + { + } + + //base.OnStartSearch(); + } + + protected new IVsSearchProviderCallback SearchCallback + { + get + { + return (IVsSearchProviderCallback)base.SearchCallback; + } + } + + public string GetWebQuery(IVsSearchQuery pSearchQuery) + { + //"http://nuget.org/api/v2/Packages()?$orderby=DownloadCount%20desc,Id,LastUpdated%20desc&$filter=((((Id%20ne%20null)%20and%20substringof('{0}',tolower(Id)))%20or%20((Description%20ne%20null)%20and%20substringof('{0}',tolower(Description))))%20or%20((Tags%20ne%20null)%20and%20substringof('%20{0}%20',tolower(Tags))))%20and%20IsAbsoluteLatestVersion&$select=Id,Version,Authors,DownloadCount,VersionDownloadCount,PackageHash,PackageSize&$top=15", + return string.Format( + "http://nuget.org/api/v2/Packages()?$orderby=DownloadCount%20desc,Id,LastUpdated%20desc&$filter=((((Id%20ne%20null)%20and%20substringof('{0}',tolower(Id)))%20or%20((Description%20ne%20null)%20and%20substringof('{0}',tolower(Description))))%20or%20((Tags%20ne%20null)%20and%20substringof('%20{0}%20',tolower(Tags))))%20and%20IsAbsoluteLatestVersion&$select=Id&$top=10", + HttpUtility.UrlEncode(pSearchQuery.SearchString)); + } + } +} diff --git a/EditorExtensions/QuickLaunch/VSGallery/VSSearchProvider.cs b/EditorExtensions/QuickLaunch/VSGallery/VSSearchProvider.cs new file mode 100644 index 000000000..5897dd283 --- /dev/null +++ b/EditorExtensions/QuickLaunch/VSGallery/VSSearchProvider.cs @@ -0,0 +1,93 @@ +using Microsoft.Internal.VisualStudio.PlatformUI; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; +using System; +using System.Runtime.InteropServices; +using System.Windows.Media.Imaging; + +namespace Microsoft.MSDNSearch +{ + /// + /// Search Provider for MSDN Library + /// GUID uniquely identifies and differentiates MSDN search from other QuickLaunch searches + /// + [Guid("042C2B4B-C7F7-49DB-B7A2-402EB8DC7892")] + public class VSSearchProvider : IVsSearchProvider + { + // Defines all string variables like Description(Hover over Search Heading), Search Heading text, Category Shortcut + private const string DescriptionString = "search through the Visual Studio Gallery"; + private const string DisplayTextString = "Visual Studio Gallery"; + private const string CategoryShortcutString = "vs"; + + // Get the GUID that identifies this search provider + public Guid Category + { + get { return GetType().GUID; } + } + + //Main Search method that calls MSDNSearchTask to create and execute search query + public IVsSearchTask CreateSearch(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchProviderCallback pSearchCallback) + { + if (dwCookie == VSConstants.VSCOOKIE_NIL) + { + return null; + } + + return new VSSearchTask(this, dwCookie, pSearchQuery, pSearchCallback); + } + + //Verifies persistent data to populate MRU list with previously selected result + public IVsSearchItemResult CreateItemResult(string lpszPersistenceData) + { + char[] delim = { '|' }; + string[] strArr = lpszPersistenceData.Split(delim); + string displayText = strArr[0]; + string url = strArr[1]; + + return new VSSearchResult(displayText, url, this); + } + + //MSDN Search Category Heading + public string DisplayText + { + get { return DisplayTextString; } + } + + //MSDN Search Description - shows as tooltip on hover over Search Category Heading + public string Description + { + get + { + return DescriptionString; + } + } + + // + public void ProvideSearchSettings(IVsUIDataSource pSearchOptions) + { + } + + //MSDN Category shortcut to scope results to to show only from MSDN Library + public string Shortcut + { + get + { + return CategoryShortcutString; + } + } + + public string Tooltip + { + get { return null; } //no additional tooltip + } + + public IVsUIObject Icon + { + get + { + var image = BitmapFrame.Create(new Uri("pack://application:,,,/WebEssentials2013;component/Resources/vsgallery.png", UriKind.RelativeOrAbsolute)); + return WpfPropertyValue.CreateIconObject(image); + } + } + } +} diff --git a/EditorExtensions/QuickLaunch/VSGallery/VSSearchResult.cs b/EditorExtensions/QuickLaunch/VSGallery/VSSearchResult.cs new file mode 100644 index 000000000..1119d9810 --- /dev/null +++ b/EditorExtensions/QuickLaunch/VSGallery/VSSearchResult.cs @@ -0,0 +1,68 @@ +using System.Diagnostics; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.MSDNSearch +{ + public class VSSearchResult : IVsSearchItemResult + { + private string url; + + public VSSearchResult(string displaytext, string url, VSSearchProvider provider) + { + this.DisplayText = displaytext; + this.SearchProvider = provider; + this.url = url; + this.PersistenceData = displaytext + "|" + url; + this.Icon = provider.Icon; + } + + public VisualStudio.OLE.Interop.IDataObject DataObject + { + get { return null; } + } + + public string Description + { + get; + private set; + } + + public string DisplayText + { + get; + private set; + } + + public IVsUIObject Icon + { + get; + private set; + } + + //action to be performed on selection of result from result list + public void InvokeAction() + { + Process.Start(this.url); + + } + + //retrieves persistence data for this result + public string PersistenceData + { + get; + private set; + } + + public IVsSearchProvider SearchProvider + { + get; + private set; + } + + public string Tooltip + { + get; + private set; + } + } +} diff --git a/EditorExtensions/QuickLaunch/VSGallery/VSSearchTask.cs b/EditorExtensions/QuickLaunch/VSGallery/VSSearchTask.cs new file mode 100644 index 000000000..e109a84ef --- /dev/null +++ b/EditorExtensions/QuickLaunch/VSGallery/VSSearchTask.cs @@ -0,0 +1,96 @@ +using System; +using System.Text; +using System.Web; +using System.Xml; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.MSDNSearch +{ + public class VSSearchTask : VsSearchTask + { + private VSSearchProvider provider; + + public VSSearchTask(VSSearchProvider provider, uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchProviderCallback pSearchCallback) + : base(dwCookie, pSearchQuery, pSearchCallback) + { + this.provider = provider; + } + + protected override void OnStartSearch() + { + string webQuery = this.GetWebQuery(this.SearchQuery); + + try + { + //parser code to parse through RSS results + var xmlDocument = new XmlDocument(); + xmlDocument.Load(webQuery); + var root = xmlDocument.DocumentElement; + + //each item/entry is a unique result + var entries = root.GetElementsByTagName("item"); + if (entries.Count == 0) + entries = root.GetElementsByTagName("entry"); + + for (int i = 0; i < Math.Min(10, entries.Count); i++) + { + var entry = entries[i] as XmlElement; + + if (entry != null) + { + string title = null; + string url = null; + + //title tag provides result title + var titleNodes = entry.GetElementsByTagName("title"); + if (titleNodes.Count > 0) + { + title = (titleNodes[0] as XmlElement).InnerText; + } + + //link / url / id tag provides the URL linking the result string to its page + var linkNodes = entry.GetElementsByTagName("link"); + if (linkNodes.Count == 0) + linkNodes = entry.GetElementsByTagName("url"); + if (linkNodes.Count == 0) + linkNodes = entry.GetElementsByTagName("id"); + + if (linkNodes.Count > 0) + { + url = (linkNodes[0] as XmlElement).InnerText; + } + + if (title != null && url != null) + { + var result = new VSSearchResult(title, url, this.provider); + + this.SearchCallback.ReportResult(this, result); + } + } + } + + this.SearchCallback.ReportComplete(this, (uint)entries.Count); + } + catch (Exception) + { + this.SearchCallback.ReportComplete(this, 0); + } + } + + protected new IVsSearchProviderCallback SearchCallback + { + get + { + return (IVsSearchProviderCallback)base.SearchCallback; + } + } + + public string GetWebQuery(IVsSearchQuery pSearchQuery) + { + return string.Format( + "http://visualstudiogallery.msdn.microsoft.com/site/feeds/searchRss?f%5B0%5D.Type=SearchText&f%5B0%5D.Value={0}&f%5B1%5D.Type=RootCategory&f%5B1%5D.Value=tools&f%5B1%5D.Text=Tools&sortBy=Relevance", + HttpUtility.UrlEncode(pSearchQuery.SearchString)); + } + } +} diff --git a/EditorExtensions/Resources.Designer.cs b/EditorExtensions/Resources.Designer.cs new file mode 100644 index 000000000..6a4b975b4 --- /dev/null +++ b/EditorExtensions/Resources.Designer.cs @@ -0,0 +1,378 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18210 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MadsKristensen.EditorExtensions { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MadsKristensen.EditorExtensions.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Browser compatibility: Add missing standard directive ({0}). + /// + internal static string BestPracticeAddMissingStandardDirective { + get { + return ResourceManager.GetString("BestPracticeAddMissingStandardDirective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Browser compatibility: Add missing standard property ({0}). + /// + internal static string BestPracticeAddMissingStandardProperty { + get { + return ResourceManager.GetString("BestPracticeAddMissingStandardProperty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Browser compatibility: Add missing vendor specific properties to '{0}' ({1}). + /// + internal static string BestPracticeAddMissingVendorSpecific { + get { + return ResourceManager.GetString("BestPracticeAddMissingVendorSpecific", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Browser compatibility: Add missing vendor specific directives to '{0}' ({1}). + /// + internal static string BestPracticeAddMissingVendorSpecificDirective { + get { + return ResourceManager.GetString("BestPracticeAddMissingVendorSpecificDirective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Best practice: The property '{0}' is already specified in the rule. Remove any unneeded duplicates. + /// + internal static string BestPracticeDuplicatePropertyInRule { + get { + return ResourceManager.GetString("BestPracticeDuplicatePropertyInRule", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Best practice: The property '{0}' with the same value is already specified in the rule and should be removed. + /// + internal static string BestPracticeDuplicatePropertyWithSameValueInRule { + get { + return ResourceManager.GetString("BestPracticeDuplicatePropertyWithSameValueInRule", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Best practice: The exact same selector is already defined on line {0}. Consider consolidating the duplicate style rules. + /// + internal static string BestPracticeDuplicateSelectors { + get { + return ResourceManager.GetString("BestPracticeDuplicateSelectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Best practice: The '{0}' property has no effect with 'display: inline' and should be removed. + /// + internal static string BestPracticeInlineIncompat { + get { + return ResourceManager.GetString("BestPracticeInlineIncompat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Best practice: "{0}" should be placed before any pseudo classes/elements. + /// + internal static string BestPracticePseudosAfterOtherSelectors { + get { + return ResourceManager.GetString("BestPracticePseudosAfterOtherSelectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Browser compatibility: Place the standard property below its vendor specific implementations. + /// + internal static string BestPracticeStandardPropertyOrder { + get { + return ResourceManager.GetString("BestPracticeStandardPropertyOrder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Best Practice: Don't specify the unit type ({0}) when the value is zero. (Disable this check in Tools -> Options). + /// + internal static string BestPracticeZeroUnit { + get { + return ResourceManager.GetString("BestPracticeZeroUnit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make visible to IE6 only. + /// + internal static string IE6OnlyPropertyHackName { + get { + return ResourceManager.GetString("IE6OnlyPropertyHackName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make visible to IE6 only. + /// + internal static string IE6OnlySelectorHackSmartTagActionName { + get { + return ResourceManager.GetString("IE6OnlySelectorHackSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make visible to IE7 and above. + /// + internal static string IE7AboveSelectorHackSmartTagActionName { + get { + return ResourceManager.GetString("IE7AboveSelectorHackSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make visible to IE7 and below. + /// + internal static string IE7BelowPropertyHackName { + get { + return ResourceManager.GetString("IE7BelowPropertyHackName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make visible to IE7 only. + /// + internal static string IE7OnlySelectorHackSmartTagActionName { + get { + return ResourceManager.GetString("IE7OnlySelectorHackSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Make visible to IE8 and above. + /// + internal static string IE8AboveSelectorHackSmartTagActionName { + get { + return ResourceManager.GetString("IE8AboveSelectorHackSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trim over qualified selectors. + /// + internal static string OverQualifiedSmartTagActionName { + get { + return ResourceManager.GetString("OverQualifiedSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance: Don't over qualify selectors. Remove all selectors before "{0}" ({1}). ID's must only occur once per web page and doesn't need further qualification.. + /// + internal static string PerformanceDontOverQualifySelectors { + get { + return ResourceManager.GetString("PerformanceDontOverQualifySelectors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance: Never use the universal selector. It has a big negative performance impact on browser rendering.. + /// + internal static string PerformanceDontUseStarSelector { + get { + return ResourceManager.GetString("PerformanceDontUseStarSelector", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance: The image is only {0} bytes and should be embedded as a base64 dataURI to reduce the number of HTTP requests.. + /// + internal static string PerformanceEmbedImageAsDataUri { + get { + return ResourceManager.GetString("PerformanceEmbedImageAsDataUri", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance: Use shorthand notation. The properties {0} can be replaced by {1}. + /// + internal static string PerformanceUseShorthand { + get { + return ResourceManager.GetString("PerformanceUseShorthand", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove IE selector hack. + /// + internal static string RemoveSelectorHackSmartTagActionName { + get { + return ResourceManager.GetString("RemoveSelectorHackSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Save to file. + /// + internal static string ReverseEmbedSmartTagActionName { + get { + return ResourceManager.GetString("ReverseEmbedSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Add missing standard property ({0}). + /// + internal static string StandardSmartTagActionName { + get { + return ResourceManager.GetString("StandardSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Re-embed dataURI from "{0}". + /// + internal static string UpdateEmbedSmartTagActionName { + get { + return ResourceManager.GetString("UpdateEmbedSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Embed as base64 DataURI. + /// + internal static string UrlSmartTagActionName { + get { + return ResourceManager.GetString("UrlSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation (WE): Values must be between 0 and 255. + /// + internal static string ValidationColorValuesInRange { + get { + return ResourceManager.GetString("ValidationColorValuesInRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation (WE): "{0}" has been deprecated and is safe to remove. Use the un-prefixed standard property instead.. + /// + internal static string ValidationDeprecatedVendorDeclaration { + get { + return ResourceManager.GetString("ValidationDeprecatedVendorDeclaration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation (WE): Pseudo elements ("{0}") must be specified after pseudo classes ("{1}").. + /// + internal static string ValidationPseudoOrder { + get { + return ResourceManager.GetString("ValidationPseudoOrder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation (WE): "{0}" is not a valid vendor specific property or it may have been deprecated.. + /// + internal static string ValidationVendorDeclarations { + get { + return ResourceManager.GetString("ValidationVendorDeclarations", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation (WE): "{0}" is not a valid vendor specific @-directive or it may have been deprecated.. + /// + internal static string ValidationVendorDirective { + get { + return ResourceManager.GetString("ValidationVendorDirective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation (WE): "{0}" is not a valid vendor specific pseudo class/element or it may have been deprecated.. + /// + internal static string ValidationVendorPseudo { + get { + return ResourceManager.GetString("ValidationVendorPseudo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move property below last vendor specific. + /// + internal static string VendorOrderSmartTagActionName { + get { + return ResourceManager.GetString("VendorOrderSmartTagActionName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Add missing vendor specifics. + /// + internal static string VendorSmartTagActionName { + get { + return ResourceManager.GetString("VendorSmartTagActionName", resourceCulture); + } + } + } +} diff --git a/EditorExtensions/Resources.resx b/EditorExtensions/Resources.resx new file mode 100644 index 000000000..1e7d2c105 --- /dev/null +++ b/EditorExtensions/Resources.resx @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Browser compatibility: Add missing standard directive ({0}) + + + Browser compatibility: Add missing standard property ({0}) + + + Browser compatibility: Add missing vendor specific properties to '{0}' ({1}) + + + Browser compatibility: Add missing vendor specific directives to '{0}' ({1}) + + + Best practice: The property '{0}' is already specified in the rule. Remove any unneeded duplicates + + + Best practice: The property '{0}' with the same value is already specified in the rule and should be removed + + + Best practice: The exact same selector is already defined on line {0}. Consider consolidating the duplicate style rules + + + Best practice: The '{0}' property has no effect with 'display: inline' and should be removed + + + Best practice: "{0}" should be placed before any pseudo classes/elements + + + Browser compatibility: Place the standard property below its vendor specific implementations + + + Best Practice: Don't specify the unit type ({0}) when the value is zero. (Disable this check in Tools -> Options) + + + Make visible to IE6 only + + + Make visible to IE6 only + + + Make visible to IE7 and above + + + Make visible to IE7 and below + + + Make visible to IE7 only + + + Make visible to IE8 and above + + + Trim over qualified selectors + + + Performance: Don't over qualify selectors. Remove all selectors before "{0}" ({1}). ID's must only occur once per web page and doesn't need further qualification. + + + Performance: Never use the universal selector. It has a big negative performance impact on browser rendering. + + + Performance: The image is only {0} bytes and should be embedded as a base64 dataURI to reduce the number of HTTP requests. + + + Performance: Use shorthand notation. The properties {0} can be replaced by {1} + + + Remove IE selector hack + + + Save to file + + + Add missing standard property ({0}) + + + Re-embed dataURI from "{0}" + + + Embed as base64 DataURI + + + Validation (WE): Values must be between 0 and 255 + + + Validation (WE): "{0}" has been deprecated and is safe to remove. Use the un-prefixed standard property instead. + + + Validation (WE): Pseudo elements ("{0}") must be specified after pseudo classes ("{1}"). + + + Validation (WE): "{0}" is not a valid vendor specific property or it may have been deprecated. + + + Validation (WE): "{0}" is not a valid vendor specific @-directive or it may have been deprecated. + + + Validation (WE): "{0}" is not a valid vendor specific pseudo class/element or it may have been deprecated. + + + Move property below last vendor specific + + + Add missing vendor specifics + + \ No newline at end of file diff --git a/EditorExtensions/Resources/Browsers/c.png b/EditorExtensions/Resources/Browsers/c.png new file mode 100644 index 000000000..ac8f0aad4 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/c.png differ diff --git a/EditorExtensions/Resources/Browsers/c_gray.png b/EditorExtensions/Resources/Browsers/c_gray.png new file mode 100644 index 000000000..34b9c64c7 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/c_gray.png differ diff --git a/EditorExtensions/Resources/Browsers/ff.png b/EditorExtensions/Resources/Browsers/ff.png new file mode 100644 index 000000000..5a5880834 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/ff.png differ diff --git a/EditorExtensions/Resources/Browsers/ff_gray.png b/EditorExtensions/Resources/Browsers/ff_gray.png new file mode 100644 index 000000000..14e20876e Binary files /dev/null and b/EditorExtensions/Resources/Browsers/ff_gray.png differ diff --git a/EditorExtensions/Resources/Browsers/ie.png b/EditorExtensions/Resources/Browsers/ie.png new file mode 100644 index 000000000..ffb226796 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/ie.png differ diff --git a/EditorExtensions/Resources/Browsers/ie_gray.png b/EditorExtensions/Resources/Browsers/ie_gray.png new file mode 100644 index 000000000..5770d8b55 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/ie_gray.png differ diff --git a/EditorExtensions/Resources/Browsers/o.png b/EditorExtensions/Resources/Browsers/o.png new file mode 100644 index 000000000..95e677693 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/o.png differ diff --git a/EditorExtensions/Resources/Browsers/o_gray.png b/EditorExtensions/Resources/Browsers/o_gray.png new file mode 100644 index 000000000..b96d96612 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/o_gray.png differ diff --git a/EditorExtensions/Resources/Browsers/s.png b/EditorExtensions/Resources/Browsers/s.png new file mode 100644 index 000000000..c700b35c3 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/s.png differ diff --git a/EditorExtensions/Resources/Browsers/s_gray.png b/EditorExtensions/Resources/Browsers/s_gray.png new file mode 100644 index 000000000..454710b68 Binary files /dev/null and b/EditorExtensions/Resources/Browsers/s_gray.png differ diff --git a/EditorExtensions/Resources/Images.png b/EditorExtensions/Resources/Images.png new file mode 100644 index 000000000..ba2b3e9f6 Binary files /dev/null and b/EditorExtensions/Resources/Images.png differ diff --git a/EditorExtensions/Resources/Package.ico b/EditorExtensions/Resources/Package.ico new file mode 100644 index 000000000..27420cc5d Binary files /dev/null and b/EditorExtensions/Resources/Package.ico differ diff --git a/EditorExtensions/Resources/Scripts/CoffeeScript-1.4.js b/EditorExtensions/Resources/Scripts/CoffeeScript-1.4.js new file mode 100644 index 000000000..9bc5d672c --- /dev/null +++ b/EditorExtensions/Resources/Scripts/CoffeeScript-1.4.js @@ -0,0 +1,8 @@ +/** + * CoffeeScript Compiler v1.3.3 + * http://coffeescript.org + * + * Copyright 2011, Jeremy Ashkenas + * Released under the MIT License + */ +(function(root){var CoffeeScript=function(){function require(a){return require[a]}require["./helpers"]=new function(){var a=this;(function(){var b,c;a.starts=function(a,b,c){return b===a.substr(c,b.length)},a.ends=function(a,b,c){var d;d=b.length;return b===a.substr(a.length-d-(c||0),d)},a.compact=function(a){var b,c,d,e;e=[];for(c=0,d=a.length;c=0)f+=1;else if(j=g[0],t.call(d,j)>=0)f-=1;a+=1}return a-1},a.prototype.removeLeadingNewlines=function(){var a,b,c,d,e;e=this.tokens;for(a=c=0,d=e.length;c=0)))return 1;d.splice(b,1);return 0})},a.prototype.closeOpenCalls=function(){var a,b;b=function(a,b){var c;return(c=a[0])===")"||c==="CALL_END"||a[0]==="OUTDENT"&&this.tag(b-1)===")"},a=function(a,b){return this.tokens[a[0]==="OUTDENT"?b-1:b][0]="CALL_END"};return this.scanTokens(function(c,d){c[0]==="CALL_START"&&this.detectEnd(d+1,b,a);return 1})},a.prototype.closeOpenIndexes=function(){var a,b;b=function(a,b){var c;return(c=a[0])==="]"||c==="INDEX_END"},a=function(a,b){return a[0]="INDEX_END"};return this.scanTokens(function(c,d){c[0]==="INDEX_START"&&this.detectEnd(d+1,b,a);return 1})},a.prototype.addImplicitBraces=function(){var a,b,c,f,g,i,j,k;f=[],g=null,k=null,c=!0,i=0,j=0,b=function(a,b){var d,e,f,g,i,m;i=this.tokens.slice(b+1,b+3+1||9e9),d=i[0],g=i[1],f=i[2];if("HERECOMMENT"===(d!=null?d[0]:void 0))return!1;e=a[0],t.call(l,e)>=0&&(c=!1);return(e==="TERMINATOR"||e==="OUTDENT"||t.call(h,e)>=0&&c&&b-j!==1)&&(!k&&this.tag(b-1)!==","||(g!=null?g[0]:void 0)!==":"&&((d!=null?d[0]:void 0)!=="@"||(f!=null?f[0]:void 0)!==":"))||e===","&&d&&(m=d[0])!=="IDENTIFIER"&&m!=="NUMBER"&&m!=="STRING"&&m!=="@"&&m!=="TERMINATOR"&&m!=="OUTDENT"},a=function(a,b){var c;c=this.generate("}","}",a[2]);return this.tokens.splice(b,0,c)};return this.scanTokens(function(h,i,m){var n,o,p,q,r,s,u,v;if(u=q=h[0],t.call(e,u)>=0){f.push([q==="INDENT"&&this.tag(i-1)==="{"?"{":q,i]);return 1}if(t.call(d,q)>=0){g=f.pop();return 1}if(q!==":"||(n=this.tag(i-2))!==":"&&((v=f[f.length-1])!=null?v[0]:void 0)==="{")return 1;c=!0,j=i+1,f.push(["{"]),o=n==="@"?i-2:i-1;while(this.tag(o-2)==="HERECOMMENT")o-=2;p=this.tag(o-1),k=!p||t.call(l,p)>=0,s=new String("{"),s.generated=!0,r=this.generate("{",s,h[2]),m.splice(o,0,r),this.detectEnd(i+2,b,a);return 2})},a.prototype.addImplicitParentheses=function(){var a,b,c,d,e;c=e=d=!1,b=function(a,b){var c,g,i,j;g=a[0];if(!e&&a.fromThen)return!0;if(g==="IF"||g==="ELSE"||g==="CATCH"||g==="->"||g==="=>"||g==="CLASS")e=!0;if(g==="IF"||g==="ELSE"||g==="SWITCH"||g==="TRY"||g==="=")d=!0;if((g==="."||g==="?."||g==="::")&&this.tag(b-1)==="OUTDENT")return!0;return!a.generated&&this.tag(b-1)!==","&&(t.call(h,g)>=0||g==="INDENT"&&!d)&&(g!=="INDENT"||(i=this.tag(b-2))!=="CLASS"&&i!=="EXTENDS"&&(j=this.tag(b-1),t.call(f,j)<0)&&(!(c=this.tokens[b+1])||!c.generated||c[0]!=="{"))},a=function(a,b){return this.tokens.splice(b,0,this.generate("CALL_END",")",a[2]))};return this.scanTokens(function(f,h,k){var m,n,o,p,q,r,s,u;q=f[0];if(q==="CLASS"||q==="IF"||q==="FOR"||q==="WHILE")c=!0;r=k.slice(h-1,h+1+1||9e9),p=r[0],n=r[1],o=r[2],m=!c&&q==="INDENT"&&o&&o.generated&&o[0]==="{"&&p&&(s=p[0],t.call(i,s)>=0),e=!1,d=!1,t.call(l,q)>=0&&(c=!1),p&&!p.spaced&&q==="?"&&(f.call=!0);if(f.fromThen)return 1;if(!(m||(p!=null?p.spaced:void 0)&&(p.call||(u=p[0],t.call(i,u)>=0))&&(t.call(g,q)>=0||!f.spaced&&!f.newLine&&t.call(j,q)>=0)))return 1;k.splice(h,0,this.generate("CALL_START","(",f[2])),this.detectEnd(h+1,b,a),p[0]==="?"&&(p[0]="FUNC_EXIST");return 2})},a.prototype.addImplicitIndentation=function(){var a,b,c,d,e;e=c=d=null,b=function(a,b){var c;return a[1]!==";"&&(c=a[0],t.call(m,c)>=0)&&(a[0]!=="ELSE"||e==="IF"||e==="THEN")},a=function(a,b){return this.tokens.splice(this.tag(b-1)===","?b-1:b,0,d)};return this.scanTokens(function(f,g,h){var i,j,k;i=f[0];if(i==="TERMINATOR"&&this.tag(g+1)==="THEN"){h.splice(g,1);return 0}if(i==="ELSE"&&this.tag(g-1)!=="OUTDENT"){h.splice.apply(h,[g,0].concat(u.call(this.indentation(f))));return 2}if(i==="CATCH"&&((j=this.tag(g+2))==="OUTDENT"||j==="TERMINATOR"||j==="FINALLY")){h.splice.apply(h,[g+2,0].concat(u.call(this.indentation(f))));return 4}if(t.call(n,i)>=0&&this.tag(g+1)!=="INDENT"&&(i!=="ELSE"||this.tag(g+1)!=="IF")){e=i,k=this.indentation(f,!0),c=k[0],d=k[1],e==="THEN"&&(c.fromThen=!0),h.splice(g+1,0,c),this.detectEnd(g+2,b,a),i==="THEN"&&h.splice(g,1);return 1}return 1})},a.prototype.tagPostfixConditionals=function(){var a,b,c;c=null,b=function(a,b){var c;return(c=a[0])==="TERMINATOR"||c==="INDENT"},a=function(a,b){if(a[0]!=="INDENT"||a.generated&&!a.fromThen)return c[0]="POST_"+c[0]};return this.scanTokens(function(d,e){if(d[0]!=="IF")return 1;c=d,this.detectEnd(e+1,b,a);return 1})},a.prototype.indentation=function(a,b){var c,d;b==null&&(b=!1),c=["INDENT",2,a[2]],d=["OUTDENT",2,a[2]],b&&(c.generated=d.generated=!0);return[c,d]},a.prototype.generate=function(a,b,c){var d;d=[a,b,c],d.generated=!0;return d},a.prototype.tag=function(a){var b;return(b=this.tokens[a])!=null?b[0]:void 0};return a}(),b=[["(",")"],["[","]"],["{","}"],["INDENT","OUTDENT"],["CALL_START","CALL_END"],["PARAM_START","PARAM_END"],["INDEX_START","INDEX_END"]],a.INVERSES=k={},e=[],d=[];for(q=0,r=b.length;q","=>","[","(","{","--","++"],j=["+","-"],f=["->","=>","{","[",","],h=["POST_IF","FOR","WHILE","UNTIL","WHEN","BY","LOOP","TERMINATOR"],n=["ELSE","->","=>","TRY","FINALLY","THEN"],m=["TERMINATOR","CATCH","FINALLY","ELSE","OUTDENT","LEADING_WHEN"],l=["TERMINATOR","INDENT","OUTDENT"]}).call(this)},require["./lexer"]=new function(){var a=this;(function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X=[].indexOf||function(a){for(var b=0,c=this.length;b=0||X.call(g,c)>=0)&&(j=c.toUpperCase(),j==="WHEN"&&(l=this.tag(),X.call(v,l)>=0)?j="LEADING_WHEN":j==="FOR"?this.seenFor=!0:j==="UNLESS"?j="IF":X.call(O,j)>=0?j="UNARY":X.call(H,j)>=0&&(j!=="INSTANCEOF"&&this.seenFor?(j="FOR"+j,this.seenFor=!1):(j="RELATION",this.value()==="!"&&(this.tokens.pop(),c="!"+c)))),X.call(t,c)>=0&&(b?(j="IDENTIFIER",c=new String(c),c.reserved=!0):X.call(I,c)>=0&&this.error('reserved word "'+c+'"')),b||(X.call(e,c)>=0&&(c=f[c]),j=function(){switch(c){case"!":return"UNARY";case"==":case"!=":return"COMPARE";case"&&":case"||":return"LOGIC";case"true":case"false":return"BOOL";case"break":case"continue":return"STATEMENT";default:return j}}()),this.token(j,c),a&&this.token(":",":");return d.length},a.prototype.numberToken=function(){var a,b,c,d,e;if(!(c=E.exec(this.chunk)))return 0;d=c[0],/^0[BOX]/.test(d)?this.error("radix prefix '"+d+"' must be lowercase"):/E/.test(d)&&!/^0x/.test(d)?this.error("exponential notation '"+d+"' must be indicated with a lowercase 'e'"):/^0\d*[89]/.test(d)?this.error("decimal literal '"+d+"' must not be prefixed with '0'"):/^0\d+/.test(d)&&this.error("octal literal '"+d+"' must be prefixed with '0o'"),b=d.length;if(e=/^0o([0-7]+)/.exec(d))d="0x"+parseInt(e[1],8).toString(16);if(a=/^0b([01]+)/.exec(d))d="0x"+parseInt(a[1],2).toString(16);this.token("NUMBER",d);return b},a.prototype.stringToken=function(){var a,b,c;switch(this.chunk.charAt(0)){case"'":if(!(a=L.exec(this.chunk)))return 0;this.token("STRING",(c=a[0]).replace(A,"\\\n"));break;case'"':if(!(c=this.balancedString(this.chunk,'"')))return 0;0=0))return 0;if(!(c=G.exec(this.chunk)))return 0;g=c,c=g[0],e=g[1],a=g[2],e.slice(0,2)==="/*"&&this.error("regular expressions cannot begin with `*`"),e==="//"&&(e="/(?:)/"),this.token("REGEX",""+e+a);return c.length},a.prototype.heregexToken=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n;d=a[0],b=a[1],c=a[2];if(0>b.indexOf("#{")){e=b.replace(o,"").replace(/\//g,"\\/"),e.match(/^\*/)&&this.error("regular expressions cannot begin with `*`"),this.token("REGEX","/"+(e||"(?:)")+"/"+c);return d.length}this.token("IDENTIFIER","RegExp"),this.tokens.push(["CALL_START","("]),g=[],k=this.interpolateString(b,{regex:!0});for(i=0,j=k.length;ithis.indent){if(d){this.indebt=f-this.indent,this.suppressNewlines();return b.length}a=f-this.indent+this.outdebt,this.token("INDENT",a),this.indents.push(a),this.ends.push("OUTDENT"),this.outdebt=this.indebt=0}else this.indebt=0,this.outdentToken(this.indent-f,d);this.indent=f;return b.length},a.prototype.outdentToken=function(a,b){var c,d;while(a>0)d=this.indents.length-1,this.indents[d]===void 0?a=0:this.indents[d]===this.outdebt?(a-=this.outdebt,this.outdebt=0):this.indents[d]=0)&&this.error('reserved word "'+this.value()+"\" can't be assigned");if((h=b[1])==="||"||h==="&&"){b[0]="COMPOUND_ASSIGN",b[1]+="=";return f.length}}if(f===";")this.seenFor=!1,e="TERMINATOR";else if(X.call(z,f)>=0)e="MATH";else if(X.call(i,f)>=0)e="COMPARE";else if(X.call(j,f)>=0)e="COMPOUND_ASSIGN";else if(X.call(O,f)>=0)e="UNARY";else if(X.call(K,f)>=0)e="SHIFT";else if(X.call(x,f)>=0||f==="?"&&(b!=null?b.spaced:void 0))e="LOGIC";else if(b&&!b.spaced)if(f==="("&&(k=b[0],X.call(c,k)>=0))b[0]==="?"&&(b[0]="FUNC_EXIST"),e="CALL_START";else if(f==="["&&(l=b[0],X.call(q,l)>=0)){e="INDEX_START";switch(b[0]){case"?":b[0]="INDEX_SOAK"}}switch(f){case"(":case"{":case"[":this.ends.push(r[f]);break;case")":case"}":case"]":this.pair(f)}this.token(e,f);return f.length},a.prototype.sanitizeHeredoc=function(a,b){var c,d,e,f,g;e=b.indent,d=b.herecomment;if(d){l.test(a)&&this.error('block comment cannot contain "*/", starting');if(a.indexOf("\n")<=0)return a}else while(f=m.exec(a)){c=f[1];if(e===null||0<(g=c.length)&&gj;d=1<=j?++i:--i){if(c){--c;continue}switch(e=a.charAt(d)){case"\\":++c;continue;case b:h.pop();if(!h.length)return a.slice(0,d+1||9e9);b=h[h.length-1];continue}b!=="}"||e!=='"'&&e!=="'"?b==="}"&&e==="/"&&(f=n.exec(a.slice(d))||G.exec(a.slice(d)))?c+=f[0].length-1:b==="}"&&e==="{"?h.push(b="}"):b==='"'&&g==="#"&&e==="{"&&h.push(b="}"):h.push(b=e),g=e}return this.error("missing "+h.pop()+", starting")},a.prototype.interpolateString=function(b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;c==null&&(c={}),e=c.heredoc,m=c.regex,o=[],l=0,f=-1;while(j=b.charAt(f+=1)){if(j==="\\"){f+=1;continue}if(j!=="#"||b.charAt(f+1)!=="{"||!(d=this.balancedString(b.slice(f+1),"}")))continue;l1&&(k.unshift(["(","(",this.line]),k.push([")",")",this.line])),o.push(["TOKENS",k])}f+=d.length,l=f+1}f>l&&l1)&&this.token("(","(");for(f=q=0,r=o.length;q|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/,P=/^[^\n\S]+/,h=/^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/,d=/^[-=]>/,B=/^(?:\n[^\n\S]*)+/,L=/^'[^\\']*(?:\\.[^\\']*)*'/,s=/^`[^\\`]*(?:\\.[^\\`]*)*`/,G=/^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/,n=/^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/,o=/\s+(?:#.*)?/g,A=/\n/g,m=/\n+([^\n\S]*)/g,l=/\*\//,w=/^\s*(?:,|\??\.(?![.\d])|::)/,N=/\s+$/,j=["-=","+=","/=","*=","%=","||=","&&=","?=","<<=",">>=",">>>=","&=","^=","|="],O=["!","~","NEW","TYPEOF","DELETE","DO"],x=["&&","||","&","|","^"],K=["<<",">>",">>>"],i=["==","!=","<",">","<=",">="],z=["*","/","%"],H=["IN","OF","INSTANCEOF"],b=["TRUE","FALSE"],C=["NUMBER","REGEX","BOOL","NULL","UNDEFINED","++","--","]"],D=C.concat(")","}","THIS","IDENTIFIER","STRING"),c=["IDENTIFIER","STRING","REGEX",")","]","}","?","::","@","THIS","SUPER"],q=c.concat("NUMBER","BOOL","NULL","UNDEFINED"),v=["INDENT","OUTDENT","TERMINATOR"]}).call(this)},require["./parser"]=new function(){var a=this,b=function(){var a={trace:function(){},yy:{},symbols_:{error:2,Root:3,Body:4,Block:5,TERMINATOR:6,Line:7,Expression:8,Statement:9,Return:10,Comment:11,STATEMENT:12,Value:13,Invocation:14,Code:15,Operation:16,Assign:17,If:18,Try:19,While:20,For:21,Switch:22,Class:23,Throw:24,INDENT:25,OUTDENT:26,Identifier:27,IDENTIFIER:28,AlphaNumeric:29,NUMBER:30,STRING:31,Literal:32,JS:33,REGEX:34,DEBUGGER:35,UNDEFINED:36,NULL:37,BOOL:38,Assignable:39,"=":40,AssignObj:41,ObjAssignable:42,":":43,ThisProperty:44,RETURN:45,HERECOMMENT:46,PARAM_START:47,ParamList:48,PARAM_END:49,FuncGlyph:50,"->":51,"=>":52,OptComma:53,",":54,Param:55,ParamVar:56,"...":57,Array:58,Object:59,Splat:60,SimpleAssignable:61,Accessor:62,Parenthetical:63,Range:64,This:65,".":66,"?.":67,"::":68,Index:69,INDEX_START:70,IndexValue:71,INDEX_END:72,INDEX_SOAK:73,Slice:74,"{":75,AssignList:76,"}":77,CLASS:78,EXTENDS:79,OptFuncExist:80,Arguments:81,SUPER:82,FUNC_EXIST:83,CALL_START:84,CALL_END:85,ArgList:86,THIS:87,"@":88,"[":89,"]":90,RangeDots:91,"..":92,Arg:93,SimpleArgs:94,TRY:95,Catch:96,FINALLY:97,CATCH:98,THROW:99,"(":100,")":101,WhileSource:102,WHILE:103,WHEN:104,UNTIL:105,Loop:106,LOOP:107,ForBody:108,FOR:109,ForStart:110,ForSource:111,ForVariables:112,OWN:113,ForValue:114,FORIN:115,FOROF:116,BY:117,SWITCH:118,Whens:119,ELSE:120,When:121,LEADING_WHEN:122,IfBlock:123,IF:124,POST_IF:125,UNARY:126,"-":127,"+":128,"--":129,"++":130,"?":131,MATH:132,SHIFT:133,COMPARE:134,LOGIC:135,RELATION:136,COMPOUND_ASSIGN:137,$accept:0,$end:1},terminals_:{2:"error",6:"TERMINATOR",12:"STATEMENT",25:"INDENT",26:"OUTDENT",28:"IDENTIFIER",30:"NUMBER",31:"STRING",33:"JS",34:"REGEX",35:"DEBUGGER",36:"UNDEFINED",37:"NULL",38:"BOOL",40:"=",43:":",45:"RETURN",46:"HERECOMMENT",47:"PARAM_START",49:"PARAM_END",51:"->",52:"=>",54:",",57:"...",66:".",67:"?.",68:"::",70:"INDEX_START",72:"INDEX_END",73:"INDEX_SOAK",75:"{",77:"}",78:"CLASS",79:"EXTENDS",82:"SUPER",83:"FUNC_EXIST",84:"CALL_START",85:"CALL_END",87:"THIS",88:"@",89:"[",90:"]",92:"..",95:"TRY",97:"FINALLY",98:"CATCH",99:"THROW",100:"(",101:")",103:"WHILE",104:"WHEN",105:"UNTIL",107:"LOOP",109:"FOR",113:"OWN",115:"FORIN",116:"FOROF",117:"BY",118:"SWITCH",120:"ELSE",122:"LEADING_WHEN",124:"IF",125:"POST_IF",126:"UNARY",127:"-",128:"+",129:"--",130:"++",131:"?",132:"MATH",133:"SHIFT",134:"COMPARE",135:"LOGIC",136:"RELATION",137:"COMPOUND_ASSIGN"},productions_:[0,[3,0],[3,1],[3,2],[4,1],[4,3],[4,2],[7,1],[7,1],[9,1],[9,1],[9,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[5,2],[5,3],[27,1],[29,1],[29,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[17,3],[17,4],[17,5],[41,1],[41,3],[41,5],[41,1],[42,1],[42,1],[42,1],[10,2],[10,1],[11,1],[15,5],[15,2],[50,1],[50,1],[53,0],[53,1],[48,0],[48,1],[48,3],[48,4],[48,6],[55,1],[55,2],[55,3],[56,1],[56,1],[56,1],[56,1],[60,2],[61,1],[61,2],[61,2],[61,1],[39,1],[39,1],[39,1],[13,1],[13,1],[13,1],[13,1],[13,1],[62,2],[62,2],[62,2],[62,1],[62,1],[69,3],[69,2],[71,1],[71,1],[59,4],[76,0],[76,1],[76,3],[76,4],[76,6],[23,1],[23,2],[23,3],[23,4],[23,2],[23,3],[23,4],[23,5],[14,3],[14,3],[14,1],[14,2],[80,0],[80,1],[81,2],[81,4],[65,1],[65,1],[44,2],[58,2],[58,4],[91,1],[91,1],[64,5],[74,3],[74,2],[74,2],[74,1],[86,1],[86,3],[86,4],[86,4],[86,6],[93,1],[93,1],[94,1],[94,3],[19,2],[19,3],[19,4],[19,5],[96,3],[24,2],[63,3],[63,5],[102,2],[102,4],[102,2],[102,4],[20,2],[20,2],[20,2],[20,1],[106,2],[106,2],[21,2],[21,2],[21,2],[108,2],[108,2],[110,2],[110,3],[114,1],[114,1],[114,1],[114,1],[112,1],[112,3],[111,2],[111,2],[111,4],[111,4],[111,4],[111,6],[111,6],[22,5],[22,7],[22,4],[22,6],[119,1],[119,2],[121,3],[121,4],[123,3],[123,5],[18,1],[18,3],[18,3],[18,3],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,5],[16,3]],performAction:function(a,b,c,d,e,f,g){var h=f.length-1;switch(e){case 1:return this.$=new d.Block;case 2:return this.$=f[h];case 3:return this.$=f[h-1];case 4:this.$=d.Block.wrap([f[h]]);break;case 5:this.$=f[h-2].push(f[h]);break;case 6:this.$=f[h-1];break;case 7:this.$=f[h];break;case 8:this.$=f[h];break;case 9:this.$=f[h];break;case 10:this.$=f[h];break;case 11:this.$=new d.Literal(f[h]);break;case 12:this.$=f[h];break;case 13:this.$=f[h];break;case 14:this.$=f[h];break;case 15:this.$=f[h];break;case 16:this.$=f[h];break;case 17:this.$=f[h];break;case 18:this.$=f[h];break;case 19:this.$=f[h];break;case 20:this.$=f[h];break;case 21:this.$=f[h];break;case 22:this.$=f[h];break;case 23:this.$=f[h];break;case 24:this.$=new d.Block;break;case 25:this.$=f[h-1];break;case 26:this.$=new d.Literal(f[h]);break;case 27:this.$=new d.Literal(f[h]);break;case 28:this.$=new d.Literal(f[h]);break;case 29:this.$=f[h];break;case 30:this.$=new d.Literal(f[h]);break;case 31:this.$=new d.Literal(f[h]);break;case 32:this.$=new d.Literal(f[h]);break;case 33:this.$=new d.Undefined;break;case 34:this.$=new d.Null;break;case 35:this.$=new d.Bool(f[h]);break;case 36:this.$=new d.Assign(f[h-2],f[h]);break;case 37:this.$=new d.Assign(f[h-3],f[h]);break;case 38:this.$=new d.Assign(f[h-4],f[h-1]);break;case 39:this.$=new d.Value(f[h]);break;case 40:this.$=new d.Assign(new d.Value(f[h-2]),f[h],"object");break;case 41:this.$=new d.Assign(new d.Value(f[h-4]),f[h-1],"object");break;case 42:this.$=f[h];break;case 43:this.$=f[h];break;case 44:this.$=f[h];break;case 45:this.$=f[h];break;case 46:this.$=new d.Return(f[h]);break;case 47:this.$=new d.Return;break;case 48:this.$=new d.Comment(f[h]);break;case 49:this.$=new d.Code(f[h-3],f[h],f[h-1]);break;case 50:this.$=new d.Code([],f[h],f[h-1]);break;case 51:this.$="func";break;case 52:this.$="boundfunc";break;case 53:this.$=f[h];break;case 54:this.$=f[h];break;case 55:this.$=[];break;case 56:this.$=[f[h]];break;case 57:this.$=f[h-2].concat(f[h]);break;case 58:this.$=f[h-3].concat(f[h]);break;case 59:this.$=f[h-5].concat(f[h-2]);break;case 60:this.$=new d.Param(f[h]);break;case 61:this.$=new d.Param(f[h-1],null,!0);break;case 62:this.$=new d.Param(f[h-2],f[h]);break;case 63:this.$=f[h];break;case 64:this.$=f[h];break;case 65:this.$=f[h];break;case 66:this.$=f[h];break;case 67:this.$=new d.Splat(f[h-1]);break;case 68:this.$=new d.Value(f[h]);break;case 69:this.$=f[h-1].add(f[h]);break;case 70:this.$=new d.Value(f[h-1],[].concat(f[h]));break;case 71:this.$=f[h];break;case 72:this.$=f[h];break;case 73:this.$=new d.Value(f[h]);break;case 74:this.$=new d.Value(f[h]);break;case 75:this.$=f[h];break;case 76:this.$=new d.Value(f[h]);break;case 77:this.$=new d.Value(f[h]);break;case 78:this.$=new d.Value(f[h]);break;case 79:this.$=f[h];break;case 80:this.$=new d.Access(f[h]);break;case 81:this.$=new d.Access(f[h],"soak");break;case 82:this.$=[new d.Access(new d.Literal("prototype")),new d.Access(f[h])];break;case 83:this.$=new d.Access(new d.Literal("prototype"));break;case 84:this.$=f[h];break;case 85:this.$=f[h-1];break;case 86:this.$=d.extend(f[h],{soak:!0});break;case 87:this.$=new d.Index(f[h]);break;case 88:this.$=new d.Slice(f[h]);break;case 89:this.$=new d.Obj(f[h-2],f[h-3].generated);break;case 90:this.$=[];break;case 91:this.$=[f[h]];break;case 92:this.$=f[h-2].concat(f[h]);break;case 93:this.$=f[h-3].concat(f[h]);break;case 94:this.$=f[h-5].concat(f[h-2]);break;case 95:this.$=new d.Class;break;case 96:this.$=new d.Class(null,null,f[h]);break;case 97:this.$=new d.Class(null,f[h]);break;case 98:this.$=new d.Class(null,f[h-1],f[h]);break;case 99:this.$=new d.Class(f[h]);break;case 100:this.$=new d.Class(f[h-1],null,f[h]);break;case 101:this.$=new d.Class(f[h-2],f[h]);break;case 102:this.$=new d.Class(f[h-3],f[h-1],f[h]);break;case 103:this.$=new d.Call(f[h-2],f[h],f[h-1]);break;case 104:this.$=new d.Call(f[h-2],f[h],f[h-1]);break;case 105:this.$=new d.Call("super",[new d.Splat(new d.Literal("arguments"))]);break;case 106:this.$=new d.Call("super",f[h]);break;case 107:this.$=!1;break;case 108:this.$=!0;break;case 109:this.$=[];break;case 110:this.$=f[h-2];break;case 111:this.$=new d.Value(new d.Literal("this"));break;case 112:this.$=new d.Value(new d.Literal("this"));break;case 113:this.$=new d.Value(new d.Literal("this"),[new d.Access(f[h])],"this");break;case 114:this.$=new d.Arr([]);break;case 115:this.$=new d.Arr(f[h-2]);break;case 116:this.$="inclusive";break;case 117:this.$="exclusive";break;case 118:this.$=new d.Range(f[h-3],f[h-1],f[h-2]);break;case 119:this.$=new d.Range(f[h-2],f[h],f[h-1]);break;case 120:this.$=new d.Range(f[h-1],null,f[h]);break;case 121:this.$=new d.Range(null,f[h],f[h-1]);break;case 122:this.$=new d.Range(null,null,f[h]);break;case 123:this.$=[f[h]];break;case 124:this.$=f[h-2].concat(f[h]);break;case 125:this.$=f[h-3].concat(f[h]);break;case 126:this.$=f[h-2];break;case 127:this.$=f[h-5].concat(f[h-2]);break;case 128:this.$=f[h];break;case 129:this.$=f[h];break;case 130:this.$=f[h];break;case 131:this.$=[].concat(f[h-2],f[h]);break;case 132:this.$=new d.Try(f[h]);break;case 133:this.$=new d.Try(f[h-1],f[h][0],f[h][1]);break;case 134:this.$=new d.Try(f[h-2],null,null,f[h]);break;case 135:this.$=new d.Try(f[h-3],f[h-2][0],f[h-2][1],f[h]);break;case 136:this.$=[f[h-1],f[h]];break;case 137:this.$=new d.Throw(f[h]);break;case 138:this.$=new d.Parens(f[h-1]);break;case 139:this.$=new d.Parens(f[h-2]);break;case 140:this.$=new d.While(f[h]);break;case 141:this.$=new d.While(f[h-2],{guard:f[h]});break;case 142:this.$=new d.While(f[h],{invert:!0});break;case 143:this.$=new d.While(f[h-2],{invert:!0,guard:f[h]});break;case 144:this.$=f[h-1].addBody(f[h]);break;case 145:this.$=f[h].addBody(d.Block.wrap([f[h-1]]));break;case 146:this.$=f[h].addBody(d.Block.wrap([f[h-1]]));break;case 147:this.$=f[h];break;case 148:this.$=(new d.While(new d.Literal("true"))).addBody(f[h]);break;case 149:this.$=(new d.While(new d.Literal("true"))).addBody(d.Block.wrap([f[h]]));break;case 150:this.$=new d.For(f[h-1],f[h]);break;case 151:this.$=new d.For(f[h-1],f[h]);break;case 152:this.$=new d.For(f[h],f[h-1]);break;case 153:this.$={source:new d.Value(f[h])};break;case 154:this.$=function(){f[h].own=f[h-1].own,f[h].name=f[h-1][0],f[h].index=f[h-1][1];return f[h]}();break;case 155:this.$=f[h];break;case 156:this.$=function(){f[h].own=!0;return f[h]}();break;case 157:this.$=f[h];break;case 158:this.$=f[h];break;case 159:this.$=new d.Value(f[h]);break;case 160:this.$=new d.Value(f[h]);break;case 161:this.$=[f[h]];break;case 162:this.$=[f[h-2],f[h]];break;case 163:this.$={source:f[h]};break;case 164:this.$={source:f[h],object:!0};break;case 165:this.$={source:f[h-2],guard:f[h]};break;case 166:this.$={source:f[h-2],guard:f[h],object:!0};break;case 167:this.$={source:f[h-2],step:f[h]};break;case 168:this.$={source:f[h-4],guard:f[h-2],step:f[h]};break;case 169:this.$={source:f[h-4],step:f[h-2],guard:f[h]};break;case 170:this.$=new d.Switch(f[h-3],f[h-1]);break;case 171:this.$=new d.Switch(f[h-5],f[h-3],f[h-1]);break;case 172:this.$=new d.Switch(null,f[h-1]);break;case 173:this.$=new d.Switch(null,f[h-3],f[h-1]);break;case 174:this.$=f[h];break;case 175:this.$=f[h-1].concat(f[h]);break;case 176:this.$=[[f[h-1],f[h]]];break;case 177:this.$=[[f[h-2],f[h-1]]];break;case 178:this.$=new d.If(f[h-1],f[h],{type:f[h-2]});break;case 179:this.$=f[h-4].addElse(new d.If(f[h-1],f[h],{type:f[h-2]}));break;case 180:this.$=f[h];break;case 181:this.$=f[h-2].addElse(f[h]);break;case 182:this.$=new d.If(f[h],d.Block.wrap([f[h-2]]),{type:f[h-1],statement:!0});break;case 183:this.$=new d.If(f[h],d.Block.wrap([f[h-2]]),{type:f[h-1],statement:!0});break;case 184:this.$=new d.Op(f[h-1],f[h]);break;case 185:this.$=new d.Op("-",f[h]);break;case 186:this.$=new d.Op("+",f[h]);break;case 187:this.$=new d.Op("--",f[h]);break;case 188:this.$=new d.Op("++",f[h]);break;case 189:this.$=new d.Op("--",f[h-1],null,!0);break;case 190:this.$=new d.Op("++",f[h-1],null,!0);break;case 191:this.$=new d.Existence(f[h-1]);break;case 192:this.$=new d.Op("+",f[h-2],f[h]);break;case 193:this.$=new d.Op("-",f[h-2],f[h]);break;case 194:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 195:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 196:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 197:this.$=new d.Op(f[h-1],f[h-2],f[h]);break;case 198:this.$=function(){return f[h-1].charAt(0)==="!"?(new d.Op(f[h-1].slice(1),f[h-2],f[h])).invert():new d.Op(f[h-1],f[h-2],f[h])}();break;case 199:this.$=new d.Assign(f[h-2],f[h],f[h-1]);break;case 200:this.$=new d.Assign(f[h-4],f[h-1],f[h-3]);break;case 201:this.$=new d.Extends(f[h-2],f[h])}},table:[{1:[2,1],3:1,4:2,5:3,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[3]},{1:[2,2],6:[1,74]},{6:[1,75]},{1:[2,4],6:[2,4],26:[2,4],101:[2,4]},{4:77,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[1,76],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,7],6:[2,7],26:[2,7],101:[2,7],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,8],6:[2,8],26:[2,8],101:[2,8],102:90,103:[1,65],105:[1,66],108:91,109:[1,68],110:69,125:[1,89]},{1:[2,12],6:[2,12],25:[2,12],26:[2,12],49:[2,12],54:[2,12],57:[2,12],62:93,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],72:[2,12],73:[1,100],77:[2,12],80:92,83:[1,94],84:[2,107],85:[2,12],90:[2,12],92:[2,12],101:[2,12],103:[2,12],104:[2,12],105:[2,12],109:[2,12],117:[2,12],125:[2,12],127:[2,12],128:[2,12],131:[2,12],132:[2,12],133:[2,12],134:[2,12],135:[2,12],136:[2,12]},{1:[2,13],6:[2,13],25:[2,13],26:[2,13],49:[2,13],54:[2,13],57:[2,13],62:102,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],72:[2,13],73:[1,100],77:[2,13],80:101,83:[1,94],84:[2,107],85:[2,13],90:[2,13],92:[2,13],101:[2,13],103:[2,13],104:[2,13],105:[2,13],109:[2,13],117:[2,13],125:[2,13],127:[2,13],128:[2,13],131:[2,13],132:[2,13],133:[2,13],134:[2,13],135:[2,13],136:[2,13]},{1:[2,14],6:[2,14],25:[2,14],26:[2,14],49:[2,14],54:[2,14],57:[2,14],72:[2,14],77:[2,14],85:[2,14],90:[2,14],92:[2,14],101:[2,14],103:[2,14],104:[2,14],105:[2,14],109:[2,14],117:[2,14],125:[2,14],127:[2,14],128:[2,14],131:[2,14],132:[2,14],133:[2,14],134:[2,14],135:[2,14],136:[2,14]},{1:[2,15],6:[2,15],25:[2,15],26:[2,15],49:[2,15],54:[2,15],57:[2,15],72:[2,15],77:[2,15],85:[2,15],90:[2,15],92:[2,15],101:[2,15],103:[2,15],104:[2,15],105:[2,15],109:[2,15],117:[2,15],125:[2,15],127:[2,15],128:[2,15],131:[2,15],132:[2,15],133:[2,15],134:[2,15],135:[2,15],136:[2,15]},{1:[2,16],6:[2,16],25:[2,16],26:[2,16],49:[2,16],54:[2,16],57:[2,16],72:[2,16],77:[2,16],85:[2,16],90:[2,16],92:[2,16],101:[2,16],103:[2,16],104:[2,16],105:[2,16],109:[2,16],117:[2,16],125:[2,16],127:[2,16],128:[2,16],131:[2,16],132:[2,16],133:[2,16],134:[2,16],135:[2,16],136:[2,16]},{1:[2,17],6:[2,17],25:[2,17],26:[2,17],49:[2,17],54:[2,17],57:[2,17],72:[2,17],77:[2,17],85:[2,17],90:[2,17],92:[2,17],101:[2,17],103:[2,17],104:[2,17],105:[2,17],109:[2,17],117:[2,17],125:[2,17],127:[2,17],128:[2,17],131:[2,17],132:[2,17],133:[2,17],134:[2,17],135:[2,17],136:[2,17]},{1:[2,18],6:[2,18],25:[2,18],26:[2,18],49:[2,18],54:[2,18],57:[2,18],72:[2,18],77:[2,18],85:[2,18],90:[2,18],92:[2,18],101:[2,18],103:[2,18],104:[2,18],105:[2,18],109:[2,18],117:[2,18],125:[2,18],127:[2,18],128:[2,18],131:[2,18],132:[2,18],133:[2,18],134:[2,18],135:[2,18],136:[2,18]},{1:[2,19],6:[2,19],25:[2,19],26:[2,19],49:[2,19],54:[2,19],57:[2,19],72:[2,19],77:[2,19],85:[2,19],90:[2,19],92:[2,19],101:[2,19],103:[2,19],104:[2,19],105:[2,19],109:[2,19],117:[2,19],125:[2,19],127:[2,19],128:[2,19],131:[2,19],132:[2,19],133:[2,19],134:[2,19],135:[2,19],136:[2,19]},{1:[2,20],6:[2,20],25:[2,20],26:[2,20],49:[2,20],54:[2,20],57:[2,20],72:[2,20],77:[2,20],85:[2,20],90:[2,20],92:[2,20],101:[2,20],103:[2,20],104:[2,20],105:[2,20],109:[2,20],117:[2,20],125:[2,20],127:[2,20],128:[2,20],131:[2,20],132:[2,20],133:[2,20],134:[2,20],135:[2,20],136:[2,20]},{1:[2,21],6:[2,21],25:[2,21],26:[2,21],49:[2,21],54:[2,21],57:[2,21],72:[2,21],77:[2,21],85:[2,21],90:[2,21],92:[2,21],101:[2,21],103:[2,21],104:[2,21],105:[2,21],109:[2,21],117:[2,21],125:[2,21],127:[2,21],128:[2,21],131:[2,21],132:[2,21],133:[2,21],134:[2,21],135:[2,21],136:[2,21]},{1:[2,22],6:[2,22],25:[2,22],26:[2,22],49:[2,22],54:[2,22],57:[2,22],72:[2,22],77:[2,22],85:[2,22],90:[2,22],92:[2,22],101:[2,22],103:[2,22],104:[2,22],105:[2,22],109:[2,22],117:[2,22],125:[2,22],127:[2,22],128:[2,22],131:[2,22],132:[2,22],133:[2,22],134:[2,22],135:[2,22],136:[2,22]},{1:[2,23],6:[2,23],25:[2,23],26:[2,23],49:[2,23],54:[2,23],57:[2,23],72:[2,23],77:[2,23],85:[2,23],90:[2,23],92:[2,23],101:[2,23],103:[2,23],104:[2,23],105:[2,23],109:[2,23],117:[2,23],125:[2,23],127:[2,23],128:[2,23],131:[2,23],132:[2,23],133:[2,23],134:[2,23],135:[2,23],136:[2,23]},{1:[2,9],6:[2,9],26:[2,9],101:[2,9],103:[2,9],105:[2,9],109:[2,9],125:[2,9]},{1:[2,10],6:[2,10],26:[2,10],101:[2,10],103:[2,10],105:[2,10],109:[2,10],125:[2,10]},{1:[2,11],6:[2,11],26:[2,11],101:[2,11],103:[2,11],105:[2,11],109:[2,11],125:[2,11]},{1:[2,75],6:[2,75],25:[2,75],26:[2,75],40:[1,103],49:[2,75],54:[2,75],57:[2,75],66:[2,75],67:[2,75],68:[2,75],70:[2,75],72:[2,75],73:[2,75],77:[2,75],83:[2,75],84:[2,75],85:[2,75],90:[2,75],92:[2,75],101:[2,75],103:[2,75],104:[2,75],105:[2,75],109:[2,75],117:[2,75],125:[2,75],127:[2,75],128:[2,75],131:[2,75],132:[2,75],133:[2,75],134:[2,75],135:[2,75],136:[2,75]},{1:[2,76],6:[2,76],25:[2,76],26:[2,76],49:[2,76],54:[2,76],57:[2,76],66:[2,76],67:[2,76],68:[2,76],70:[2,76],72:[2,76],73:[2,76],77:[2,76],83:[2,76],84:[2,76],85:[2,76],90:[2,76],92:[2,76],101:[2,76],103:[2,76],104:[2,76],105:[2,76],109:[2,76],117:[2,76],125:[2,76],127:[2,76],128:[2,76],131:[2,76],132:[2,76],133:[2,76],134:[2,76],135:[2,76],136:[2,76]},{1:[2,77],6:[2,77],25:[2,77],26:[2,77],49:[2,77],54:[2,77],57:[2,77],66:[2,77],67:[2,77],68:[2,77],70:[2,77],72:[2,77],73:[2,77],77:[2,77],83:[2,77],84:[2,77],85:[2,77],90:[2,77],92:[2,77],101:[2,77],103:[2,77],104:[2,77],105:[2,77],109:[2,77],117:[2,77],125:[2,77],127:[2,77],128:[2,77],131:[2,77],132:[2,77],133:[2,77],134:[2,77],135:[2,77],136:[2,77]},{1:[2,78],6:[2,78],25:[2,78],26:[2,78],49:[2,78],54:[2,78],57:[2,78],66:[2,78],67:[2,78],68:[2,78],70:[2,78],72:[2,78],73:[2,78],77:[2,78],83:[2,78],84:[2,78],85:[2,78],90:[2,78],92:[2,78],101:[2,78],103:[2,78],104:[2,78],105:[2,78],109:[2,78],117:[2,78],125:[2,78],127:[2,78],128:[2,78],131:[2,78],132:[2,78],133:[2,78],134:[2,78],135:[2,78],136:[2,78]},{1:[2,79],6:[2,79],25:[2,79],26:[2,79],49:[2,79],54:[2,79],57:[2,79],66:[2,79],67:[2,79],68:[2,79],70:[2,79],72:[2,79],73:[2,79],77:[2,79],83:[2,79],84:[2,79],85:[2,79],90:[2,79],92:[2,79],101:[2,79],103:[2,79],104:[2,79],105:[2,79],109:[2,79],117:[2,79],125:[2,79],127:[2,79],128:[2,79],131:[2,79],132:[2,79],133:[2,79],134:[2,79],135:[2,79],136:[2,79]},{1:[2,105],6:[2,105],25:[2,105],26:[2,105],49:[2,105],54:[2,105],57:[2,105],66:[2,105],67:[2,105],68:[2,105],70:[2,105],72:[2,105],73:[2,105],77:[2,105],81:104,83:[2,105],84:[1,105],85:[2,105],90:[2,105],92:[2,105],101:[2,105],103:[2,105],104:[2,105],105:[2,105],109:[2,105],117:[2,105],125:[2,105],127:[2,105],128:[2,105],131:[2,105],132:[2,105],133:[2,105],134:[2,105],135:[2,105],136:[2,105]},{6:[2,55],25:[2,55],27:109,28:[1,73],44:110,48:106,49:[2,55],54:[2,55],55:107,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{5:115,25:[1,5]},{8:116,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:118,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:119,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{13:121,14:122,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,58:47,59:48,61:120,63:25,64:26,65:27,75:[1,70],82:[1,28],87:[1,58],88:[1,59],89:[1,57],100:[1,56]},{13:121,14:122,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,58:47,59:48,61:124,63:25,64:26,65:27,75:[1,70],82:[1,28],87:[1,58],88:[1,59],89:[1,57],100:[1,56]},{1:[2,72],6:[2,72],25:[2,72],26:[2,72],40:[2,72],49:[2,72],54:[2,72],57:[2,72],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,72],73:[2,72],77:[2,72],79:[1,128],83:[2,72],84:[2,72],85:[2,72],90:[2,72],92:[2,72],101:[2,72],103:[2,72],104:[2,72],105:[2,72],109:[2,72],117:[2,72],125:[2,72],127:[2,72],128:[2,72],129:[1,125],130:[1,126],131:[2,72],132:[2,72],133:[2,72],134:[2,72],135:[2,72],136:[2,72],137:[1,127]},{1:[2,180],6:[2,180],25:[2,180],26:[2,180],49:[2,180],54:[2,180],57:[2,180],72:[2,180],77:[2,180],85:[2,180],90:[2,180],92:[2,180],101:[2,180],103:[2,180],104:[2,180],105:[2,180],109:[2,180],117:[2,180],120:[1,129],125:[2,180],127:[2,180],128:[2,180],131:[2,180],132:[2,180],133:[2,180],134:[2,180],135:[2,180],136:[2,180]},{5:130,25:[1,5]},{5:131,25:[1,5]},{1:[2,147],6:[2,147],25:[2,147],26:[2,147],49:[2,147],54:[2,147],57:[2,147],72:[2,147],77:[2,147],85:[2,147],90:[2,147],92:[2,147],101:[2,147],103:[2,147],104:[2,147],105:[2,147],109:[2,147],117:[2,147],125:[2,147],127:[2,147],128:[2,147],131:[2,147],132:[2,147],133:[2,147],134:[2,147],135:[2,147],136:[2,147]},{5:132,25:[1,5]},{8:133,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,134],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,95],5:135,6:[2,95],13:121,14:122,25:[1,5],26:[2,95],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,49:[2,95],54:[2,95],57:[2,95],58:47,59:48,61:137,63:25,64:26,65:27,72:[2,95],75:[1,70],77:[2,95],79:[1,136],82:[1,28],85:[2,95],87:[1,58],88:[1,59],89:[1,57],90:[2,95],92:[2,95],100:[1,56],101:[2,95],103:[2,95],104:[2,95],105:[2,95],109:[2,95],117:[2,95],125:[2,95],127:[2,95],128:[2,95],131:[2,95],132:[2,95],133:[2,95],134:[2,95],135:[2,95],136:[2,95]},{8:138,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,47],6:[2,47],8:139,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,47],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],101:[2,47],102:39,103:[2,47],105:[2,47],106:40,107:[1,67],108:41,109:[2,47],110:69,118:[1,42],123:37,124:[1,64],125:[2,47],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,48],6:[2,48],25:[2,48],26:[2,48],54:[2,48],77:[2,48],101:[2,48],103:[2,48],105:[2,48],109:[2,48],125:[2,48]},{1:[2,73],6:[2,73],25:[2,73],26:[2,73],40:[2,73],49:[2,73],54:[2,73],57:[2,73],66:[2,73],67:[2,73],68:[2,73],70:[2,73],72:[2,73],73:[2,73],77:[2,73],83:[2,73],84:[2,73],85:[2,73],90:[2,73],92:[2,73],101:[2,73],103:[2,73],104:[2,73],105:[2,73],109:[2,73],117:[2,73],125:[2,73],127:[2,73],128:[2,73],131:[2,73],132:[2,73],133:[2,73],134:[2,73],135:[2,73],136:[2,73]},{1:[2,74],6:[2,74],25:[2,74],26:[2,74],40:[2,74],49:[2,74],54:[2,74],57:[2,74],66:[2,74],67:[2,74],68:[2,74],70:[2,74],72:[2,74],73:[2,74],77:[2,74],83:[2,74],84:[2,74],85:[2,74],90:[2,74],92:[2,74],101:[2,74],103:[2,74],104:[2,74],105:[2,74],109:[2,74],117:[2,74],125:[2,74],127:[2,74],128:[2,74],131:[2,74],132:[2,74],133:[2,74],134:[2,74],135:[2,74],136:[2,74]},{1:[2,29],6:[2,29],25:[2,29],26:[2,29],49:[2,29],54:[2,29],57:[2,29],66:[2,29],67:[2,29],68:[2,29],70:[2,29],72:[2,29],73:[2,29],77:[2,29],83:[2,29],84:[2,29],85:[2,29],90:[2,29],92:[2,29],101:[2,29],103:[2,29],104:[2,29],105:[2,29],109:[2,29],117:[2,29],125:[2,29],127:[2,29],128:[2,29],131:[2,29],132:[2,29],133:[2,29],134:[2,29],135:[2,29],136:[2,29]},{1:[2,30],6:[2,30],25:[2,30],26:[2,30],49:[2,30],54:[2,30],57:[2,30],66:[2,30],67:[2,30],68:[2,30],70:[2,30],72:[2,30],73:[2,30],77:[2,30],83:[2,30],84:[2,30],85:[2,30],90:[2,30],92:[2,30],101:[2,30],103:[2,30],104:[2,30],105:[2,30],109:[2,30],117:[2,30],125:[2,30],127:[2,30],128:[2,30],131:[2,30],132:[2,30],133:[2,30],134:[2,30],135:[2,30],136:[2,30]},{1:[2,31],6:[2,31],25:[2,31],26:[2,31],49:[2,31],54:[2,31],57:[2,31],66:[2,31],67:[2,31],68:[2,31],70:[2,31],72:[2,31],73:[2,31],77:[2,31],83:[2,31],84:[2,31],85:[2,31],90:[2,31],92:[2,31],101:[2,31],103:[2,31],104:[2,31],105:[2,31],109:[2,31],117:[2,31],125:[2,31],127:[2,31],128:[2,31],131:[2,31],132:[2,31],133:[2,31],134:[2,31],135:[2,31],136:[2,31]},{1:[2,32],6:[2,32],25:[2,32],26:[2,32],49:[2,32],54:[2,32],57:[2,32],66:[2,32],67:[2,32],68:[2,32],70:[2,32],72:[2,32],73:[2,32],77:[2,32],83:[2,32],84:[2,32],85:[2,32],90:[2,32],92:[2,32],101:[2,32],103:[2,32],104:[2,32],105:[2,32],109:[2,32],117:[2,32],125:[2,32],127:[2,32],128:[2,32],131:[2,32],132:[2,32],133:[2,32],134:[2,32],135:[2,32],136:[2,32]},{1:[2,33],6:[2,33],25:[2,33],26:[2,33],49:[2,33],54:[2,33],57:[2,33],66:[2,33],67:[2,33],68:[2,33],70:[2,33],72:[2,33],73:[2,33],77:[2,33],83:[2,33],84:[2,33],85:[2,33],90:[2,33],92:[2,33],101:[2,33],103:[2,33],104:[2,33],105:[2,33],109:[2,33],117:[2,33],125:[2,33],127:[2,33],128:[2,33],131:[2,33],132:[2,33],133:[2,33],134:[2,33],135:[2,33],136:[2,33]},{1:[2,34],6:[2,34],25:[2,34],26:[2,34],49:[2,34],54:[2,34],57:[2,34],66:[2,34],67:[2,34],68:[2,34],70:[2,34],72:[2,34],73:[2,34],77:[2,34],83:[2,34],84:[2,34],85:[2,34],90:[2,34],92:[2,34],101:[2,34],103:[2,34],104:[2,34],105:[2,34],109:[2,34],117:[2,34],125:[2,34],127:[2,34],128:[2,34],131:[2,34],132:[2,34],133:[2,34],134:[2,34],135:[2,34],136:[2,34]},{1:[2,35],6:[2,35],25:[2,35],26:[2,35],49:[2,35],54:[2,35],57:[2,35],66:[2,35],67:[2,35],68:[2,35],70:[2,35],72:[2,35],73:[2,35],77:[2,35],83:[2,35],84:[2,35],85:[2,35],90:[2,35],92:[2,35],101:[2,35],103:[2,35],104:[2,35],105:[2,35],109:[2,35],117:[2,35],125:[2,35],127:[2,35],128:[2,35],131:[2,35],132:[2,35],133:[2,35],134:[2,35],135:[2,35],136:[2,35]},{4:140,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,141],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:142,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:144,87:[1,58],88:[1,59],89:[1,57],90:[1,143],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,111],6:[2,111],25:[2,111],26:[2,111],49:[2,111],54:[2,111],57:[2,111],66:[2,111],67:[2,111],68:[2,111],70:[2,111],72:[2,111],73:[2,111],77:[2,111],83:[2,111],84:[2,111],85:[2,111],90:[2,111],92:[2,111],101:[2,111],103:[2,111],104:[2,111],105:[2,111],109:[2,111],117:[2,111],125:[2,111],127:[2,111],128:[2,111],131:[2,111],132:[2,111],133:[2,111],134:[2,111],135:[2,111],136:[2,111]},{1:[2,112],6:[2,112],25:[2,112],26:[2,112],27:148,28:[1,73],49:[2,112],54:[2,112],57:[2,112],66:[2,112],67:[2,112],68:[2,112],70:[2,112],72:[2,112],73:[2,112],77:[2,112],83:[2,112],84:[2,112],85:[2,112],90:[2,112],92:[2,112],101:[2,112],103:[2,112],104:[2,112],105:[2,112],109:[2,112],117:[2,112],125:[2,112],127:[2,112],128:[2,112],131:[2,112],132:[2,112],133:[2,112],134:[2,112],135:[2,112],136:[2,112]},{25:[2,51]},{25:[2,52]},{1:[2,68],6:[2,68],25:[2,68],26:[2,68],40:[2,68],49:[2,68],54:[2,68],57:[2,68],66:[2,68],67:[2,68],68:[2,68],70:[2,68],72:[2,68],73:[2,68],77:[2,68],79:[2,68],83:[2,68],84:[2,68],85:[2,68],90:[2,68],92:[2,68],101:[2,68],103:[2,68],104:[2,68],105:[2,68],109:[2,68],117:[2,68],125:[2,68],127:[2,68],128:[2,68],129:[2,68],130:[2,68],131:[2,68],132:[2,68],133:[2,68],134:[2,68],135:[2,68],136:[2,68],137:[2,68]},{1:[2,71],6:[2,71],25:[2,71],26:[2,71],40:[2,71],49:[2,71],54:[2,71],57:[2,71],66:[2,71],67:[2,71],68:[2,71],70:[2,71],72:[2,71],73:[2,71],77:[2,71],79:[2,71],83:[2,71],84:[2,71],85:[2,71],90:[2,71],92:[2,71],101:[2,71],103:[2,71],104:[2,71],105:[2,71],109:[2,71],117:[2,71],125:[2,71],127:[2,71],128:[2,71],129:[2,71],130:[2,71],131:[2,71],132:[2,71],133:[2,71],134:[2,71],135:[2,71],136:[2,71],137:[2,71]},{8:149,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:150,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:151,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{5:152,8:153,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{27:158,28:[1,73],44:159,58:160,59:161,64:154,75:[1,70],88:[1,113],89:[1,57],112:155,113:[1,156],114:157},{111:162,115:[1,163],116:[1,164]},{6:[2,90],11:168,25:[2,90],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:166,42:167,44:171,46:[1,46],54:[2,90],76:165,77:[2,90],88:[1,113]},{1:[2,27],6:[2,27],25:[2,27],26:[2,27],43:[2,27],49:[2,27],54:[2,27],57:[2,27],66:[2,27],67:[2,27],68:[2,27],70:[2,27],72:[2,27],73:[2,27],77:[2,27],83:[2,27],84:[2,27],85:[2,27],90:[2,27],92:[2,27],101:[2,27],103:[2,27],104:[2,27],105:[2,27],109:[2,27],117:[2,27],125:[2,27],127:[2,27],128:[2,27],131:[2,27],132:[2,27],133:[2,27],134:[2,27],135:[2,27],136:[2,27]},{1:[2,28],6:[2,28],25:[2,28],26:[2,28],43:[2,28],49:[2,28],54:[2,28],57:[2,28],66:[2,28],67:[2,28],68:[2,28],70:[2,28],72:[2,28],73:[2,28],77:[2,28],83:[2,28],84:[2,28],85:[2,28],90:[2,28],92:[2,28],101:[2,28],103:[2,28],104:[2,28],105:[2,28],109:[2,28],117:[2,28],125:[2,28],127:[2,28],128:[2,28],131:[2,28],132:[2,28],133:[2,28],134:[2,28],135:[2,28],136:[2,28]},{1:[2,26],6:[2,26],25:[2,26],26:[2,26],40:[2,26],43:[2,26],49:[2,26],54:[2,26],57:[2,26],66:[2,26],67:[2,26],68:[2,26],70:[2,26],72:[2,26],73:[2,26],77:[2,26],79:[2,26],83:[2,26],84:[2,26],85:[2,26],90:[2,26],92:[2,26],101:[2,26],103:[2,26],104:[2,26],105:[2,26],109:[2,26],115:[2,26],116:[2,26],117:[2,26],125:[2,26],127:[2,26],128:[2,26],129:[2,26],130:[2,26],131:[2,26],132:[2,26],133:[2,26],134:[2,26],135:[2,26],136:[2,26],137:[2,26]},{1:[2,6],6:[2,6],7:172,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,6],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],101:[2,6],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,3]},{1:[2,24],6:[2,24],25:[2,24],26:[2,24],49:[2,24],54:[2,24],57:[2,24],72:[2,24],77:[2,24],85:[2,24],90:[2,24],92:[2,24],97:[2,24],98:[2,24],101:[2,24],103:[2,24],104:[2,24],105:[2,24],109:[2,24],117:[2,24],120:[2,24],122:[2,24],125:[2,24],127:[2,24],128:[2,24],131:[2,24],132:[2,24],133:[2,24],134:[2,24],135:[2,24],136:[2,24]},{6:[1,74],26:[1,173]},{1:[2,191],6:[2,191],25:[2,191],26:[2,191],49:[2,191],54:[2,191],57:[2,191],72:[2,191],77:[2,191],85:[2,191],90:[2,191],92:[2,191],101:[2,191],103:[2,191],104:[2,191],105:[2,191],109:[2,191],117:[2,191],125:[2,191],127:[2,191],128:[2,191],131:[2,191],132:[2,191],133:[2,191],134:[2,191],135:[2,191],136:[2,191]},{8:174,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:175,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:176,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:177,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:178,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:179,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:180,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:181,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,146],6:[2,146],25:[2,146],26:[2,146],49:[2,146],54:[2,146],57:[2,146],72:[2,146],77:[2,146],85:[2,146],90:[2,146],92:[2,146],101:[2,146],103:[2,146],104:[2,146],105:[2,146],109:[2,146],117:[2,146],125:[2,146],127:[2,146],128:[2,146],131:[2,146],132:[2,146],133:[2,146],134:[2,146],135:[2,146],136:[2,146]},{1:[2,151],6:[2,151],25:[2,151],26:[2,151],49:[2,151],54:[2,151],57:[2,151],72:[2,151],77:[2,151],85:[2,151],90:[2,151],92:[2,151],101:[2,151],103:[2,151],104:[2,151],105:[2,151],109:[2,151],117:[2,151],125:[2,151],127:[2,151],128:[2,151],131:[2,151],132:[2,151],133:[2,151],134:[2,151],135:[2,151],136:[2,151]},{8:182,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,145],6:[2,145],25:[2,145],26:[2,145],49:[2,145],54:[2,145],57:[2,145],72:[2,145],77:[2,145],85:[2,145],90:[2,145],92:[2,145],101:[2,145],103:[2,145],104:[2,145],105:[2,145],109:[2,145],117:[2,145],125:[2,145],127:[2,145],128:[2,145],131:[2,145],132:[2,145],133:[2,145],134:[2,145],135:[2,145],136:[2,145]},{1:[2,150],6:[2,150],25:[2,150],26:[2,150],49:[2,150],54:[2,150],57:[2,150],72:[2,150],77:[2,150],85:[2,150],90:[2,150],92:[2,150],101:[2,150],103:[2,150],104:[2,150],105:[2,150],109:[2,150],117:[2,150],125:[2,150],127:[2,150],128:[2,150],131:[2,150],132:[2,150],133:[2,150],134:[2,150],135:[2,150],136:[2,150]},{81:183,84:[1,105]},{1:[2,69],6:[2,69],25:[2,69],26:[2,69],40:[2,69],49:[2,69],54:[2,69],57:[2,69],66:[2,69],67:[2,69],68:[2,69],70:[2,69],72:[2,69],73:[2,69],77:[2,69],79:[2,69],83:[2,69],84:[2,69],85:[2,69],90:[2,69],92:[2,69],101:[2,69],103:[2,69],104:[2,69],105:[2,69],109:[2,69],117:[2,69],125:[2,69],127:[2,69],128:[2,69],129:[2,69],130:[2,69],131:[2,69],132:[2,69],133:[2,69],134:[2,69],135:[2,69],136:[2,69],137:[2,69]},{84:[2,108]},{27:184,28:[1,73]},{27:185,28:[1,73]},{1:[2,83],6:[2,83],25:[2,83],26:[2,83],27:186,28:[1,73],40:[2,83],49:[2,83],54:[2,83],57:[2,83],66:[2,83],67:[2,83],68:[2,83],70:[2,83],72:[2,83],73:[2,83],77:[2,83],79:[2,83],83:[2,83],84:[2,83],85:[2,83],90:[2,83],92:[2,83],101:[2,83],103:[2,83],104:[2,83],105:[2,83],109:[2,83],117:[2,83],125:[2,83],127:[2,83],128:[2,83],129:[2,83],130:[2,83],131:[2,83],132:[2,83],133:[2,83],134:[2,83],135:[2,83],136:[2,83],137:[2,83]},{1:[2,84],6:[2,84],25:[2,84],26:[2,84],40:[2,84],49:[2,84],54:[2,84],57:[2,84],66:[2,84],67:[2,84],68:[2,84],70:[2,84],72:[2,84],73:[2,84],77:[2,84],79:[2,84],83:[2,84],84:[2,84],85:[2,84],90:[2,84],92:[2,84],101:[2,84],103:[2,84],104:[2,84],105:[2,84],109:[2,84],117:[2,84],125:[2,84],127:[2,84],128:[2,84],129:[2,84],130:[2,84],131:[2,84],132:[2,84],133:[2,84],134:[2,84],135:[2,84],136:[2,84],137:[2,84]},{8:188,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],57:[1,192],58:47,59:48,61:36,63:25,64:26,65:27,71:187,74:189,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],91:190,92:[1,191],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{69:193,70:[1,99],73:[1,100]},{81:194,84:[1,105]},{1:[2,70],6:[2,70],25:[2,70],26:[2,70],40:[2,70],49:[2,70],54:[2,70],57:[2,70],66:[2,70],67:[2,70],68:[2,70],70:[2,70],72:[2,70],73:[2,70],77:[2,70],79:[2,70],83:[2,70],84:[2,70],85:[2,70],90:[2,70],92:[2,70],101:[2,70],103:[2,70],104:[2,70],105:[2,70],109:[2,70],117:[2,70],125:[2,70],127:[2,70],128:[2,70],129:[2,70],130:[2,70],131:[2,70],132:[2,70],133:[2,70],134:[2,70],135:[2,70],136:[2,70],137:[2,70]},{6:[1,196],8:195,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,197],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,106],6:[2,106],25:[2,106],26:[2,106],49:[2,106],54:[2,106],57:[2,106],66:[2,106],67:[2,106],68:[2,106],70:[2,106],72:[2,106],73:[2,106],77:[2,106],83:[2,106],84:[2,106],85:[2,106],90:[2,106],92:[2,106],101:[2,106],103:[2,106],104:[2,106],105:[2,106],109:[2,106],117:[2,106],125:[2,106],127:[2,106],128:[2,106],131:[2,106],132:[2,106],133:[2,106],134:[2,106],135:[2,106],136:[2,106]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],85:[1,198],86:199,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],49:[1,201],53:203,54:[1,202]},{6:[2,56],25:[2,56],26:[2,56],49:[2,56],54:[2,56]},{6:[2,60],25:[2,60],26:[2,60],40:[1,205],49:[2,60],54:[2,60],57:[1,204]},{6:[2,63],25:[2,63],26:[2,63],40:[2,63],49:[2,63],54:[2,63],57:[2,63]},{6:[2,64],25:[2,64],26:[2,64],40:[2,64],49:[2,64],54:[2,64],57:[2,64]},{6:[2,65],25:[2,65],26:[2,65],40:[2,65],49:[2,65],54:[2,65],57:[2,65]},{6:[2,66],25:[2,66],26:[2,66],40:[2,66],49:[2,66],54:[2,66],57:[2,66]},{27:148,28:[1,73]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:144,87:[1,58],88:[1,59],89:[1,57],90:[1,143],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,50],6:[2,50],25:[2,50],26:[2,50],49:[2,50],54:[2,50],57:[2,50],72:[2,50],77:[2,50],85:[2,50],90:[2,50],92:[2,50],101:[2,50],103:[2,50],104:[2,50],105:[2,50],109:[2,50],117:[2,50],125:[2,50],127:[2,50],128:[2,50],131:[2,50],132:[2,50],133:[2,50],134:[2,50],135:[2,50],136:[2,50]},{1:[2,184],6:[2,184],25:[2,184],26:[2,184],49:[2,184],54:[2,184],57:[2,184],72:[2,184],77:[2,184],85:[2,184],90:[2,184],92:[2,184],101:[2,184],102:87,103:[2,184],104:[2,184],105:[2,184],108:88,109:[2,184],110:69,117:[2,184],125:[2,184],127:[2,184],128:[2,184],131:[1,78],132:[2,184],133:[2,184],134:[2,184],135:[2,184],136:[2,184]},{102:90,103:[1,65],105:[1,66],108:91,109:[1,68],110:69,125:[1,89]},{1:[2,185],6:[2,185],25:[2,185],26:[2,185],49:[2,185],54:[2,185],57:[2,185],72:[2,185],77:[2,185],85:[2,185],90:[2,185],92:[2,185],101:[2,185],102:87,103:[2,185],104:[2,185],105:[2,185],108:88,109:[2,185],110:69,117:[2,185],125:[2,185],127:[2,185],128:[2,185],131:[1,78],132:[2,185],133:[2,185],134:[2,185],135:[2,185],136:[2,185]},{1:[2,186],6:[2,186],25:[2,186],26:[2,186],49:[2,186],54:[2,186],57:[2,186],72:[2,186],77:[2,186],85:[2,186],90:[2,186],92:[2,186],101:[2,186],102:87,103:[2,186],104:[2,186],105:[2,186],108:88,109:[2,186],110:69,117:[2,186],125:[2,186],127:[2,186],128:[2,186],131:[1,78],132:[2,186],133:[2,186],134:[2,186],135:[2,186],136:[2,186]},{1:[2,187],6:[2,187],25:[2,187],26:[2,187],49:[2,187],54:[2,187],57:[2,187],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,187],73:[2,72],77:[2,187],83:[2,72],84:[2,72],85:[2,187],90:[2,187],92:[2,187],101:[2,187],103:[2,187],104:[2,187],105:[2,187],109:[2,187],117:[2,187],125:[2,187],127:[2,187],128:[2,187],131:[2,187],132:[2,187],133:[2,187],134:[2,187],135:[2,187],136:[2,187]},{62:93,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],73:[1,100],80:92,83:[1,94],84:[2,107]},{62:102,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],73:[1,100],80:101,83:[1,94],84:[2,107]},{66:[2,75],67:[2,75],68:[2,75],70:[2,75],73:[2,75],83:[2,75],84:[2,75]},{1:[2,188],6:[2,188],25:[2,188],26:[2,188],49:[2,188],54:[2,188],57:[2,188],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,188],73:[2,72],77:[2,188],83:[2,72],84:[2,72],85:[2,188],90:[2,188],92:[2,188],101:[2,188],103:[2,188],104:[2,188],105:[2,188],109:[2,188],117:[2,188],125:[2,188],127:[2,188],128:[2,188],131:[2,188],132:[2,188],133:[2,188],134:[2,188],135:[2,188],136:[2,188]},{1:[2,189],6:[2,189],25:[2,189],26:[2,189],49:[2,189],54:[2,189],57:[2,189],72:[2,189],77:[2,189],85:[2,189],90:[2,189],92:[2,189],101:[2,189],103:[2,189],104:[2,189],105:[2,189],109:[2,189],117:[2,189],125:[2,189],127:[2,189],128:[2,189],131:[2,189],132:[2,189],133:[2,189],134:[2,189],135:[2,189],136:[2,189]},{1:[2,190],6:[2,190],25:[2,190],26:[2,190],49:[2,190],54:[2,190],57:[2,190],72:[2,190],77:[2,190],85:[2,190],90:[2,190],92:[2,190],101:[2,190],103:[2,190],104:[2,190],105:[2,190],109:[2,190],117:[2,190],125:[2,190],127:[2,190],128:[2,190],131:[2,190],132:[2,190],133:[2,190],134:[2,190],135:[2,190],136:[2,190]},{8:206,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,207],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:208,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{5:209,25:[1,5],124:[1,210]},{1:[2,132],6:[2,132],25:[2,132],26:[2,132],49:[2,132],54:[2,132],57:[2,132],72:[2,132],77:[2,132],85:[2,132],90:[2,132],92:[2,132],96:211,97:[1,212],98:[1,213],101:[2,132],103:[2,132],104:[2,132],105:[2,132],109:[2,132],117:[2,132],125:[2,132],127:[2,132],128:[2,132],131:[2,132],132:[2,132],133:[2,132],134:[2,132],135:[2,132],136:[2,132]},{1:[2,144],6:[2,144],25:[2,144],26:[2,144],49:[2,144],54:[2,144],57:[2,144],72:[2,144],77:[2,144],85:[2,144],90:[2,144],92:[2,144],101:[2,144],103:[2,144],104:[2,144],105:[2,144],109:[2,144],117:[2,144],125:[2,144],127:[2,144],128:[2,144],131:[2,144],132:[2,144],133:[2,144],134:[2,144],135:[2,144],136:[2,144]},{1:[2,152],6:[2,152],25:[2,152],26:[2,152],49:[2,152],54:[2,152],57:[2,152],72:[2,152],77:[2,152],85:[2,152],90:[2,152],92:[2,152],101:[2,152],103:[2,152],104:[2,152],105:[2,152],109:[2,152],117:[2,152],125:[2,152],127:[2,152],128:[2,152],131:[2,152],132:[2,152],133:[2,152],134:[2,152],135:[2,152],136:[2,152]},{25:[1,214],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{119:215,121:216,122:[1,217]},{1:[2,96],6:[2,96],25:[2,96],26:[2,96],49:[2,96],54:[2,96],57:[2,96],72:[2,96],77:[2,96],85:[2,96],90:[2,96],92:[2,96],101:[2,96],103:[2,96],104:[2,96],105:[2,96],109:[2,96],117:[2,96],125:[2,96],127:[2,96],128:[2,96],131:[2,96],132:[2,96],133:[2,96],134:[2,96],135:[2,96],136:[2,96]},{8:218,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,99],5:219,6:[2,99],25:[1,5],26:[2,99],49:[2,99],54:[2,99],57:[2,99],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,99],73:[2,72],77:[2,99],79:[1,220],83:[2,72],84:[2,72],85:[2,99],90:[2,99],92:[2,99],101:[2,99],103:[2,99],104:[2,99],105:[2,99],109:[2,99],117:[2,99],125:[2,99],127:[2,99],128:[2,99],131:[2,99],132:[2,99],133:[2,99],134:[2,99],135:[2,99],136:[2,99]},{1:[2,137],6:[2,137],25:[2,137],26:[2,137],49:[2,137],54:[2,137],57:[2,137],72:[2,137],77:[2,137],85:[2,137],90:[2,137],92:[2,137],101:[2,137],102:87,103:[2,137],104:[2,137],105:[2,137],108:88,109:[2,137],110:69,117:[2,137],125:[2,137],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,46],6:[2,46],26:[2,46],101:[2,46],102:87,103:[2,46],105:[2,46],108:88,109:[2,46],110:69,125:[2,46],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,74],101:[1,221]},{4:222,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,128],25:[2,128],54:[2,128],57:[1,224],90:[2,128],91:223,92:[1,191],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,114],6:[2,114],25:[2,114],26:[2,114],40:[2,114],49:[2,114],54:[2,114],57:[2,114],66:[2,114],67:[2,114],68:[2,114],70:[2,114],72:[2,114],73:[2,114],77:[2,114],83:[2,114],84:[2,114],85:[2,114],90:[2,114],92:[2,114],101:[2,114],103:[2,114],104:[2,114],105:[2,114],109:[2,114],115:[2,114],116:[2,114],117:[2,114],125:[2,114],127:[2,114],128:[2,114],131:[2,114],132:[2,114],133:[2,114],134:[2,114],135:[2,114],136:[2,114]},{6:[2,53],25:[2,53],53:225,54:[1,226],90:[2,53]},{6:[2,123],25:[2,123],26:[2,123],54:[2,123],85:[2,123],90:[2,123]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:227,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,129],25:[2,129],26:[2,129],54:[2,129],85:[2,129],90:[2,129]},{1:[2,113],6:[2,113],25:[2,113],26:[2,113],40:[2,113],43:[2,113],49:[2,113],54:[2,113],57:[2,113],66:[2,113],67:[2,113],68:[2,113],70:[2,113],72:[2,113],73:[2,113],77:[2,113],79:[2,113],83:[2,113],84:[2,113],85:[2,113],90:[2,113],92:[2,113],101:[2,113],103:[2,113],104:[2,113],105:[2,113],109:[2,113],115:[2,113],116:[2,113],117:[2,113],125:[2,113],127:[2,113],128:[2,113],129:[2,113],130:[2,113],131:[2,113],132:[2,113],133:[2,113],134:[2,113],135:[2,113],136:[2,113],137:[2,113]},{5:228,25:[1,5],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,140],6:[2,140],25:[2,140],26:[2,140],49:[2,140],54:[2,140],57:[2,140],72:[2,140],77:[2,140],85:[2,140],90:[2,140],92:[2,140],101:[2,140],102:87,103:[1,65],104:[1,229],105:[1,66],108:88,109:[1,68],110:69,117:[2,140],125:[2,140],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,142],6:[2,142],25:[2,142],26:[2,142],49:[2,142],54:[2,142],57:[2,142],72:[2,142],77:[2,142],85:[2,142],90:[2,142],92:[2,142],101:[2,142],102:87,103:[1,65],104:[1,230],105:[1,66],108:88,109:[1,68],110:69,117:[2,142],125:[2,142],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,148],6:[2,148],25:[2,148],26:[2,148],49:[2,148],54:[2,148],57:[2,148],72:[2,148],77:[2,148],85:[2,148],90:[2,148],92:[2,148],101:[2,148],103:[2,148],104:[2,148],105:[2,148],109:[2,148],117:[2,148],125:[2,148],127:[2,148],128:[2,148],131:[2,148],132:[2,148],133:[2,148],134:[2,148],135:[2,148],136:[2,148]},{1:[2,149],6:[2,149],25:[2,149],26:[2,149],49:[2,149],54:[2,149],57:[2,149],72:[2,149],77:[2,149],85:[2,149],90:[2,149],92:[2,149],101:[2,149],102:87,103:[1,65],104:[2,149],105:[1,66],108:88,109:[1,68],110:69,117:[2,149],125:[2,149],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,153],6:[2,153],25:[2,153],26:[2,153],49:[2,153],54:[2,153],57:[2,153],72:[2,153],77:[2,153],85:[2,153],90:[2,153],92:[2,153],101:[2,153],103:[2,153],104:[2,153],105:[2,153],109:[2,153],117:[2,153],125:[2,153],127:[2,153],128:[2,153],131:[2,153],132:[2,153],133:[2,153],134:[2,153],135:[2,153],136:[2,153]},{115:[2,155],116:[2,155]},{27:158,28:[1,73],44:159,58:160,59:161,75:[1,70],88:[1,113],89:[1,114],112:231,114:157},{54:[1,232],115:[2,161],116:[2,161]},{54:[2,157],115:[2,157],116:[2,157]},{54:[2,158],115:[2,158],116:[2,158]},{54:[2,159],115:[2,159],116:[2,159]},{54:[2,160],115:[2,160],116:[2,160]},{1:[2,154],6:[2,154],25:[2,154],26:[2,154],49:[2,154],54:[2,154],57:[2,154],72:[2,154],77:[2,154],85:[2,154],90:[2,154],92:[2,154],101:[2,154],103:[2,154],104:[2,154],105:[2,154],109:[2,154],117:[2,154],125:[2,154],127:[2,154],128:[2,154],131:[2,154],132:[2,154],133:[2,154],134:[2,154],135:[2,154],136:[2,154]},{8:233,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:234,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],53:235,54:[1,236],77:[2,53]},{6:[2,91],25:[2,91],26:[2,91],54:[2,91],77:[2,91]},{6:[2,39],25:[2,39],26:[2,39],43:[1,237],54:[2,39],77:[2,39]},{6:[2,42],25:[2,42],26:[2,42],54:[2,42],77:[2,42]},{6:[2,43],25:[2,43],26:[2,43],43:[2,43],54:[2,43],77:[2,43]},{6:[2,44],25:[2,44],26:[2,44],43:[2,44],54:[2,44],77:[2,44]},{6:[2,45],25:[2,45],26:[2,45],43:[2,45],54:[2,45],77:[2,45]},{1:[2,5],6:[2,5],26:[2,5],101:[2,5]},{1:[2,25],6:[2,25],25:[2,25],26:[2,25],49:[2,25],54:[2,25],57:[2,25],72:[2,25],77:[2,25],85:[2,25],90:[2,25],92:[2,25],97:[2,25],98:[2,25],101:[2,25],103:[2,25],104:[2,25],105:[2,25],109:[2,25],117:[2,25],120:[2,25],122:[2,25],125:[2,25],127:[2,25],128:[2,25],131:[2,25],132:[2,25],133:[2,25],134:[2,25],135:[2,25],136:[2,25]},{1:[2,192],6:[2,192],25:[2,192],26:[2,192],49:[2,192],54:[2,192],57:[2,192],72:[2,192],77:[2,192],85:[2,192],90:[2,192],92:[2,192],101:[2,192],102:87,103:[2,192],104:[2,192],105:[2,192],108:88,109:[2,192],110:69,117:[2,192],125:[2,192],127:[2,192],128:[2,192],131:[1,78],132:[1,81],133:[2,192],134:[2,192],135:[2,192],136:[2,192]},{1:[2,193],6:[2,193],25:[2,193],26:[2,193],49:[2,193],54:[2,193],57:[2,193],72:[2,193],77:[2,193],85:[2,193],90:[2,193],92:[2,193],101:[2,193],102:87,103:[2,193],104:[2,193],105:[2,193],108:88,109:[2,193],110:69,117:[2,193],125:[2,193],127:[2,193],128:[2,193],131:[1,78],132:[1,81],133:[2,193],134:[2,193],135:[2,193],136:[2,193]},{1:[2,194],6:[2,194],25:[2,194],26:[2,194],49:[2,194],54:[2,194],57:[2,194],72:[2,194],77:[2,194],85:[2,194],90:[2,194],92:[2,194],101:[2,194],102:87,103:[2,194],104:[2,194],105:[2,194],108:88,109:[2,194],110:69,117:[2,194],125:[2,194],127:[2,194],128:[2,194],131:[1,78],132:[2,194],133:[2,194],134:[2,194],135:[2,194],136:[2,194]},{1:[2,195],6:[2,195],25:[2,195],26:[2,195],49:[2,195],54:[2,195],57:[2,195],72:[2,195],77:[2,195],85:[2,195],90:[2,195],92:[2,195],101:[2,195],102:87,103:[2,195],104:[2,195],105:[2,195],108:88,109:[2,195],110:69,117:[2,195],125:[2,195],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[2,195],134:[2,195],135:[2,195],136:[2,195]},{1:[2,196],6:[2,196],25:[2,196],26:[2,196],49:[2,196],54:[2,196],57:[2,196],72:[2,196],77:[2,196],85:[2,196],90:[2,196],92:[2,196],101:[2,196],102:87,103:[2,196],104:[2,196],105:[2,196],108:88,109:[2,196],110:69,117:[2,196],125:[2,196],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[2,196],135:[2,196],136:[1,85]},{1:[2,197],6:[2,197],25:[2,197],26:[2,197],49:[2,197],54:[2,197],57:[2,197],72:[2,197],77:[2,197],85:[2,197],90:[2,197],92:[2,197],101:[2,197],102:87,103:[2,197],104:[2,197],105:[2,197],108:88,109:[2,197],110:69,117:[2,197],125:[2,197],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[2,197],136:[1,85]},{1:[2,198],6:[2,198],25:[2,198],26:[2,198],49:[2,198],54:[2,198],57:[2,198],72:[2,198],77:[2,198],85:[2,198],90:[2,198],92:[2,198],101:[2,198],102:87,103:[2,198],104:[2,198],105:[2,198],108:88,109:[2,198],110:69,117:[2,198],125:[2,198],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[2,198],135:[2,198],136:[2,198]},{1:[2,183],6:[2,183],25:[2,183],26:[2,183],49:[2,183],54:[2,183],57:[2,183],72:[2,183],77:[2,183],85:[2,183],90:[2,183],92:[2,183],101:[2,183],102:87,103:[1,65],104:[2,183],105:[1,66],108:88,109:[1,68],110:69,117:[2,183],125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,182],6:[2,182],25:[2,182],26:[2,182],49:[2,182],54:[2,182],57:[2,182],72:[2,182],77:[2,182],85:[2,182],90:[2,182],92:[2,182],101:[2,182],102:87,103:[1,65],104:[2,182],105:[1,66],108:88,109:[1,68],110:69,117:[2,182],125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,103],6:[2,103],25:[2,103],26:[2,103],49:[2,103],54:[2,103],57:[2,103],66:[2,103],67:[2,103],68:[2,103],70:[2,103],72:[2,103],73:[2,103],77:[2,103],83:[2,103],84:[2,103],85:[2,103],90:[2,103],92:[2,103],101:[2,103],103:[2,103],104:[2,103],105:[2,103],109:[2,103],117:[2,103],125:[2,103],127:[2,103],128:[2,103],131:[2,103],132:[2,103],133:[2,103],134:[2,103],135:[2,103],136:[2,103]},{1:[2,80],6:[2,80],25:[2,80],26:[2,80],40:[2,80],49:[2,80],54:[2,80],57:[2,80],66:[2,80],67:[2,80],68:[2,80],70:[2,80],72:[2,80],73:[2,80],77:[2,80],79:[2,80],83:[2,80],84:[2,80],85:[2,80],90:[2,80],92:[2,80],101:[2,80],103:[2,80],104:[2,80],105:[2,80],109:[2,80],117:[2,80],125:[2,80],127:[2,80],128:[2,80],129:[2,80],130:[2,80],131:[2,80],132:[2,80],133:[2,80],134:[2,80],135:[2,80],136:[2,80],137:[2,80]},{1:[2,81],6:[2,81],25:[2,81],26:[2,81],40:[2,81],49:[2,81],54:[2,81],57:[2,81],66:[2,81],67:[2,81],68:[2,81],70:[2,81],72:[2,81],73:[2,81],77:[2,81],79:[2,81],83:[2,81],84:[2,81],85:[2,81],90:[2,81],92:[2,81],101:[2,81],103:[2,81],104:[2,81],105:[2,81],109:[2,81],117:[2,81],125:[2,81],127:[2,81],128:[2,81],129:[2,81],130:[2,81],131:[2,81],132:[2,81],133:[2,81],134:[2,81],135:[2,81],136:[2,81],137:[2,81]},{1:[2,82],6:[2,82],25:[2,82],26:[2,82],40:[2,82],49:[2,82],54:[2,82],57:[2,82],66:[2,82],67:[2,82],68:[2,82],70:[2,82],72:[2,82],73:[2,82],77:[2,82],79:[2,82],83:[2,82],84:[2,82],85:[2,82],90:[2,82],92:[2,82],101:[2,82],103:[2,82],104:[2,82],105:[2,82],109:[2,82],117:[2,82],125:[2,82],127:[2,82],128:[2,82],129:[2,82],130:[2,82],131:[2,82],132:[2,82],133:[2,82],134:[2,82],135:[2,82],136:[2,82],137:[2,82]},{72:[1,238]},{57:[1,192],72:[2,87],91:239,92:[1,191],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{72:[2,88]},{8:240,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,72:[2,122],75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{12:[2,116],28:[2,116],30:[2,116],31:[2,116],33:[2,116],34:[2,116],35:[2,116],36:[2,116],37:[2,116],38:[2,116],45:[2,116],46:[2,116],47:[2,116],51:[2,116],52:[2,116],72:[2,116],75:[2,116],78:[2,116],82:[2,116],87:[2,116],88:[2,116],89:[2,116],95:[2,116],99:[2,116],100:[2,116],103:[2,116],105:[2,116],107:[2,116],109:[2,116],118:[2,116],124:[2,116],126:[2,116],127:[2,116],128:[2,116],129:[2,116],130:[2,116]},{12:[2,117],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],72:[2,117],75:[2,117],78:[2,117],82:[2,117],87:[2,117],88:[2,117],89:[2,117],95:[2,117],99:[2,117],100:[2,117],103:[2,117],105:[2,117],107:[2,117],109:[2,117],118:[2,117],124:[2,117],126:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117]},{1:[2,86],6:[2,86],25:[2,86],26:[2,86],40:[2,86],49:[2,86],54:[2,86],57:[2,86],66:[2,86],67:[2,86],68:[2,86],70:[2,86],72:[2,86],73:[2,86],77:[2,86],79:[2,86],83:[2,86],84:[2,86],85:[2,86],90:[2,86],92:[2,86],101:[2,86],103:[2,86],104:[2,86],105:[2,86],109:[2,86],117:[2,86],125:[2,86],127:[2,86],128:[2,86],129:[2,86],130:[2,86],131:[2,86],132:[2,86],133:[2,86],134:[2,86],135:[2,86],136:[2,86],137:[2,86]},{1:[2,104],6:[2,104],25:[2,104],26:[2,104],49:[2,104],54:[2,104],57:[2,104],66:[2,104],67:[2,104],68:[2,104],70:[2,104],72:[2,104],73:[2,104],77:[2,104],83:[2,104],84:[2,104],85:[2,104],90:[2,104],92:[2,104],101:[2,104],103:[2,104],104:[2,104],105:[2,104],109:[2,104],117:[2,104],125:[2,104],127:[2,104],128:[2,104],131:[2,104],132:[2,104],133:[2,104],134:[2,104],135:[2,104],136:[2,104]},{1:[2,36],6:[2,36],25:[2,36],26:[2,36],49:[2,36],54:[2,36],57:[2,36],72:[2,36],77:[2,36],85:[2,36],90:[2,36],92:[2,36],101:[2,36],102:87,103:[2,36],104:[2,36],105:[2,36],108:88,109:[2,36],110:69,117:[2,36],125:[2,36],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:241,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:242,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,109],6:[2,109],25:[2,109],26:[2,109],49:[2,109],54:[2,109],57:[2,109],66:[2,109],67:[2,109],68:[2,109],70:[2,109],72:[2,109],73:[2,109],77:[2,109],83:[2,109],84:[2,109],85:[2,109],90:[2,109],92:[2,109],101:[2,109],103:[2,109],104:[2,109],105:[2,109],109:[2,109],117:[2,109],125:[2,109],127:[2,109],128:[2,109],131:[2,109],132:[2,109],133:[2,109],134:[2,109],135:[2,109],136:[2,109]},{6:[2,53],25:[2,53],53:243,54:[1,226],85:[2,53]},{6:[2,128],25:[2,128],26:[2,128],54:[2,128],57:[1,244],85:[2,128],90:[2,128],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{50:245,51:[1,60],52:[1,61]},{6:[2,54],25:[2,54],26:[2,54],27:109,28:[1,73],44:110,55:246,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[1,247],25:[1,248]},{6:[2,61],25:[2,61],26:[2,61],49:[2,61],54:[2,61]},{8:249,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,199],6:[2,199],25:[2,199],26:[2,199],49:[2,199],54:[2,199],57:[2,199],72:[2,199],77:[2,199],85:[2,199],90:[2,199],92:[2,199],101:[2,199],102:87,103:[2,199],104:[2,199],105:[2,199],108:88,109:[2,199],110:69,117:[2,199],125:[2,199],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:250,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,201],6:[2,201],25:[2,201],26:[2,201],49:[2,201],54:[2,201],57:[2,201],72:[2,201],77:[2,201],85:[2,201],90:[2,201],92:[2,201],101:[2,201],102:87,103:[2,201],104:[2,201],105:[2,201],108:88,109:[2,201],110:69,117:[2,201],125:[2,201],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,181],6:[2,181],25:[2,181],26:[2,181],49:[2,181],54:[2,181],57:[2,181],72:[2,181],77:[2,181],85:[2,181],90:[2,181],92:[2,181],101:[2,181],103:[2,181],104:[2,181],105:[2,181],109:[2,181],117:[2,181],125:[2,181],127:[2,181],128:[2,181],131:[2,181],132:[2,181],133:[2,181],134:[2,181],135:[2,181],136:[2,181]},{8:251,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,133],6:[2,133],25:[2,133],26:[2,133],49:[2,133],54:[2,133],57:[2,133],72:[2,133],77:[2,133],85:[2,133],90:[2,133],92:[2,133],97:[1,252],101:[2,133],103:[2,133],104:[2,133],105:[2,133],109:[2,133],117:[2,133],125:[2,133],127:[2,133],128:[2,133],131:[2,133],132:[2,133],133:[2,133],134:[2,133],135:[2,133],136:[2,133]},{5:253,25:[1,5]},{27:254,28:[1,73]},{119:255,121:216,122:[1,217]},{26:[1,256],120:[1,257],121:258,122:[1,217]},{26:[2,174],120:[2,174],122:[2,174]},{8:260,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],94:259,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,97],5:261,6:[2,97],25:[1,5],26:[2,97],49:[2,97],54:[2,97],57:[2,97],72:[2,97],77:[2,97],85:[2,97],90:[2,97],92:[2,97],101:[2,97],102:87,103:[1,65],104:[2,97],105:[1,66],108:88,109:[1,68],110:69,117:[2,97],125:[2,97],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,100],6:[2,100],25:[2,100],26:[2,100],49:[2,100],54:[2,100],57:[2,100],72:[2,100],77:[2,100],85:[2,100],90:[2,100],92:[2,100],101:[2,100],103:[2,100],104:[2,100],105:[2,100],109:[2,100],117:[2,100],125:[2,100],127:[2,100],128:[2,100],131:[2,100],132:[2,100],133:[2,100],134:[2,100],135:[2,100],136:[2,100]},{8:262,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,138],6:[2,138],25:[2,138],26:[2,138],49:[2,138],54:[2,138],57:[2,138],66:[2,138],67:[2,138],68:[2,138],70:[2,138],72:[2,138],73:[2,138],77:[2,138],83:[2,138],84:[2,138],85:[2,138],90:[2,138],92:[2,138],101:[2,138],103:[2,138],104:[2,138],105:[2,138],109:[2,138],117:[2,138],125:[2,138],127:[2,138],128:[2,138],131:[2,138],132:[2,138],133:[2,138],134:[2,138],135:[2,138],136:[2,138]},{6:[1,74],26:[1,263]},{8:264,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,67],12:[2,117],25:[2,67],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],54:[2,67],75:[2,117],78:[2,117],82:[2,117],87:[2,117],88:[2,117],89:[2,117],90:[2,67],95:[2,117],99:[2,117],100:[2,117],103:[2,117],105:[2,117],107:[2,117],109:[2,117],118:[2,117],124:[2,117],126:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117]},{6:[1,266],25:[1,267],90:[1,265]},{6:[2,54],8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[2,54],26:[2,54],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],85:[2,54],87:[1,58],88:[1,59],89:[1,57],90:[2,54],93:268,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],26:[2,53],53:269,54:[1,226]},{1:[2,178],6:[2,178],25:[2,178],26:[2,178],49:[2,178],54:[2,178],57:[2,178],72:[2,178],77:[2,178],85:[2,178],90:[2,178],92:[2,178],101:[2,178],103:[2,178],104:[2,178],105:[2,178],109:[2,178],117:[2,178],120:[2,178],125:[2,178],127:[2,178],128:[2,178],131:[2,178],132:[2,178],133:[2,178],134:[2,178],135:[2,178],136:[2,178]},{8:270,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:271,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{115:[2,156],116:[2,156]},{27:158,28:[1,73],44:159,58:160,59:161,75:[1,70],88:[1,113],89:[1,114],114:272},{1:[2,163],6:[2,163],25:[2,163],26:[2,163],49:[2,163],54:[2,163],57:[2,163],72:[2,163],77:[2,163],85:[2,163],90:[2,163],92:[2,163],101:[2,163],102:87,103:[2,163],104:[1,273],105:[2,163],108:88,109:[2,163],110:69,117:[1,274],125:[2,163],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,164],6:[2,164],25:[2,164],26:[2,164],49:[2,164],54:[2,164],57:[2,164],72:[2,164],77:[2,164],85:[2,164],90:[2,164],92:[2,164],101:[2,164],102:87,103:[2,164],104:[1,275],105:[2,164],108:88,109:[2,164],110:69,117:[2,164],125:[2,164],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,277],25:[1,278],77:[1,276]},{6:[2,54],11:168,25:[2,54],26:[2,54],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:279,42:167,44:171,46:[1,46],77:[2,54],88:[1,113]},{8:280,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,281],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,85],6:[2,85],25:[2,85],26:[2,85],40:[2,85],49:[2,85],54:[2,85],57:[2,85],66:[2,85],67:[2,85],68:[2,85],70:[2,85],72:[2,85],73:[2,85],77:[2,85],79:[2,85],83:[2,85],84:[2,85],85:[2,85],90:[2,85],92:[2,85],101:[2,85],103:[2,85],104:[2,85],105:[2,85],109:[2,85],117:[2,85],125:[2,85],127:[2,85],128:[2,85],129:[2,85],130:[2,85],131:[2,85],132:[2,85],133:[2,85],134:[2,85],135:[2,85],136:[2,85],137:[2,85]},{8:282,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,72:[2,120],75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{72:[2,121],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,37],6:[2,37],25:[2,37],26:[2,37],49:[2,37],54:[2,37],57:[2,37],72:[2,37],77:[2,37],85:[2,37],90:[2,37],92:[2,37],101:[2,37],102:87,103:[2,37],104:[2,37],105:[2,37],108:88,109:[2,37],110:69,117:[2,37],125:[2,37],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{26:[1,283],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,266],25:[1,267],85:[1,284]},{6:[2,67],25:[2,67],26:[2,67],54:[2,67],85:[2,67],90:[2,67]},{5:285,25:[1,5]},{6:[2,57],25:[2,57],26:[2,57],49:[2,57],54:[2,57]},{27:109,28:[1,73],44:110,55:286,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[2,55],25:[2,55],26:[2,55],27:109,28:[1,73],44:110,48:287,54:[2,55],55:107,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[2,62],25:[2,62],26:[2,62],49:[2,62],54:[2,62],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{26:[1,288],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{5:289,25:[1,5],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{5:290,25:[1,5]},{1:[2,134],6:[2,134],25:[2,134],26:[2,134],49:[2,134],54:[2,134],57:[2,134],72:[2,134],77:[2,134],85:[2,134],90:[2,134],92:[2,134],101:[2,134],103:[2,134],104:[2,134],105:[2,134],109:[2,134],117:[2,134],125:[2,134],127:[2,134],128:[2,134],131:[2,134],132:[2,134],133:[2,134],134:[2,134],135:[2,134],136:[2,134]},{5:291,25:[1,5]},{26:[1,292],120:[1,293],121:258,122:[1,217]},{1:[2,172],6:[2,172],25:[2,172],26:[2,172],49:[2,172],54:[2,172],57:[2,172],72:[2,172],77:[2,172],85:[2,172],90:[2,172],92:[2,172],101:[2,172],103:[2,172],104:[2,172],105:[2,172],109:[2,172],117:[2,172],125:[2,172],127:[2,172],128:[2,172],131:[2,172],132:[2,172],133:[2,172],134:[2,172],135:[2,172],136:[2,172]},{5:294,25:[1,5]},{26:[2,175],120:[2,175],122:[2,175]},{5:295,25:[1,5],54:[1,296]},{25:[2,130],54:[2,130],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,98],6:[2,98],25:[2,98],26:[2,98],49:[2,98],54:[2,98],57:[2,98],72:[2,98],77:[2,98],85:[2,98],90:[2,98],92:[2,98],101:[2,98],103:[2,98],104:[2,98],105:[2,98],109:[2,98],117:[2,98],125:[2,98],127:[2,98],128:[2,98],131:[2,98],132:[2,98],133:[2,98],134:[2,98],135:[2,98],136:[2,98]},{1:[2,101],5:297,6:[2,101],25:[1,5],26:[2,101],49:[2,101],54:[2,101],57:[2,101],72:[2,101],77:[2,101],85:[2,101],90:[2,101],92:[2,101],101:[2,101],102:87,103:[1,65],104:[2,101],105:[1,66],108:88,109:[1,68],110:69,117:[2,101],125:[2,101],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{101:[1,298]},{90:[1,299],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,115],6:[2,115],25:[2,115],26:[2,115],40:[2,115],49:[2,115],54:[2,115],57:[2,115],66:[2,115],67:[2,115],68:[2,115],70:[2,115],72:[2,115],73:[2,115],77:[2,115],83:[2,115],84:[2,115],85:[2,115],90:[2,115],92:[2,115],101:[2,115],103:[2,115],104:[2,115],105:[2,115],109:[2,115],115:[2,115],116:[2,115],117:[2,115],125:[2,115],127:[2,115],128:[2,115],131:[2,115],132:[2,115],133:[2,115],134:[2,115],135:[2,115],136:[2,115]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],93:300,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:301,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,124],25:[2,124],26:[2,124],54:[2,124],85:[2,124],90:[2,124]},{6:[1,266],25:[1,267],26:[1,302]},{1:[2,141],6:[2,141],25:[2,141],26:[2,141],49:[2,141],54:[2,141],57:[2,141],72:[2,141],77:[2,141],85:[2,141],90:[2,141],92:[2,141],101:[2,141],102:87,103:[1,65],104:[2,141],105:[1,66],108:88,109:[1,68],110:69,117:[2,141],125:[2,141],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,143],6:[2,143],25:[2,143],26:[2,143],49:[2,143],54:[2,143],57:[2,143],72:[2,143],77:[2,143],85:[2,143],90:[2,143],92:[2,143],101:[2,143],102:87,103:[1,65],104:[2,143],105:[1,66],108:88,109:[1,68],110:69,117:[2,143],125:[2,143],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{115:[2,162],116:[2,162]},{8:303,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:304,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:305,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,89],6:[2,89],25:[2,89],26:[2,89],40:[2,89],49:[2,89],54:[2,89],57:[2,89],66:[2,89],67:[2,89],68:[2,89],70:[2,89],72:[2,89],73:[2,89],77:[2,89],83:[2,89],84:[2,89],85:[2,89],90:[2,89],92:[2,89],101:[2,89],103:[2,89],104:[2,89],105:[2,89],109:[2,89],115:[2,89],116:[2,89],117:[2,89],125:[2,89],127:[2,89],128:[2,89],131:[2,89],132:[2,89],133:[2,89],134:[2,89],135:[2,89],136:[2,89]},{11:168,27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:306,42:167,44:171,46:[1,46],88:[1,113]},{6:[2,90],11:168,25:[2,90],26:[2,90],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:166,42:167,44:171,46:[1,46],54:[2,90],76:307,88:[1,113]},{6:[2,92],25:[2,92],26:[2,92],54:[2,92],77:[2,92]},{6:[2,40],25:[2,40],26:[2,40],54:[2,40],77:[2,40],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:308,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{72:[2,119],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,38],6:[2,38],25:[2,38],26:[2,38],49:[2,38],54:[2,38],57:[2,38],72:[2,38],77:[2,38],85:[2,38],90:[2,38],92:[2,38],101:[2,38],103:[2,38],104:[2,38],105:[2,38],109:[2,38],117:[2,38],125:[2,38],127:[2,38],128:[2,38],131:[2,38],132:[2,38],133:[2,38],134:[2,38],135:[2,38],136:[2,38]},{1:[2,110],6:[2,110],25:[2,110],26:[2,110],49:[2,110],54:[2,110],57:[2,110],66:[2,110],67:[2,110],68:[2,110],70:[2,110],72:[2,110],73:[2,110],77:[2,110],83:[2,110],84:[2,110],85:[2,110],90:[2,110],92:[2,110],101:[2,110],103:[2,110],104:[2,110],105:[2,110],109:[2,110],117:[2,110],125:[2,110],127:[2,110],128:[2,110],131:[2,110],132:[2,110],133:[2,110],134:[2,110],135:[2,110],136:[2,110]},{1:[2,49],6:[2,49],25:[2,49],26:[2,49],49:[2,49],54:[2,49],57:[2,49],72:[2,49],77:[2,49],85:[2,49],90:[2,49],92:[2,49],101:[2,49],103:[2,49],104:[2,49],105:[2,49],109:[2,49],117:[2,49],125:[2,49],127:[2,49],128:[2,49],131:[2,49],132:[2,49],133:[2,49],134:[2,49],135:[2,49],136:[2,49]},{6:[2,58],25:[2,58],26:[2,58],49:[2,58],54:[2,58]},{6:[2,53],25:[2,53],26:[2,53],53:309,54:[1,202]},{1:[2,200],6:[2,200],25:[2,200],26:[2,200],49:[2,200],54:[2,200],57:[2,200],72:[2,200],77:[2,200],85:[2,200],90:[2,200],92:[2,200],101:[2,200],103:[2,200],104:[2,200],105:[2,200],109:[2,200],117:[2,200],125:[2,200],127:[2,200],128:[2,200],131:[2,200],132:[2,200],133:[2,200],134:[2,200],135:[2,200],136:[2,200]},{1:[2,179],6:[2,179],25:[2,179],26:[2,179],49:[2,179],54:[2,179],57:[2,179],72:[2,179],77:[2,179],85:[2,179],90:[2,179],92:[2,179],101:[2,179],103:[2,179],104:[2,179],105:[2,179],109:[2,179],117:[2,179],120:[2,179],125:[2,179],127:[2,179],128:[2,179],131:[2,179],132:[2,179],133:[2,179],134:[2,179],135:[2,179],136:[2,179]},{1:[2,135],6:[2,135],25:[2,135],26:[2,135],49:[2,135],54:[2,135],57:[2,135],72:[2,135],77:[2,135],85:[2,135],90:[2,135],92:[2,135],101:[2,135],103:[2,135],104:[2,135],105:[2,135],109:[2,135],117:[2,135],125:[2,135],127:[2,135],128:[2,135],131:[2,135],132:[2,135],133:[2,135],134:[2,135],135:[2,135],136:[2,135]},{1:[2,136],6:[2,136],25:[2,136],26:[2,136],49:[2,136],54:[2,136],57:[2,136],72:[2,136],77:[2,136],85:[2,136],90:[2,136],92:[2,136],97:[2,136],101:[2,136],103:[2,136],104:[2,136],105:[2,136],109:[2,136],117:[2,136],125:[2,136],127:[2,136],128:[2,136],131:[2,136],132:[2,136],133:[2,136],134:[2,136],135:[2,136],136:[2,136]},{1:[2,170],6:[2,170],25:[2,170],26:[2,170],49:[2,170],54:[2,170],57:[2,170],72:[2,170],77:[2,170],85:[2,170],90:[2,170],92:[2,170],101:[2,170],103:[2,170],104:[2,170],105:[2,170],109:[2,170],117:[2,170],125:[2,170],127:[2,170],128:[2,170],131:[2,170],132:[2,170],133:[2,170],134:[2,170],135:[2,170],136:[2,170]},{5:310,25:[1,5]},{26:[1,311]},{6:[1,312],26:[2,176],120:[2,176],122:[2,176]},{8:313,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,102],6:[2,102],25:[2,102],26:[2,102],49:[2,102],54:[2,102],57:[2,102],72:[2,102],77:[2,102],85:[2,102],90:[2,102],92:[2,102],101:[2,102],103:[2,102],104:[2,102],105:[2,102],109:[2,102],117:[2,102],125:[2,102],127:[2,102],128:[2,102],131:[2,102],132:[2,102],133:[2,102],134:[2,102],135:[2,102],136:[2,102]},{1:[2,139],6:[2,139],25:[2,139],26:[2,139],49:[2,139],54:[2,139],57:[2,139],66:[2,139],67:[2,139],68:[2,139],70:[2,139],72:[2,139],73:[2,139],77:[2,139],83:[2,139],84:[2,139],85:[2,139],90:[2,139],92:[2,139],101:[2,139],103:[2,139],104:[2,139],105:[2,139],109:[2,139],117:[2,139],125:[2,139],127:[2,139],128:[2,139],131:[2,139],132:[2,139],133:[2,139],134:[2,139],135:[2,139],136:[2,139]},{1:[2,118],6:[2,118],25:[2,118],26:[2,118],49:[2,118],54:[2,118],57:[2,118],66:[2,118],67:[2,118],68:[2,118],70:[2,118],72:[2,118],73:[2,118],77:[2,118],83:[2,118],84:[2,118],85:[2,118],90:[2,118],92:[2,118],101:[2,118],103:[2,118],104:[2,118],105:[2,118],109:[2,118],117:[2,118],125:[2,118],127:[2,118],128:[2,118],131:[2,118],132:[2,118],133:[2,118],134:[2,118],135:[2,118],136:[2,118]},{6:[2,125],25:[2,125],26:[2,125],54:[2,125],85:[2,125],90:[2,125]},{6:[2,53],25:[2,53],26:[2,53],53:314,54:[1,226]},{6:[2,126],25:[2,126],26:[2,126],54:[2,126],85:[2,126],90:[2,126]},{1:[2,165],6:[2,165],25:[2,165],26:[2,165],49:[2,165],54:[2,165],57:[2,165],72:[2,165],77:[2,165],85:[2,165],90:[2,165],92:[2,165],101:[2,165],102:87,103:[2,165],104:[2,165],105:[2,165],108:88,109:[2,165],110:69,117:[1,315],125:[2,165],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,167],6:[2,167],25:[2,167],26:[2,167],49:[2,167],54:[2,167],57:[2,167],72:[2,167],77:[2,167],85:[2,167],90:[2,167],92:[2,167],101:[2,167],102:87,103:[2,167],104:[1,316],105:[2,167],108:88,109:[2,167],110:69,117:[2,167],125:[2,167],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,166],6:[2,166],25:[2,166],26:[2,166],49:[2,166],54:[2,166],57:[2,166],72:[2,166],77:[2,166],85:[2,166],90:[2,166],92:[2,166],101:[2,166],102:87,103:[2,166],104:[2,166],105:[2,166],108:88,109:[2,166],110:69,117:[2,166],125:[2,166],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[2,93],25:[2,93],26:[2,93],54:[2,93],77:[2,93]},{6:[2,53],25:[2,53],26:[2,53],53:317,54:[1,236]},{26:[1,318],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,247],25:[1,248],26:[1,319]},{26:[1,320]},{1:[2,173],6:[2,173],25:[2,173],26:[2,173],49:[2,173],54:[2,173],57:[2,173],72:[2,173],77:[2,173],85:[2,173],90:[2,173],92:[2,173],101:[2,173],103:[2,173],104:[2,173],105:[2,173],109:[2,173],117:[2,173],125:[2,173],127:[2,173],128:[2,173],131:[2,173],132:[2,173],133:[2,173],134:[2,173],135:[2,173],136:[2,173]},{26:[2,177],120:[2,177],122:[2,177]},{25:[2,131],54:[2,131],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,266],25:[1,267],26:[1,321]},{8:322,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:323,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[1,277],25:[1,278],26:[1,324]},{6:[2,41],25:[2,41],26:[2,41],54:[2,41],77:[2,41]},{6:[2,59],25:[2,59],26:[2,59],49:[2,59],54:[2,59]},{1:[2,171],6:[2,171],25:[2,171],26:[2,171],49:[2,171],54:[2,171],57:[2,171],72:[2,171],77:[2,171],85:[2,171],90:[2,171],92:[2,171],101:[2,171],103:[2,171],104:[2,171],105:[2,171],109:[2,171],117:[2,171],125:[2,171],127:[2,171],128:[2,171],131:[2,171],132:[2,171],133:[2,171],134:[2,171],135:[2,171],136:[2,171]},{6:[2,127],25:[2,127],26:[2,127],54:[2,127],85:[2,127],90:[2,127]},{1:[2,168],6:[2,168],25:[2,168],26:[2,168],49:[2,168],54:[2,168],57:[2,168],72:[2,168],77:[2,168],85:[2,168],90:[2,168],92:[2,168],101:[2,168],102:87,103:[2,168],104:[2,168],105:[2,168],108:88,109:[2,168],110:69,117:[2,168],125:[2,168],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,169],6:[2,169],25:[2,169],26:[2,169],49:[2,169],54:[2,169],57:[2,169],72:[2,169],77:[2,169],85:[2,169],90:[2,169],92:[2,169],101:[2,169],102:87,103:[2,169],104:[2,169],105:[2,169],108:88,109:[2,169],110:69,117:[2,169],125:[2,169],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[2,94],25:[2,94],26:[2,94],54:[2,94],77:[2,94]}],defaultActions:{60:[2,51],61:[2,52],75:[2,3],94:[2,108],189:[2,88]},parseError:function(a,b){throw new Error(a)},parse:function(a){function o(){var a;a=b.lexer.lex()||1,typeof a!="number"&&(a=b.symbols_[a]||a);return a}function n(a){c.length=c.length-2*a,d.length=d.length-a,e.length=e.length-a}var b=this,c=[0],d=[null],e=[],f=this.table,g="",h=0,i=0,j=0,k=2,l=1;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,typeof this.lexer.yylloc=="undefined"&&(this.lexer.yylloc={});var m=this.lexer.yylloc;e.push(m),typeof this.yy.parseError=="function"&&(this.parseError=this.yy.parseError);var p,q,r,s,t,u,v={},w,x,y,z;for(;;){r=c[c.length-1],this.defaultActions[r]?s=this.defaultActions[r]:(p==null&&(p=o()),s=f[r]&&f[r][p]);_handle_error:if(typeof s=="undefined"||!s.length||!s[0]){if(!j){z=[];for(w in f[r])this.terminals_[w]&&w>2&&z.push("'"+this.terminals_[w]+"'");var A="";this.lexer.showPosition?A="Parse error on line "+(h+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+z.join(", ")+", got '"+this.terminals_[p]+"'":A="Parse error on line "+(h+1)+": Unexpected "+(p==1?"end of input":"'"+(this.terminals_[p]||p)+"'"),this.parseError(A,{text:this.lexer.match,token:this.terminals_[p]||p,line:this.lexer.yylineno,loc:m,expected:z})}if(j==3){if(p==l)throw new Error(A||"Parsing halted.");i=this.lexer.yyleng,g=this.lexer.yytext,h=this.lexer.yylineno,m=this.lexer.yylloc,p=o()}for(;;){if(k.toString()in f[r])break;if(r==0)throw new Error(A||"Parsing halted.");n(1),r=c[c.length-1]}q=p,p=k,r=c[c.length-1],s=f[r]&&f[r][k],j=3}if(s[0]instanceof Array&&s.length>1)throw new Error("Parse Error: multiple actions possible at state: "+r+", token: "+p);switch(s[0]){case 1:c.push(p),d.push(this.lexer.yytext),e.push(this.lexer.yylloc),c.push(s[1]),p=null,q?(p=q,q=null):(i=this.lexer.yyleng,g=this.lexer.yytext,h=this.lexer.yylineno,m=this.lexer.yylloc,j>0&&j--);break;case 2:x=this.productions_[s[1]][1],v.$=d[d.length-x],v._$={first_line:e[e.length-(x||1)].first_line,last_line:e[e.length-1].last_line,first_column:e[e.length-(x||1)].first_column,last_column:e[e.length-1].last_column},u=this.performAction.call(v,g,i,h,this.yy,s[1],d,e);if(typeof u!="undefined")return u;x&&(c=c.slice(0,-1*x*2),d=d.slice(0,-1*x),e=e.slice(0,-1*x)),c.push(this.productions_[s[1]][0]),d.push(v.$),e.push(v._$),y=f[c[c.length-2]][c[c.length-1]],c.push(y);break;case 3:return!0}}return!0}};undefined;return a}();typeof require!="undefined"&&typeof a!="undefined"&&(a.parser=b,a.parse=function(){return b.parse.apply(b,arguments)},a.main=function(b){if(!b[1])throw new Error("Usage: "+b[0]+" FILE");if(typeof process!="undefined")var c=require("fs").readFileSync(require("path").join(process.cwd(),b[1]),"utf8");else var d=require("file").path(require("file").cwd()),c=d.join(b[1]).read({charset:"utf-8"});return a.parser.parse(c)},typeof module!="undefined"&&require.main===module&&a.main(typeof process!="undefined"?process.argv.slice(1):require("system").args))},require["./scope"]=new function(){var a=this;(function(){var b,c,d,e;e=require("./helpers"),c=e.extend,d=e.last,a.Scope=b=function(){function a(b,c,d){this.parent=b,this.expressions=c,this.method=d,this.variables=[{name:"arguments",type:"arguments"}],this.positions={},this.parent||(a.root=this)}a.root=null,a.prototype.add=function(a,b,c){if(this.shared&&!c)return this.parent.add(a,b,c);return Object.prototype.hasOwnProperty.call(this.positions,a)?this.variables[this.positions[a]].type=b:this.positions[a]=this.variables.push({name:a,type:b})-1},a.prototype.namedMethod=function(){if(this.method.name||!this.parent)return this.method;return this.parent.namedMethod()},a.prototype.find=function(a){if(this.check(a))return!0;this.add(a,"var");return!1},a.prototype.parameter=function(a){if(!this.shared||!this.parent.check(a,!0))return this.add(a,"param")},a.prototype.check=function(a){var b;return!!(this.type(a)||((b=this.parent)!=null?b.check(a):void 0))},a.prototype.temporary=function(a,b){return a.length>1?"_"+a+(b>1?b-1:""):"_"+(b+parseInt(a,36)).toString(36).replace(/\d/g,"a")},a.prototype.type=function(a){var b,c,d,e;e=this.variables;for(c=0,d=e.length;c1&&a.level>=w?"("+c+")":c},b.prototype.compileRoot=function(a){var b,c,d,e,f,g;a.indent=a.bare?"":R,a.scope=new N(null,this,null),a.level=z,this.spaced=!0,e="",a.bare||(f=function(){var a,b,e,f;e=this.expressions,f=[];for(d=a=0,b=e.length;a=u?"(void 0)":"void 0"};return b}(e),a.Null=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}bl(b,a),b.prototype.isAssignable=D,b.prototype.isComplex=D,b.prototype.compileNode=function(){return"null"};return b}(e),a.Bool=function(a){function b(a){this.val=a}bl(b,a),b.prototype.isAssignable=D,b.prototype.isComplex=D,b.prototype.compileNode=function(){return this.val};return b}(e),a.Return=K=function(a){function b(a){a&&!a.unwrap().isUndefined&&(this.expression=a)}bl(b,a),b.prototype.children=["expression"],b.prototype.isStatement=Y,b.prototype.makeReturn=S,b.prototype.jumps=S,b.prototype.compile=function(a,c){var d,e;d=(e=this.expression)!=null?e.makeReturn():void 0;return!d||d instanceof b?b.__super__.compile.call(this,a,c):d.compile(a,c)},b.prototype.compileNode=function(a){return this.tab+("return"+[this.expression?" "+this.expression.compile(a,y):void 0]+";")};return b}(e),a.Value=W=function(a){function b(a,c,d){if(!c&&a instanceof b)return a;this.base=a,this.properties=c||[],d&&(this[d]=!0);return this}bl(b,a),b.prototype.children=["base","properties"],b.prototype.add=function(a){this.properties=this.properties.concat(a);return this},b.prototype.hasProperties=function(){return!!this.properties.length},b.prototype.isArray=function(){return!this.properties.length&&this.base instanceof c},b.prototype.isComplex=function(){return this.hasProperties()||this.base.isComplex()},b.prototype.isAssignable=function(){return this.hasProperties()||this.base.isAssignable()},b.prototype.isSimpleNumber=function(){return this.base instanceof A&&L.test(this.base.value)},b.prototype.isString=function(){return this.base instanceof A&&q.test(this.base.value)},b.prototype.isAtomic=function(){var a,b,c,d;d=this.properties.concat(this.base);for(b=0,c=d.length;b"+this.equals],i=n[0],e=n[1],c=this.stepNum?+this.stepNum>0?""+i+" "+this.toVar:""+e+" "+this.toVar:h?(o=[+this.fromNum,+this.toNum],d=o[0],l=o[1],o,d<=l?""+i+" "+l:""+e+" "+l):(b=""+this.fromVar+" <= "+this.toVar,""+b+" ? "+i+" "+this.toVar+" : "+e+" "+this.toVar),k=this.stepVar?""+f+" += "+this.stepVar:h?j?d<=l?"++"+f:"--"+f:d<=l?""+f+"++":""+f+"--":j?""+b+" ? ++"+f+" : --"+f:""+b+" ? "+f+"++ : "+f+"--",j&&(m=""+g+" = "+m),j&&(k=""+g+" = "+k);return""+m+"; "+c+"; "+k},b.prototype.compileArray=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;if(this.fromNum&&this.toNum&&Math.abs(this.fromNum-this.toNum)<=20){j=function(){p=[];for(var a=n=+this.fromNum,b=+this.toNum;n<=b?a<=b:a>=b;n<=b?a++:a--)p.push(a);return p}.apply(this),this.exclusive&&j.pop();return"["+j.join(", ")+"]"}g=this.tab+R,f=a.scope.freeVariable("i"),k=a.scope.freeVariable("results"),i="\n"+g+k+" = [];",this.fromNum&&this.toNum?(a.index=f,c=this.compileNode(a)):(l=""+f+" = "+this.fromC+(this.toC!==this.toVar?", "+this.toC:""),d=""+this.fromVar+" <= "+this.toVar,c="var "+l+"; "+d+" ? "+f+" <"+this.equals+" "+this.toVar+" : "+f+" >"+this.equals+" "+this.toVar+"; "+d+" ? "+f+"++ : "+f+"--"),h="{ "+k+".push("+f+"); }\n"+g+"return "+k+";\n"+a.indent,e=function(a){return a!=null?a.contains(function(a){return a instanceof A&&a.value==="arguments"&&!a.asKey}):void 0};if(e(this.from)||e(this.to))b=", arguments";return"(function() {"+i+"\n"+g+"for ("+c+")"+h+"}).apply(this"+(b!=null?b:"")+")"};return b}(e),a.Slice=O=function(a){function b(a){this.range=a,b.__super__.constructor.call(this)}bl(b,a),b.prototype.children=["range"],b.prototype.compileNode=function(a){var b,c,d,e,f,g;g=this.range,e=g.to,c=g.from,d=c&&c.compile(a,y)||"0",b=e&&e.compile(a,y),e&&(!!this.range.exclusive||+b!==-1)&&(f=", "+(this.range.exclusive?b:L.test(b)?""+(+b+1):(b=e.compile(a,u),""+b+" + 1 || 9e9")));return".slice("+d+(f||"")+")"};return b}(e),a.Obj=E=function(a){function b(a,b){this.generated=b!=null?b:!1,this.objects=this.properties=a||[]}bl(b,a),b.prototype.children=["properties"],b.prototype.compileNode=function(a){var b,c,e,f,g,h,i,j,l,m,n,o,p,q,r,s;n=this.properties,m=[],s=this.properties;for(o=0,q=s.length;o=0)throw SyntaxError('multiple object literal properties named "'+l+'"');m.push(l)}}if(!n.length)return this.front?"({})":"{}";if(this.generated)for(p=0,r=n.length;p=0?"[\n"+a.indent+b+"\n"+this.tab+"]":"["+b+"]"},b.prototype.assigns=function(a){var b,c,d,e;e=this.objects;for(c=0,d=e.length;c=0)throw SyntaxError("variable name may not be "+a);return a&&(a=o.test(a)&&a)},c.prototype.setContext=function(a){return this.body.traverseChildren(!1,function(b){if(b.classBody)return!1;if(b instanceof A&&b.value==="this")return b.value=a;if(b instanceof j){b.klass=a;if(b.bound)return b.context=a}})},c.prototype.addBoundFunctions=function(a){var c,d,e,f,g,h;if(this.boundFuncs.length){g=this.boundFuncs,h=[];for(e=0,f=g.length;e=0);if(e&&this.context!=="object")throw SyntaxError('variable name may not be "'+f+'"')}bl(c,a),c.prototype.children=["variable","value"],c.prototype.isStatement=function(a){return(a!=null?a.level:void 0)===z&&this.context!=null&&bm.call(this.context,"?")>=0},c.prototype.assigns=function(a){return this[this.context==="object"?"value":"variable"].assigns(a)},c.prototype.unfoldSoak=function(a){return bg(a,this,"variable")},c.prototype.compileNode=function(a){var b,c,d,e,f,g,h,i,k;if(b=this.variable instanceof W){if(this.variable.isArray()||this.variable.isObject())return this.compilePatternMatch(a);if(this.variable.isSplice())return this.compileSplice(a);if((g=this.context)==="||="||g==="&&="||g==="?=")return this.compileConditional(a)}d=this.variable.compile(a,w);if(!this.context){if(!(f=this.variable.unwrapAll()).isAssignable())throw SyntaxError('"'+this.variable.compile(a)+'" cannot be assigned.');if(typeof f.hasProperties=="function"?!f.hasProperties():!void 0)this.param?a.scope.add(d,"var"):a.scope.find(d)}this.value instanceof j&&(c=B.exec(d))&&(c[1]&&(this.value.klass=c[1]),this.value.name=(h=(i=(k=c[2])!=null?k:c[3])!=null?i:c[4])!=null?h:c[5]),e=this.value.compile(a,w);if(this.context==="object")return""+d+": "+e;e=d+(" "+(this.context||"=")+" ")+e;return a.level<=w?e:"("+e+")"},c.prototype.compilePatternMatch=function(a){var d,e,f,g,h,i,j,k,l,m,n,p,q,r,s,u,v,y,B,C,D,E,F,G,J,K,L;s=a.level===z,v=this.value,m=this.variable.base.objects;if(!(n=m.length)){f=v.compile(a);return a.level>=x?"("+f+")":f}i=this.variable.isObject();if(s&&n===1&&!((l=m[0])instanceof P)){l instanceof c?(D=l,E=D.variable,h=E.base,l=D.value):l.base instanceof H?(F=(new W(l.unwrapAll())).cacheReference(a),l=F[0],h=F[1]):h=i?l["this"]?l.properties[0].name:l:new A(0),d=o.test(h.unwrap().value||0),v=new W(v),v.properties.push(new(d?b:t)(h));if(G=l.unwrap().value,bm.call(I,G)>=0)throw new SyntaxError("assignment to a reserved word: "+l.compile(a)+" = "+v.compile(a));return(new c(l,v,null,{param:this.param})).compile(a,z)}y=v.compile(a,w),e=[],r=!1;if(!o.test(y)||this.variable.assigns(y))e.push(""+(p=a.scope.freeVariable("ref"))+" = "+y),y=p;for(g=B=0,C=m.length;B=0)throw new SyntaxError("assignment to a reserved word: "+l.compile(a)+" = "+u.compile(a));e.push((new c(l,u,null,{param:this.param,subpattern:!0})).compile(a,w))}!s&&!this.subpattern&&e.push(y),f=e.join(", ");return a.level=0&&(a.isExistentialEquals=!0);return(new F(this.context.slice(0,-1),b,new c(d,this.value,"="))).compile(a)},c.prototype.compileSplice=function(a){var b,c,d,e,f,g,h,i,j,k,l,m;k=this.variable.properties.pop().range,d=k.from,h=k.to,c=k.exclusive,g=this.variable.compile(a),l=(d!=null?d.cache(a,x):void 0)||["0","0"],e=l[0],f=l[1],h?(d!=null?d.isSimpleNumber():void 0)&&h.isSimpleNumber()?(h=+h.compile(a)- +f,c||(h+=1)):(h=h.compile(a,u)+" - "+f,c||(h+=" + 1")):h="9e9",m=this.value.cache(a,w),i=m[0],j=m[1],b="[].splice.apply("+g+", ["+e+", "+h+"].concat("+i+")), "+j;return a.level>z?"("+b+")":b};return c}(e),a.Code=j=function(a){function b(a,b,c){this.params=a||[],this.body=b||new f,this.bound=c==="boundfunc",this.bound&&(this.context="_this")}bl(b,a),b.prototype.children=["params","body"],b.prototype.isStatement=function(){return!!this.ctor},b.prototype.jumps=D,b.prototype.compileNode=function(a){var b,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,v,w,x,y,z,B,C,D,E,G,H,I,J,K,L,M,O;a.scope=new N(a.scope,this.body,this),a.scope.shared=$(a,"sharedScope"),a.indent+=R,delete a.bare,delete a.isExistentialEquals,l=[],e=[],H=this.paramNames();for(s=0,x=H.length;s=u?"("+b+")":b},b.prototype.paramNames=function(){var a,b,c,d,e;a=[],e=this.params;for(c=0,d=e.length;c=0)throw SyntaxError('parameter name "'+a+'" is not allowed')}bl(b,a),b.prototype.children=["name","value"],b.prototype.compile=function(a){return this.name.compile(a,w)},b.prototype.asReference=function(a){var b;if(this.reference)return this.reference;b=this.name,b["this"]?(b=b.properties[0].name,b.value.reserved&&(b=new A(a.scope.freeVariable(b.value)))):b.isComplex()&&(b=new A(a.scope.freeVariable("arg"))),b=new W(b),this.splat&&(b=new P(b));return this.reference=b},b.prototype.isComplex=function(){return this.name.isComplex()},b.prototype.names=function(a){var b,c,e,f,g,h;a==null&&(a=this.name),b=function(a){var b;b=a.properties[0].name.value;return b.reserved?[]:[b]};if(a instanceof A)return[a.value];if(a instanceof W)return b(a);c=[],h=a.objects;for(f=0,g=h.length;f=c.length)return"";if(c.length===1){g=c[0].compile(a,w);if(d)return g;return""+bh("slice")+".call("+g+")"}e=c.slice(i);for(h=k=0,l=e.length;k1?b.expressions.unshift(new r((new H(this.guard)).invert(),new A("continue"))):this.guard&&(b=f.wrap([new r(this.guard,b)]))),b="\n"+b.compile(a,z)+"\n"+this.tab),c=e+this.tab+("while ("+this.condition.compile(a,y)+") {"+b+"}"),this.returns&&(c+="\n"+this.tab+"return "+d+";");return c};return b}(e),a.Op=F=function(a){function e(a,c,d,e){if(a==="in")return new s(c,d);if(a==="do")return this.generateDo(c);if(a==="new"){if(c instanceof g&&!c["do"]&&!c.isNew)return c.newInstance();if(c instanceof j&&c.bound||c["do"])c=new H(c)}this.operator=b[a]||a,this.first=c,this.second=d,this.flip=!!e;return this}var b,c;bl(e,a),b={"==":"===","!=":"!==",of:"in"},c={"!==":"===","===":"!=="},e.prototype.children=["first","second"],e.prototype.isSimpleNumber=D,e.prototype.isUnary=function(){return!this.second},e.prototype.isComplex=function(){var a;return!this.isUnary()||(a=this.operator)!=="+"&&a!=="-"||this.first.isComplex()},e.prototype.isChainable=function(){var a;return(a=this.operator)==="<"||a===">"||a===">="||a==="<="||a==="==="||a==="!=="},e.prototype.invert=function(){var a,b,d,f,g;if(this.isChainable()&&this.first.isChainable()){a=!0,b=this;while(b&&b.operator)a&&(a=b.operator in c),b=b.first;if(!a)return(new H(this)).invert();b=this;while(b&&b.operator)b.invert=!b.invert,b.operator=c[b.operator],b=b.first;return this}if(f=c[this.operator]){this.operator=f,this.first.unwrap()instanceof e&&this.first.invert();return this}return this.second?(new H(this)).invert():this.operator==="!"&&(d=this.first.unwrap())instanceof e&&((g=d.operator)==="!"||g==="in"||g==="instanceof")?d:new e("!",this)},e.prototype.unfoldSoak=function(a){var b;return((b=this.operator)==="++"||b==="--"||b==="delete")&&bg(a,this,"first")},e.prototype.generateDo=function(a){var b,c,e,f,h,i,k,l;f=[],c=a instanceof d&&(h=a.value.unwrap())instanceof j?h:a,l=c.params||[];for(i=0,k=l.length;i=0))throw SyntaxError("prefix increment/decrement may not have eval or arguments operand");if(this.isUnary())return this.compileUnary(a);if(c)return this.compileChain(a);if(this.operator==="?")return this.compileExistence(a);b=this.first.compile(a,x)+" "+this.operator+" "+this.second.compile(a,x);return a.level<=x?b:"("+b+")"},e.prototype.compileChain=function(a){var b,c,d,e;e=this.first.second.cache(a),this.first.second=e[0],d=e[1],c=this.first.compile(a,x),b=""+c+" "+(this.invert?"&&":"||")+" "+d.compile(a)+" "+this.operator+" "+this.second.compile(a,x);return"("+b+")"},e.prototype.compileExistence=function(a){var b,c;this.first.isComplex()?(c=new A(a.scope.freeVariable("ref")),b=new H(new d(c,this.first))):(b=this.first,c=b);return(new r(new l(b),c,{type:"if"})).addElse(this.second).compile(a)},e.prototype.compileUnary=function(a){var b,c,d;if(a.level>=u)return(new H(this)).compile(a);c=[b=this.operator],d=b==="+"||b==="-",(b==="new"||b==="typeof"||b==="delete"||d&&this.first instanceof e&&this.first.operator===b)&&c.push(" ");if(d&&this.first instanceof e||b==="new"&&this.first.isStatement(a))this.first=new H(this.first);c.push(this.first.compile(a,x)),this.flip&&c.reverse();return c.join("")},e.prototype.toString=function(a){return e.__super__.toString.call(this,a,this.constructor.name+" "+this.operator)};return e}(e),a.In=s=function(a){function b(a,b){this.object=a,this.array=b}bl(b,a),b.prototype.children=["object","array"],b.prototype.invert=C,b.prototype.compileNode=function(a){var b,c,d,e,f;if(this.array instanceof W&&this.array.isArray()){f=this.array.base.objects;for(d=0,e=f.length;d= 0");if(d===c)return b;b=d+", "+b;return a.level=0)throw SyntaxError('catch variable may not be "'+this.error.value+'"');a.scope.check(this.error.value)||a.scope.add(this.error.value,"param");return" catch"+d+"{\n"+this.recovery.compile(a,z)+"\n"+this.tab+"}"}if(!this.ensure&&!this.recovery)return" catch (_error) {}"}.call(this),c=this.ensure?" finally {\n"+this.ensure.compile(a,z)+"\n"+this.tab+"}":"";return""+this.tab+"try {\n"+e+"\n"+this.tab+"}"+(b||"")+c};return b}(e),a.Throw=T=function(a){function b(a){this.expression=a}bl(b,a),b.prototype.children=["expression"],b.prototype.isStatement=Y,b.prototype.jumps=D,b.prototype.makeReturn=S,b.prototype.compileNode=function(a){return this.tab+("throw "+this.expression.compile(a)+";")};return b}(e),a.Existence=l=function(a){function b(a){this.expression=a}bl(b,a),b.prototype.children=["expression"],b.prototype.invert=C,b.prototype.compileNode=function(a){var b,c,d,e;this.expression.front=this.front,d=this.expression.compile(a,x),o.test(d)&&!a.scope.check(d)?(e=this.negated?["===","||"]:["!==","&&"],b=e[0],c=e[1],d="typeof "+d+" "+b+' "undefined" '+c+" "+d+" "+b+" null"):d=""+d+" "+(this.negated?"==":"!=")+" null";return a.level<=v?d:"("+d+")"};return b}(e),a.Parens=H=function(a){function b(a){this.body=a}bl(b,a),b.prototype.children=["body"],b.prototype.unwrap=function(){return this.body},b.prototype.isComplex=function(){return this.body.isComplex()},b.prototype.compileNode=function(a){var b,c,d;d=this.body.unwrap();if(d instanceof W&&d.isAtomic()){d.front=this.front;return d.compile(a)}c=d.compile(a,y),b=a.level1?b.expressions.unshift(new r((new H(this.guard)).invert(),new A("continue"))):this.guard&&(b=f.wrap([new r(this.guard,b)]))),this.pattern&&b.expressions.unshift(new d(this.name,new A(""+F+"["+l+"]"))),c+=this.pluckDirectCall(a,b),s&&(G="\n"+i+s+";"),this.object&&(e=""+l+" in "+F,this.own&&(h="\n"+i+"if (!"+bh("hasProp")+".call("+F+", "+l+")) continue;")),b=b.compile(bd(a,{indent:i}),z),b&&(b="\n"+b+"\n");return""+c+(u||"")+this.tab+"for ("+e+") {"+h+G+b+this.tab+"}"+(v||"")},b.prototype.pluckDirectCall=function(a,b){var c,e,f,h,i,k,l,m,n,o,p,q,r,s,t;e="",o=b.expressions;for(i=m=0,n=o.length;m=v?"("+d+")":d},b.prototype.unfoldSoak=function(){return this.soak&&this};return b}(e),i={wrap:function(a,c,d){var e,h,i,k,l;if(a.jumps())return a;i=new j([],f.wrap([a])),e=[];if((k=a.contains(this.literalArgs))||a.contains(this.literalThis))l=new A(k?"apply":"call"),e=[new A("this")],k&&e.push(new A("arguments")),i=new W(i,[new b(l)]);i.noReturn=d,h=new g(i,e);return c?f.wrap([h]):h},literalArgs:function(a){return a instanceof A&&a.value==="arguments"&&!a.asKey},literalThis:function(a){return a instanceof A&&a.value==="this"&&!a.asKey||a instanceof j&&a.bound||a instanceof g&&a.isSuper}},bg=function(a,b,c){var d;if(!!(d=b[c].unfoldSoak(a))){b[c]=d.body,d.body=new W(b);return d}},V={"extends":function(){return"function(child, parent) { for (var key in parent) { if ("+bh("hasProp")+".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }"},bind:function(){return"function(fn, me){ return function(){ return fn.apply(me, arguments); }; }"},indexOf:function(){return"[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"},hasProp:function(){return"{}.hasOwnProperty"},slice:function(){return"[].slice"}},z=1,y=2,w=3,v=4,x=5,u=6,R=" ",p="[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*",o=RegExp("^"+p+"$"),L=/^[+-]?\d+$/,B=RegExp("^(?:("+p+")\\.prototype(?:\\.("+p+")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|("+p+")$"),q=/^['"]/,bh=function(a){var b;b="__"+a,N.root.assign(b,V[a]());return b},be=function(a,b){a=a.replace(/\n/g,"$&"+b);return a.replace(/\s+$/,"")}}).call(this)},require["./coffee-script"]=new function(){var a=this;(function(){var b,c,d,e,f,g,h,i,j,k=({}).hasOwnProperty;e=require("fs"),h=require("path"),j=require("./lexer"),b=j.Lexer,c=j.RESERVED,g=require("./parser").parser,i=require("vm"),require.extensions?require.extensions[".coffee"]=function(a,b){var c;c=d(e.readFileSync(b,"utf8"),{filename:b});return a._compile(c,b)}:require.registerExtension&&require.registerExtension(".coffee",function(a){return d(a)}),a.VERSION="1.3.3",a.RESERVED=c,a.helpers=require("./helpers"),a.compile=d=function(b,c){var d,e,h;c==null&&(c={}),h=a.helpers.merge;try{e=g.parse(f.tokenize(b)).compile(c);if(!c.header)return e}catch(i){c.filename&&(i.message="In "+c.filename+", "+i.message);throw i}d="Generated by CoffeeScript "+this.VERSION;return"// "+d+"\n"+e},a.tokens=function(a,b){return f.tokenize(a,b)},a.nodes=function(a,b){return typeof a=="string"?g.parse(f.tokenize(a,b)):g.parse(a)},a.run=function(a,b){var c;b==null&&(b={}),c=require.main,c.filename=process.argv[1]=b.filename?e.realpathSync(b.filename):".",c.moduleCache&&(c.moduleCache={}),c.paths=require("module")._nodeModulePaths(h.dirname(e.realpathSync(b.filename)));return h.extname(c.filename)!==".coffee"||require.extensions?c._compile(d(a,b),c.filename):c._compile(a,c.filename)},a.eval=function(a,b){var c,e,f,g,j,l,m,n,o,p,q,r,s,t;b==null&&(b={});if(!!(a=a.trim())){e=i.Script;if(e){if(b.sandbox!=null){if(b.sandbox instanceof e.createContext().constructor)m=b.sandbox;else{m=e.createContext(),r=b.sandbox;for(g in r){if(!k.call(r,g))continue;n=r[g],m[g]=n}}m.global=m.root=m.GLOBAL=m}else m=global;m.__filename=b.filename||"eval",m.__dirname=h.dirname(m.__filename);if(m===global&&!m.module&&!m.require){c=require("module"),m.module=q=new c(b.modulename||"eval"),m.require=t=function(a){return c._load(a,q,!0)},q.filename=m.__filename,s=Object.getOwnPropertyNames(require);for(o=0,p=s.length;o=0)s+=1;else if(f=o[0],b.call(r,f)>=0)s-=1;e+=1}return e-1},e.prototype.removeLeadingNewlines=function(){var e,t,n,r,i;i=this.tokens;for(e=n=0,r=i.length;n=0)?(r.splice(t,1),0):1})},e.prototype.closeOpenCalls=function(){var e,t;return t=function(e,t){var n;return(n=e[0])===")"||n==="CALL_END"||e[0]==="OUTDENT"&&this.tag(t-1)===")"},e=function(e,t){return this.tokens[e[0]==="OUTDENT"?t-1:t][0]="CALL_END"},this.scanTokens(function(n,r){return n[0]==="CALL_START"&&this.detectEnd(r+1,t,e),1})},e.prototype.closeOpenIndexes=function(){var e,t;return t=function(e,t){var n;return(n=e[0])==="]"||n==="INDEX_END"},e=function(e,t){return e[0]="INDEX_END"},this.scanTokens(function(n,r){return n[0]==="INDEX_START"&&this.detectEnd(r+1,t,e),1})},e.prototype.addImplicitBraces=function(){var e,t,n,s,o,a,f,l;return s=[],o=null,l=null,n=!0,a=0,f=0,t=function(e,t){var r,i,s,o,a,h;return a=this.tokens.slice(t+1,+(t+3)+1||9e9),r=a[0],o=a[1],s=a[2],"HERECOMMENT"===(r!=null?r[0]:void 0)?!1:(i=e[0],b.call(c,i)>=0&&(n=!1),(i==="TERMINATOR"||i==="OUTDENT"||b.call(u,i)>=0&&n&&t-f!==1)&&(!l&&this.tag(t-1)!==","||(o!=null?o[0]:void 0)!==":"&&((r!=null?r[0]:void 0)!=="@"||(s!=null?s[0]:void 0)!==":"))||i===","&&r&&(h=r[0])!=="IDENTIFIER"&&h!=="NUMBER"&&h!=="STRING"&&h!=="@"&&h!=="TERMINATOR"&&h!=="OUTDENT")},e=function(e,t){var n;return n=this.generate("}","}",e[2]),this.tokens.splice(t,0,n)},this.scanTokens(function(u,a,h){var p,d,v,m,g,y,w,E;if(w=m=u[0],b.call(i,w)>=0)return s.push([m==="INDENT"&&this.tag(a-1)==="{"?"{":m,a]),1;if(b.call(r,m)>=0)return o=s.pop(),1;if(m!==":"||(p=this.tag(a-2))!==":"&&((E=s[s.length-1])!=null?E[0]:void 0)==="{")return 1;n=!0,f=a+1,s.push(["{"]),d=p==="@"?a-2:a-1;while(this.tag(d-2)==="HERECOMMENT")d-=2;return v=this.tag(d-1),l=!v||b.call(c,v)>=0,y=new String("{"),y.generated=!0,g=this.generate("{",y,u[2]),h.splice(d,0,g),this.detectEnd(a+2,t,e),2})},e.prototype.addImplicitParentheses=function(){var e,t,n,r,i;return n=i=r=!1,t=function(e,t){var n,o,a,f;o=e[0];if(!i&&e.fromThen)return!0;if(o==="IF"||o==="ELSE"||o==="CATCH"||o==="->"||o==="=>"||o==="CLASS")i=!0;if(o==="IF"||o==="ELSE"||o==="SWITCH"||o==="TRY"||o==="=")r=!0;return o!=="."&&o!=="?."&&o!=="::"||this.tag(t-1)!=="OUTDENT"?!e.generated&&this.tag(t-1)!==","&&(b.call(u,o)>=0||o==="INDENT"&&!r)&&(o!=="INDENT"||(a=this.tag(t-2))!=="CLASS"&&a!=="EXTENDS"&&(f=this.tag(t-1),b.call(s,f)<0)&&(!(n=this.tokens[t+1])||!n.generated||n[0]!=="{")):!0},e=function(e,t){return this.tokens.splice(t,0,this.generate("CALL_END",")",e[2]))},this.scanTokens(function(s,u,l){var h,p,d,v,m,g,y,w;m=s[0];if(m==="CLASS"||m==="IF"||m==="FOR"||m==="WHILE")n=!0;return g=l.slice(u-1,+(u+1)+1||9e9),v=g[0],p=g[1],d=g[2],h=!n&&m==="INDENT"&&d&&d.generated&&d[0]==="{"&&v&&(y=v[0],b.call(a,y)>=0),i=!1,r=!1,b.call(c,m)>=0&&(n=!1),v&&!v.spaced&&m==="?"&&(s.call=!0),s.fromThen?1:h||(v!=null?v.spaced:void 0)&&(v.call||(w=v[0],b.call(a,w)>=0))&&(b.call(o,m)>=0||!s.spaced&&!s.newLine&&b.call(f,m)>=0)?(l.splice(u,0,this.generate("CALL_START","(",s[2])),this.detectEnd(u+1,t,e),v[0]==="?"&&(v[0]="FUNC_EXIST"),2):1})},e.prototype.addImplicitIndentation=function(){var e,t,n,r,i;return i=n=r=null,t=function(e,t){var n;return e[1]!==";"&&(n=e[0],b.call(h,n)>=0)&&(e[0]!=="ELSE"||i==="IF"||i==="THEN")},e=function(e,t){return this.tokens.splice(this.tag(t-1)===","?t-1:t,0,r)},this.scanTokens(function(s,o,u){var a,f,l;return a=s[0],a==="TERMINATOR"&&this.tag(o+1)==="THEN"?(u.splice(o,1),0):a==="ELSE"&&this.tag(o-1)!=="OUTDENT"?(u.splice.apply(u,[o,0].concat(w.call(this.indentation(s)))),2):a!=="CATCH"||(f=this.tag(o+2))!=="OUTDENT"&&f!=="TERMINATOR"&&f!=="FINALLY"?b.call(p,a)>=0&&this.tag(o+1)!=="INDENT"&&(a!=="ELSE"||this.tag(o+1)!=="IF")?(i=a,l=this.indentation(s,!0),n=l[0],r=l[1],i==="THEN"&&(n.fromThen=!0),u.splice(o+1,0,n),this.detectEnd(o+2,t,e),a==="THEN"&&u.splice(o,1),1):1:(u.splice.apply(u,[o+2,0].concat(w.call(this.indentation(s)))),4)})},e.prototype.tagPostfixConditionals=function(){var e,t,n;return n=null,t=function(e,t){var n;return(n=e[0])==="TERMINATOR"||n==="INDENT"},e=function(e,t){if(e[0]!=="INDENT"||e.generated&&!e.fromThen)return n[0]="POST_"+n[0]},this.scanTokens(function(r,i){return r[0]!=="IF"?1:(n=r,this.detectEnd(i+1,t,e),1)})},e.prototype.indentation=function(e,t){var n,r;return t==null&&(t=!1),n=["INDENT",2,e[2]],r=["OUTDENT",2,e[2]],t&&(n.generated=r.generated=!0),[n,r]},e.prototype.generate=function(e,t,n){var r;return r=[e,t,n],r.generated=!0,r},e.prototype.tag=function(e){var t;return(t=this.tokens[e])!=null?t[0]:void 0},e}(),t=[["(",")"],["[","]"],["{","}"],["INDENT","OUTDENT"],["CALL_START","CALL_END"],["PARAM_START","PARAM_END"],["INDEX_START","INDEX_END"]],e.INVERSES=l={},i=[],r=[];for(m=0,g=t.length;m","=>","[","(","{","--","++"],f=["+","-"],s=["->","=>","{","[",","],u=["POST_IF","FOR","WHILE","UNTIL","WHEN","BY","LOOP","TERMINATOR","AWAIT"],p=["ELSE","->","=>","TRY","FINALLY","THEN"],h=["TERMINATOR","CATCH","FINALLY","ELSE","OUTDENT","LEADING_WHEN"],c=["TERMINATOR","INDENT","OUTDENT"]}).call(this)},require["./lexer"]=new function(){var e=this;(function(){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x,T,N,C,k,L,A,O,M,_,D,P,H,B,j,F,I,q,R,U,z,W,X,V,$,J,K=[].indexOf||function(e){for(var t=0,n=this.length;t=0||K.call(o,n)>=0)&&(f=n.toUpperCase(),f==="WHEN"&&(c=this.tag(),K.call(E,c)>=0)?f="LEADING_WHEN":f==="FOR"?this.seenFor=!0:f==="UNLESS"?f="IF":K.call(q,f)>=0?f="UNARY":K.call(D,f)>=0&&(f!=="INSTANCEOF"&&this.seenFor?(f="FOR"+f,this.seenFor=!1):(f="RELATION",this.value()==="!"&&(this.tokens.pop(),n="!"+n)))),K.call(b,n)>=0&&(t?(f="IDENTIFIER",n=new String(n),n.reserved=!0):K.call(P,n)>=0&&this.error('reserved word "'+n+'"')),t||(K.call(i,n)>=0&&(n=s[n]),f=function(){switch(n){case"!":return"UNARY";case"==":case"!=":return"COMPARE";case"&&":case"||":return"LOGIC";case"true":case"false":return"BOOL";case"break":case"continue":return"STATEMENT";default:return f}}()),this.token(f,n),e&&this.token(":",":"),r.length)):0},e.prototype.numberToken=function(){var e,t,n,r,i;if(!(n=O.exec(this.chunk)))return 0;r=n[0],/^0[BOX]/.test(r)?this.error("radix prefix '"+r+"' must be lowercase"):/E/.test(r)&&!/^0x/.test(r)?this.error("exponential notation '"+r+"' must be indicated with a lowercase 'e'"):/^0\d*[89]/.test(r)?this.error("decimal literal '"+r+"' must not be prefixed with '0'"):/^0\d+/.test(r)&&this.error("octal literal '"+r+"' must be prefixed with '0o'"),t=r.length;if(i=/^0o([0-7]+)/.exec(r))r="0x"+parseInt(i[1],8).toString(16);if(e=/^0b([01]+)/.exec(r))r="0x"+parseInt(e[1],2).toString(16);return this.token("NUMBER",r),t},e.prototype.stringToken=function(){var e,t,n;switch(this.chunk.charAt(0)){case"'":if(!(e=j.exec(this.chunk)))return 0;this.token("STRING",(n=e[0]).replace(C,"\\\n"));break;case'"':if(!(n=this.balancedString(this.chunk,'"')))return 0;0=0)?0:(n=_.exec(this.chunk))?(o=n,n=o[0],i=o[1],e=o[2],i.slice(0,2)==="/*"&&this.error("regular expressions cannot begin with `*`"),i==="//"&&(i="/(?:)/"),this.token("REGEX",""+i+e),n.length):0)},e.prototype.heregexToken=function(e){var t,n,r,i,s,o,u,a,f,l,c,h,p;r=e[0],t=e[1],n=e[2];if(0>t.indexOf("#{"))return i=t.replace(d,"").replace(/\//g,"\\/"),i.match(/^\*/)&&this.error("regular expressions cannot begin with `*`"),this.token("REGEX","/"+(i||"(?:)")+"/"+n),r.length;this.token("IDENTIFIER","RegExp"),this.tokens.push(["CALL_START","("]),o=[],l=this.interpolateString(t,{regex:!0});for(a=0,f=l.length;athis.indent){if(r)return this.indebt=i-this.indent,this.suppressNewlines(),t.length;e=i-this.indent+this.outdebt,this.token("INDENT",e),this.indents.push(e),this.ends.push("OUTDENT"),this.outdebt=this.indebt=0}else this.indebt=0,this.outdentToken(this.indent-i,r);return this.indent=i,t.length},e.prototype.outdentToken=function(e,t){var n,r;while(e>0)r=this.indents.length-1,this.indents[r]===void 0?e=0:this.indents[r]===this.outdebt?(e-=this.outdebt,this.outdebt=0):this.indents[r]=0)&&this.error('reserved word "'+this.value()+"\" can't be assigned");if((u=t[1])==="||"||u==="&&")return t[0]="COMPOUND_ASSIGN",t[1]+="=",s.length}if(s===";")this.seenFor=!1,i="TERMINATOR";else if(K.call(N,s)>=0)i="MATH";else if(K.call(a,s)>=0)i="COMPARE";else if(K.call(f,s)>=0)i="COMPOUND_ASSIGN";else if(K.call(q,s)>=0)i="UNARY";else if(K.call(B,s)>=0)i="SHIFT";else if(K.call(x,s)>=0||s==="?"&&(t!=null?t.spaced:void 0))i="LOGIC";else if(t&&!t.spaced)if(s==="("&&(l=t[0],K.call(n,l)>=0))t[0]==="?"&&(t[0]="FUNC_EXIST"),i="CALL_START";else if(s==="["&&(c=t[0],K.call(m,c)>=0)){i="INDEX_START";switch(t[0]){case"?":t[0]="INDEX_SOAK"}}switch(s){case"(":case"{":case"[":this.ends.push(g[s]);break;case")":case"}":case"]":this.pair(s)}return this.token(i,s),s.length},e.prototype.sanitizeHeredoc=function(e,t){var n,r,i,s,o;i=t.indent,r=t.herecomment;if(r){c.test(e)&&this.error('block comment cannot contain "*/", starting');if(e.indexOf("\n")<=0)return e}else while(s=h.exec(e)){n=s[1];if(i===null||0<(o=n.length)&&of;r=1<=f?++a:--a){if(n){--n;continue}switch(i=e.charAt(r)){case"\\":++n;continue;case t:u.pop();if(!u.length)return e.slice(0,+r+1||9e9);t=u[u.length-1];continue}t!=="}"||i!=='"'&&i!=="'"?t==="}"&&i==="/"&&(s=p.exec(e.slice(r))||_.exec(e.slice(r)))?n+=s[0].length-1:t==="}"&&i==="{"?u.push(t="}"):t==='"'&&o==="#"&&i==="{"&&u.push(t="}"):u.push(t=i),o=i}return this.error("missing "+u.pop()+", starting")},e.prototype.interpolateString=function(t,n){var r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w;n==null&&(n={}),i=n.heredoc,h=n.regex,d=[],c=0,s=-1;while(f=t.charAt(s+=1)){if(f==="\\"){s+=1;continue}if(f!=="#"||t.charAt(s+1)!=="{"||!(r=this.balancedString(t.slice(s+1),"}")))continue;c1&&(l.unshift(["(","(",this.line]),l.push([")",")",this.line])),d.push(["TOKENS",l])}s+=r.length,c=s+1}s>c&&c1)&&this.token("(","(");for(s=m=0,g=d.length;m|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/,R=/^[^\n\S]+/,u=/^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/,r=/^[-=]>/,k=/^(?:\n[^\n\S]*)+/,j=/^'[^\\']*(?:\\.[^\\']*)*'/,y=/^`[^\\`]*(?:\\.[^\\`]*)*`/,_=/^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/,p=/^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/,d=/\s+(?:#.*)?/g,C=/\n/g,h=/\n+([^\n\S]*)/g,c=/\*\//,S=/^\s*(?:,|\??\.(?![.\d])|::)/,I=/\s+$/,f=["-=","+=","/=","*=","%=","||=","&&=","?=","<<=",">>=",">>>=","&=","^=","|="],q=["!","~","NEW","TYPEOF","DELETE","DO"],x=["&&","||","&","|","^"],B=["<<",">>",">>>"],a=["==","!=","<",">","<=",">="],N=["*","/","%"],D=["IN","OF","INSTANCEOF"],t=["TRUE","FALSE"],L=["NUMBER","REGEX","BOOL","NULL","UNDEFINED","++","--","]"],A=L.concat(")","}","THIS","IDENTIFIER","STRING"),n=["IDENTIFIER","STRING","REGEX",")","]","}","?","::","@","THIS","SUPER","DEFER","TAMEREQUIRE"],m=n.concat("NUMBER","BOOL","NULL","UNDEFINED"),E=["INDENT","OUTDENT","TERMINATOR"]}).call(this)},require["./parser"]=new function(){var e=this,t=function(){var e={trace:function(){},yy:{},symbols_:{error:2,Root:3,Body:4,Block:5,TERMINATOR:6,Line:7,Expression:8,Statement:9,Return:10,Comment:11,STATEMENT:12,Await:13,AWAIT:14,Value:15,Invocation:16,Code:17,Operation:18,Assign:19,If:20,Try:21,While:22,For:23,Switch:24,Class:25,Throw:26,Defer:27,INDENT:28,OUTDENT:29,Identifier:30,IDENTIFIER:31,AlphaNumeric:32,NUMBER:33,STRING:34,Literal:35,JS:36,REGEX:37,DEBUGGER:38,UNDEFINED:39,NULL:40,BOOL:41,Assignable:42,"=":43,AssignObj:44,ObjAssignable:45,":":46,ThisProperty:47,RETURN:48,HERECOMMENT:49,PARAM_START:50,ParamList:51,PARAM_END:52,FuncGlyph:53,"->":54,"=>":55,OptComma:56,",":57,Param:58,ParamVar:59,"...":60,Array:61,Object:62,Splat:63,SimpleAssignable:64,Accessor:65,Parenthetical:66,Range:67,This:68,".":69,"?.":70,"::":71,Index:72,INDEX_START:73,IndexValue:74,INDEX_END:75,INDEX_SOAK:76,Slice:77,"{":78,AssignList:79,"}":80,CLASS:81,EXTENDS:82,OptFuncExist:83,Arguments:84,SUPER:85,DEFER:86,FUNC_EXIST:87,CALL_START:88,CALL_END:89,ArgList:90,THIS:91,"@":92,"[":93,"]":94,RangeDots:95,"..":96,Arg:97,SimpleArgs:98,TRY:99,Catch:100,FINALLY:101,CATCH:102,THROW:103,"(":104,")":105,WhileSource:106,WHILE:107,WHEN:108,UNTIL:109,Loop:110,LOOP:111,ForBody:112,FOR:113,ForStart:114,ForSource:115,ForVariables:116,OWN:117,ForValue:118,FORIN:119,FOROF:120,BY:121,SWITCH:122,Whens:123,ELSE:124,When:125,LEADING_WHEN:126,IfBlock:127,IF:128,POST_IF:129,UNARY:130,"-":131,"+":132,"--":133,"++":134,"?":135,MATH:136,SHIFT:137,COMPARE:138,LOGIC:139,RELATION:140,COMPOUND_ASSIGN:141,$accept:0,$end:1},terminals_:{2:"error",6:"TERMINATOR",12:"STATEMENT",14:"AWAIT",28:"INDENT",29:"OUTDENT",31:"IDENTIFIER",33:"NUMBER",34:"STRING",36:"JS",37:"REGEX",38:"DEBUGGER",39:"UNDEFINED",40:"NULL",41:"BOOL",43:"=",46:":",48:"RETURN",49:"HERECOMMENT",50:"PARAM_START",52:"PARAM_END",54:"->",55:"=>",57:",",60:"...",69:".",70:"?.",71:"::",73:"INDEX_START",75:"INDEX_END",76:"INDEX_SOAK",78:"{",80:"}",81:"CLASS",82:"EXTENDS",85:"SUPER",86:"DEFER",87:"FUNC_EXIST",88:"CALL_START",89:"CALL_END",91:"THIS",92:"@",93:"[",94:"]",96:"..",99:"TRY",101:"FINALLY",102:"CATCH",103:"THROW",104:"(",105:")",107:"WHILE",108:"WHEN",109:"UNTIL",111:"LOOP",113:"FOR",117:"OWN",119:"FORIN",120:"FOROF",121:"BY",122:"SWITCH",124:"ELSE",126:"LEADING_WHEN",128:"IF",129:"POST_IF",130:"UNARY",131:"-",132:"+",133:"--",134:"++",135:"?",136:"MATH",137:"SHIFT",138:"COMPARE",139:"LOGIC",140:"RELATION",141:"COMPOUND_ASSIGN"},productions_:[0,[3,0],[3,1],[3,2],[4,1],[4,3],[4,2],[7,1],[7,1],[9,1],[9,1],[9,1],[13,2],[13,2],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[5,2],[5,3],[30,1],[32,1],[32,1],[35,1],[35,1],[35,1],[35,1],[35,1],[35,1],[35,1],[19,3],[19,4],[19,5],[44,1],[44,3],[44,5],[44,1],[45,1],[45,1],[45,1],[10,2],[10,1],[11,1],[17,5],[17,2],[53,1],[53,1],[56,0],[56,1],[51,0],[51,1],[51,3],[51,4],[51,6],[58,1],[58,2],[58,3],[59,1],[59,1],[59,1],[59,1],[63,2],[64,1],[64,2],[64,2],[64,1],[42,1],[42,1],[42,1],[15,1],[15,1],[15,1],[15,1],[15,1],[65,2],[65,2],[65,2],[65,2],[65,1],[65,1],[72,3],[72,2],[74,1],[74,1],[62,4],[79,0],[79,1],[79,3],[79,4],[79,6],[25,1],[25,2],[25,3],[25,4],[25,2],[25,3],[25,4],[25,5],[16,3],[16,3],[16,1],[16,2],[27,2],[83,0],[83,1],[84,2],[84,4],[68,1],[68,1],[47,2],[61,2],[61,4],[95,1],[95,1],[67,5],[77,3],[77,2],[77,2],[77,1],[90,1],[90,3],[90,4],[90,4],[90,6],[97,1],[97,1],[98,1],[98,3],[21,2],[21,3],[21,4],[21,5],[100,3],[26,2],[66,3],[66,5],[106,2],[106,4],[106,2],[106,4],[22,2],[22,2],[22,2],[22,1],[110,2],[110,2],[23,2],[23,2],[23,2],[112,2],[112,2],[114,2],[114,3],[118,1],[118,1],[118,1],[118,1],[116,1],[116,3],[115,2],[115,2],[115,4],[115,4],[115,4],[115,6],[115,6],[24,5],[24,7],[24,4],[24,6],[123,1],[123,2],[125,3],[125,4],[127,3],[127,5],[20,1],[20,3],[20,3],[20,3],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,5],[18,3]],performAction:function(t,n,r,i,s,o,u){var a=o.length-1;switch(s){case 1:return this.$=new i.Block;case 2:return this.$=o[a];case 3:return this.$=o[a-1];case 4:this.$=i.Block.wrap([o[a]]);break;case 5:this.$=o[a-2].push(o[a]);break;case 6:this.$=o[a-1];break;case 7:this.$=o[a];break;case 8:this.$=o[a];break;case 9:this.$=o[a];break;case 10:this.$=o[a];break;case 11:this.$=new i.Literal(o[a]);break;case 12:this.$=new i.Await(o[a]);break;case 13:this.$=new i.Await(i.Block.wrap([o[a]]));break;case 14:this.$=o[a];break;case 15:this.$=o[a];break;case 16:this.$=o[a];break;case 17:this.$=o[a];break;case 18:this.$=o[a];break;case 19:this.$=o[a];break;case 20:this.$=o[a];break;case 21:this.$=o[a];break;case 22:this.$=o[a];break;case 23:this.$=o[a];break;case 24:this.$=o[a];break;case 25:this.$=o[a];break;case 26:this.$=o[a];break;case 27:this.$=o[a];break;case 28:this.$=new i.Block;break;case 29:this.$=o[a-1];break;case 30:this.$=new i.Literal(o[a]);break;case 31:this.$=new i.Literal(o[a]);break;case 32:this.$=new i.Literal(o[a]);break;case 33:this.$=o[a];break;case 34:this.$=new i.Literal(o[a]);break;case 35:this.$=new i.Literal(o[a]);break;case 36:this.$=new i.Literal(o[a]);break;case 37:this.$=new i.Undefined;break;case 38:this.$=new i.Null;break;case 39:this.$=new i.Bool(o[a]);break;case 40:this.$=new i.Assign(o[a-2],o[a]);break;case 41:this.$=new i.Assign(o[a-3],o[a]);break;case 42:this.$=new i.Assign(o[a-4],o[a-1]);break;case 43:this.$=new i.Value(o[a]);break;case 44:this.$=new i.Assign(new i.Value(o[a-2]),o[a],"object");break;case 45:this.$=new i.Assign(new i.Value(o[a-4]),o[a-1],"object");break;case 46:this.$=o[a];break;case 47:this.$=o[a];break;case 48:this.$=o[a];break;case 49:this.$=o[a];break;case 50:this.$=new i.Return(o[a]);break;case 51:this.$=new i.Return;break;case 52:this.$=new i.Comment(o[a]);break;case 53:this.$=new i.Code(o[a-3],o[a],o[a-1]);break;case 54:this.$=new i.Code([],o[a],o[a-1]);break;case 55:this.$="func";break;case 56:this.$="boundfunc";break;case 57:this.$=o[a];break;case 58:this.$=o[a];break;case 59:this.$=[];break;case 60:this.$=[o[a]];break;case 61:this.$=o[a-2].concat(o[a]);break;case 62:this.$=o[a-3].concat(o[a]);break;case 63:this.$=o[a-5].concat(o[a-2]);break;case 64:this.$=new i.Param(o[a]);break;case 65:this.$=new i.Param(o[a-1],null,!0);break;case 66:this.$=new i.Param(o[a-2],o[a]);break;case 67:this.$=o[a];break;case 68:this.$=o[a];break;case 69:this.$=o[a];break;case 70:this.$=o[a];break;case 71:this.$=new i.Splat(o[a-1]);break;case 72:this.$=new i.Value(o[a]);break;case 73:this.$=o[a-1].add(o[a]);break;case 74:this.$=new i.Value(o[a-1],[].concat(o[a]));break;case 75:this.$=o[a];break;case 76:this.$=o[a];break;case 77:this.$=new i.Value(o[a]);break;case 78:this.$=new i.Value(o[a]);break;case 79:this.$=o[a];break;case 80:this.$=new i.Value(o[a]);break;case 81:this.$=new i.Value(o[a]);break;case 82:this.$=new i.Value(o[a]);break;case 83:this.$=o[a];break;case 84:this.$=new i.Access(o[a]);break;case 85:this.$=new i.Access(o[a]);break;case 86:this.$=new i.Access(o[a],"soak");break;case 87:this.$=[new i.Access(new i.Literal("prototype")),new i.Access(o[a])];break;case 88:this.$=new i.Access(new i.Literal("prototype"));break;case 89:this.$=o[a];break;case 90:this.$=o[a-1];break;case 91:this.$=i.extend(o[a],{soak:!0});break;case 92:this.$=new i.Index(o[a]);break;case 93:this.$=new i.Slice(o[a]);break;case 94:this.$=new i.Obj(o[a-2],o[a-3].generated);break;case 95:this.$=[];break;case 96:this.$=[o[a]];break;case 97:this.$=o[a-2].concat(o[a]);break;case 98:this.$=o[a-3].concat(o[a]);break;case 99:this.$=o[a-5].concat(o[a-2]);break;case 100:this.$=new i.Class;break;case 101:this.$=new i.Class(null,null,o[a]);break;case 102:this.$=new i.Class(null,o[a]);break;case 103:this.$=new i.Class(null,o[a-1],o[a]);break;case 104:this.$=new i.Class(o[a]);break;case 105:this.$=new i.Class(o[a-1],null,o[a]);break;case 106:this.$=new i.Class(o[a-2],o[a]);break;case 107:this.$=new i.Class(o[a-3],o[a-1],o[a]);break;case 108:this.$=new i.Call(o[a-2],o[a],o[a-1]);break;case 109:this.$=new i.Call(o[a-2],o[a],o[a-1]);break;case 110:this.$=new i.Call("super",[new i.Splat(new i.Literal("arguments"))]);break;case 111:this.$=new i.Call("super",o[a]);break;case 112:this.$=new i.Defer(o[a],r);break;case 113:this.$=!1;break;case 114:this.$=!0;break;case 115:this.$=[];break;case 116:this.$=o[a-2];break;case 117:this.$=new i.Value(new i.Literal("this"));break;case 118:this.$=new i.Value(new i.Literal("this"));break;case 119:this.$=new i.Value(new i.Literal("this"),[new i.Access(o[a])],"this");break;case 120:this.$=new i.Arr([]);break;case 121:this.$=new i.Arr(o[a-2]);break;case 122:this.$="inclusive";break;case 123:this.$="exclusive";break;case 124:this.$=new i.Range(o[a-3],o[a-1],o[a-2]);break;case 125:this.$=new i.Range(o[a-2],o[a],o[a-1]);break;case 126:this.$=new i.Range(o[a-1],null,o[a]);break;case 127:this.$=new i.Range(null,o[a],o[a-1]);break;case 128:this.$=new i.Range(null,null,o[a]);break;case 129:this.$=[o[a]];break;case 130:this.$=o[a-2].concat(o[a]);break;case 131:this.$=o[a-3].concat(o[a]);break;case 132:this.$=o[a-2];break;case 133:this.$=o[a-5].concat(o[a-2]);break;case 134:this.$=o[a];break;case 135:this.$=o[a];break;case 136:this.$=o[a];break;case 137:this.$=[].concat(o[a-2],o[a]);break;case 138:this.$=new i.Try(o[a]);break;case 139:this.$=new i.Try(o[a-1],o[a][0],o[a][1]);break;case 140:this.$=new i.Try(o[a-2],null,null,o[a]);break;case 141:this.$=new i.Try(o[a-3],o[a-2][0],o[a-2][1],o[a]);break;case 142:this.$=[o[a-1],o[a]];break;case 143:this.$=new i.Throw(o[a]);break;case 144:this.$=new i.Parens(o[a-1]);break;case 145:this.$=new i.Parens(o[a-2]);break;case 146:this.$=new i.While(o[a]);break;case 147:this.$=new i.While(o[a-2],{guard:o[a]});break;case 148:this.$=new i.While(o[a],{invert:!0});break;case 149:this.$=new i.While(o[a-2],{invert:!0,guard:o[a]});break;case 150:this.$=o[a-1].addBody(o[a]);break;case 151:this.$=o[a].addBody(i.Block.wrap([o[a-1]]));break;case 152:this.$=o[a].addBody(i.Block.wrap([o[a-1]]));break;case 153:this.$=o[a];break;case 154:this.$=(new i.While(new i.Literal("true"))).addBody(o[a]);break;case 155:this.$=(new i.While(new i.Literal("true"))).addBody(i.Block.wrap([o[a]]));break;case 156:this.$=new i.For(o[a-1],o[a]);break;case 157:this.$=new i.For(o[a-1],o[a]);break;case 158:this.$=new i.For(o[a],o[a-1]);break;case 159:this.$={source:new i.Value(o[a])};break;case 160:this.$=function(){return o[a].own=o[a-1].own,o[a].name=o[a-1][0],o[a].index=o[a-1][1],o[a]}();break;case 161:this.$=o[a];break;case 162:this.$=function(){return o[a].own=!0,o[a]}();break;case 163:this.$=o[a];break;case 164:this.$=o[a];break;case 165:this.$=new i.Value(o[a]);break;case 166:this.$=new i.Value(o[a]);break;case 167:this.$=[o[a]];break;case 168:this.$=[o[a-2],o[a]];break;case 169:this.$={source:o[a]};break;case 170:this.$={source:o[a],object:!0};break;case 171:this.$={source:o[a-2],guard:o[a]};break;case 172:this.$={source:o[a-2],guard:o[a],object:!0};break;case 173:this.$={source:o[a-2],step:o[a]};break;case 174:this.$={source:o[a-4],guard:o[a-2],step:o[a]};break;case 175:this.$={source:o[a-4],step:o[a-2],guard:o[a]};break;case 176:this.$=new i.Switch(o[a-3],o[a-1]);break;case 177:this.$=new i.Switch(o[a-5],o[a-3],o[a-1]);break;case 178:this.$=new i.Switch(null,o[a-1]);break;case 179:this.$=new i.Switch(null,o[a-3],o[a-1]);break;case 180:this.$=o[a];break;case 181:this.$=o[a-1].concat(o[a]);break;case 182:this.$=[[o[a-1],o[a]]];break;case 183:this.$=[[o[a-2],o[a-1]]];break;case 184:this.$=new i.If(o[a-1],o[a],{type:o[a-2]});break;case 185:this.$=o[a-4].addElse(new i.If(o[a-1],o[a],{type:o[a-2]}));break;case 186:this.$=o[a];break;case 187:this.$=o[a-2].addElse(o[a]);break;case 188:this.$=new i.If(o[a],i.Block.wrap([o[a-2]]),{type:o[a-1],statement:!0});break;case 189:this.$=new i.If(o[a],i.Block.wrap([o[a-2]]),{type:o[a-1],statement:!0});break;case 190:this.$=new i.Op(o[a-1],o[a]);break;case 191:this.$=new i.Op("-",o[a]);break;case 192:this.$=new i.Op("+",o[a]);break;case 193:this.$=new i.Op("--",o[a]);break;case 194:this.$=new i.Op("++",o[a]);break;case 195:this.$=new i.Op("--",o[a-1],null,!0);break;case 196:this.$=new i.Op("++",o[a-1],null,!0);break;case 197:this.$=new i.Existence(o[a-1]);break;case 198:this.$=new i.Op("+",o[a-2],o[a]);break;case 199:this.$=new i.Op("-",o[a-2],o[a]);break;case 200:this.$=new i.Op(o[a-1],o[a-2],o[a]);break;case 201:this.$=new i.Op(o[a-1],o[a-2],o[a]);break;case 202:this.$=new i.Op(o[a-1],o[a-2],o[a]);break;case 203:this.$=new i.Op(o[a-1],o[a-2],o[a]);break;case 204:this.$=function(){return o[a-1].charAt(0)==="!"?(new i.Op(o[a-1].slice(1),o[a-2],o[a])).invert():new i.Op(o[a-1],o[a-2],o[a])}();break;case 205:this.$=new i.Assign(o[a-2],o[a],o[a-1]);break;case 206:this.$=new i.Assign(o[a-4],o[a-1],o[a-3]);break;case 207:this.$=new i.Extends(o[a-2],o[a])}},table:[{1:[2,1],3:1,4:2,5:3,7:4,8:6,9:7,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,5],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[3]},{1:[2,2],6:[1,78]},{6:[1,79]},{1:[2,4],6:[2,4],29:[2,4],105:[2,4]},{4:81,7:4,8:6,9:7,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,29:[1,80],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,7],6:[2,7],29:[2,7],105:[2,7],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,8],6:[2,8],29:[2,8],105:[2,8],106:94,107:[1,69],109:[1,70],112:95,113:[1,72],114:73,129:[1,93]},{1:[2,14],6:[2,14],28:[2,14],29:[2,14],52:[2,14],57:[2,14],60:[2,14],65:97,69:[1,99],70:[1,100],71:[1,101],72:102,73:[1,103],75:[2,14],76:[1,104],80:[2,14],83:96,87:[1,98],88:[2,113],89:[2,14],94:[2,14],96:[2,14],105:[2,14],107:[2,14],108:[2,14],109:[2,14],113:[2,14],121:[2,14],129:[2,14],131:[2,14],132:[2,14],135:[2,14],136:[2,14],137:[2,14],138:[2,14],139:[2,14],140:[2,14]},{1:[2,15],6:[2,15],28:[2,15],29:[2,15],52:[2,15],57:[2,15],60:[2,15],65:106,69:[1,99],70:[1,100],71:[1,101],72:102,73:[1,103],75:[2,15],76:[1,104],80:[2,15],83:105,87:[1,98],88:[2,113],89:[2,15],94:[2,15],96:[2,15],105:[2,15],107:[2,15],108:[2,15],109:[2,15],113:[2,15],121:[2,15],129:[2,15],131:[2,15],132:[2,15],135:[2,15],136:[2,15],137:[2,15],138:[2,15],139:[2,15],140:[2,15]},{1:[2,16],6:[2,16],28:[2,16],29:[2,16],52:[2,16],57:[2,16],60:[2,16],75:[2,16],80:[2,16],89:[2,16],94:[2,16],96:[2,16],105:[2,16],107:[2,16],108:[2,16],109:[2,16],113:[2,16],121:[2,16],129:[2,16],131:[2,16],132:[2,16],135:[2,16],136:[2,16],137:[2,16],138:[2,16],139:[2,16],140:[2,16]},{1:[2,17],6:[2,17],28:[2,17],29:[2,17],52:[2,17],57:[2,17],60:[2,17],75:[2,17],80:[2,17],89:[2,17],94:[2,17],96:[2,17],105:[2,17],107:[2,17],108:[2,17],109:[2,17],113:[2,17],121:[2,17],129:[2,17],131:[2,17],132:[2,17],135:[2,17],136:[2,17],137:[2,17],138:[2,17],139:[2,17],140:[2,17]},{1:[2,18],6:[2,18],28:[2,18],29:[2,18],52:[2,18],57:[2,18],60:[2,18],75:[2,18],80:[2,18],89:[2,18],94:[2,18],96:[2,18],105:[2,18],107:[2,18],108:[2,18],109:[2,18],113:[2,18],121:[2,18],129:[2,18],131:[2,18],132:[2,18],135:[2,18],136:[2,18],137:[2,18],138:[2,18],139:[2,18],140:[2,18]},{1:[2,19],6:[2,19],28:[2,19],29:[2,19],52:[2,19],57:[2,19],60:[2,19],75:[2,19],80:[2,19],89:[2,19],94:[2,19],96:[2,19],105:[2,19],107:[2,19],108:[2,19],109:[2,19],113:[2,19],121:[2,19],129:[2,19],131:[2,19],132:[2,19],135:[2,19],136:[2,19],137:[2,19],138:[2,19],139:[2,19],140:[2,19]},{1:[2,20],6:[2,20],28:[2,20],29:[2,20],52:[2,20],57:[2,20],60:[2,20],75:[2,20],80:[2,20],89:[2,20],94:[2,20],96:[2,20],105:[2,20],107:[2,20],108:[2,20],109:[2,20],113:[2,20],121:[2,20],129:[2,20],131:[2,20],132:[2,20],135:[2,20],136:[2,20],137:[2,20],138:[2,20],139:[2,20],140:[2,20]},{1:[2,21],6:[2,21],28:[2,21],29:[2,21],52:[2,21],57:[2,21],60:[2,21],75:[2,21],80:[2,21],89:[2,21],94:[2,21],96:[2,21],105:[2,21],107:[2,21],108:[2,21],109:[2,21],113:[2,21],121:[2,21],129:[2,21],131:[2,21],132:[2,21],135:[2,21],136:[2,21],137:[2,21],138:[2,21],139:[2,21],140:[2,21]},{1:[2,22],6:[2,22],28:[2,22],29:[2,22],52:[2,22],57:[2,22],60:[2,22],75:[2,22],80:[2,22],89:[2,22],94:[2,22],96:[2,22],105:[2,22],107:[2,22],108:[2,22],109:[2,22],113:[2,22],121:[2,22],129:[2,22],131:[2,22],132:[2,22],135:[2,22],136:[2,22],137:[2,22],138:[2,22],139:[2,22],140:[2,22]},{1:[2,23],6:[2,23],28:[2,23],29:[2,23],52:[2,23],57:[2,23],60:[2,23],75:[2,23],80:[2,23],89:[2,23],94:[2,23],96:[2,23],105:[2,23],107:[2,23],108:[2,23],109:[2,23],113:[2,23],121:[2,23],129:[2,23],131:[2,23],132:[2,23],135:[2,23],136:[2,23],137:[2,23],138:[2,23],139:[2,23],140:[2,23]},{1:[2,24],6:[2,24],28:[2,24],29:[2,24],52:[2,24],57:[2,24],60:[2,24],75:[2,24],80:[2,24],89:[2,24],94:[2,24],96:[2,24],105:[2,24],107:[2,24],108:[2,24],109:[2,24],113:[2,24],121:[2,24],129:[2,24],131:[2,24],132:[2,24],135:[2,24],136:[2,24],137:[2,24],138:[2,24],139:[2,24],140:[2,24]},{1:[2,25],6:[2,25],28:[2,25],29:[2,25],52:[2,25],57:[2,25],60:[2,25],75:[2,25],80:[2,25],89:[2,25],94:[2,25],96:[2,25],105:[2,25],107:[2,25],108:[2,25],109:[2,25],113:[2,25],121:[2,25],129:[2,25],131:[2,25],132:[2,25],135:[2,25],136:[2,25],137:[2,25],138:[2,25],139:[2,25],140:[2,25]},{1:[2,26],6:[2,26],28:[2,26],29:[2,26],52:[2,26],57:[2,26],60:[2,26],75:[2,26],80:[2,26],89:[2,26],94:[2,26],96:[2,26],105:[2,26],107:[2,26],108:[2,26],109:[2,26],113:[2,26],121:[2,26],129:[2,26],131:[2,26],132:[2,26],135:[2,26],136:[2,26],137:[2,26],138:[2,26],139:[2,26],140:[2,26]},{1:[2,27],6:[2,27],28:[2,27],29:[2,27],52:[2,27],57:[2,27],60:[2,27],75:[2,27],80:[2,27],89:[2,27],94:[2,27],96:[2,27],105:[2,27],107:[2,27],108:[2,27],109:[2,27],113:[2,27],121:[2,27],129:[2,27],131:[2,27],132:[2,27],135:[2,27],136:[2,27],137:[2,27],138:[2,27],139:[2,27],140:[2,27]},{1:[2,9],6:[2,9],29:[2,9],105:[2,9],107:[2,9],109:[2,9],113:[2,9],129:[2,9]},{1:[2,10],6:[2,10],29:[2,10],105:[2,10],107:[2,10],109:[2,10],113:[2,10],129:[2,10]},{1:[2,11],6:[2,11],29:[2,11],105:[2,11],107:[2,11],109:[2,11],113:[2,11],129:[2,11]},{1:[2,79],6:[2,79],28:[2,79],29:[2,79],43:[1,107],52:[2,79],57:[2,79],60:[2,79],69:[2,79],70:[2,79],71:[2,79],73:[2,79],75:[2,79],76:[2,79],80:[2,79],87:[2,79],88:[2,79],89:[2,79],94:[2,79],96:[2,79],105:[2,79],107:[2,79],108:[2,79],109:[2,79],113:[2,79],121:[2,79],129:[2,79],131:[2,79],132:[2,79],135:[2,79],136:[2,79],137:[2,79],138:[2,79],139:[2,79],140:[2,79]},{1:[2,80],6:[2,80],28:[2,80],29:[2,80],52:[2,80],57:[2,80],60:[2,80],69:[2,80],70:[2,80],71:[2,80],73:[2,80],75:[2,80],76:[2,80],80:[2,80],87:[2,80],88:[2,80],89:[2,80],94:[2,80],96:[2,80],105:[2,80],107:[2,80],108:[2,80],109:[2,80],113:[2,80],121:[2,80],129:[2,80],131:[2,80],132:[2,80],135:[2,80],136:[2,80],137:[2,80],138:[2,80],139:[2,80],140:[2,80]},{1:[2,81],6:[2,81],28:[2,81],29:[2,81],52:[2,81],57:[2,81],60:[2,81],69:[2,81],70:[2,81],71:[2,81],73:[2,81],75:[2,81],76:[2,81],80:[2,81],87:[2,81],88:[2,81],89:[2,81],94:[2,81],96:[2,81],105:[2,81],107:[2,81],108:[2,81],109:[2,81],113:[2,81],121:[2,81],129:[2,81],131:[2,81],132:[2,81],135:[2,81],136:[2,81],137:[2,81],138:[2,81],139:[2,81],140:[2,81]},{1:[2,82],6:[2,82],28:[2,82],29:[2,82],52:[2,82],57:[2,82],60:[2,82],69:[2,82],70:[2,82],71:[2,82],73:[2,82],75:[2,82],76:[2,82],80:[2,82],87:[2,82],88:[2,82],89:[2,82],94:[2,82],96:[2,82],105:[2,82],107:[2,82],108:[2,82],109:[2,82],113:[2,82],121:[2,82],129:[2,82],131:[2,82],132:[2,82],135:[2,82],136:[2,82],137:[2,82],138:[2,82],139:[2,82],140:[2,82]},{1:[2,83],6:[2,83],28:[2,83],29:[2,83],52:[2,83],57:[2,83],60:[2,83],69:[2,83],70:[2,83],71:[2,83],73:[2,83],75:[2,83],76:[2,83],80:[2,83],87:[2,83],88:[2,83],89:[2,83],94:[2,83],96:[2,83],105:[2,83],107:[2,83],108:[2,83],109:[2,83],113:[2,83],121:[2,83],129:[2,83],131:[2,83],132:[2,83],135:[2,83],136:[2,83],137:[2,83],138:[2,83],139:[2,83],140:[2,83]},{1:[2,110],6:[2,110],28:[2,110],29:[2,110],52:[2,110],57:[2,110],60:[2,110],69:[2,110],70:[2,110],71:[2,110],73:[2,110],75:[2,110],76:[2,110],80:[2,110],84:108,87:[2,110],88:[1,109],89:[2,110],94:[2,110],96:[2,110],105:[2,110],107:[2,110],108:[2,110],109:[2,110],113:[2,110],121:[2,110],129:[2,110],131:[2,110],132:[2,110],135:[2,110],136:[2,110],137:[2,110],138:[2,110],139:[2,110],140:[2,110]},{6:[2,59],28:[2,59],30:113,31:[1,77],47:114,51:110,52:[2,59],57:[2,59],58:111,59:112,61:115,62:116,78:[1,74],92:[1,117],93:[1,118]},{5:119,28:[1,5]},{8:120,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:122,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:123,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{15:125,16:126,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:127,47:67,61:51,62:52,64:124,66:27,67:28,68:29,78:[1,74],85:[1,30],91:[1,62],92:[1,63],93:[1,61],104:[1,60]},{15:125,16:126,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:127,47:67,61:51,62:52,64:128,66:27,67:28,68:29,78:[1,74],85:[1,30],91:[1,62],92:[1,63],93:[1,61],104:[1,60]},{1:[2,76],6:[2,76],28:[2,76],29:[2,76],43:[2,76],52:[2,76],57:[2,76],60:[2,76],69:[2,76],70:[2,76],71:[2,76],73:[2,76],75:[2,76],76:[2,76],80:[2,76],82:[1,132],87:[2,76],88:[2,76],89:[2,76],94:[2,76],96:[2,76],105:[2,76],107:[2,76],108:[2,76],109:[2,76],113:[2,76],121:[2,76],129:[2,76],131:[2,76],132:[2,76],133:[1,129],134:[1,130],135:[2,76],136:[2,76],137:[2,76],138:[2,76],139:[2,76],140:[2,76],141:[1,131]},{1:[2,186],6:[2,186],28:[2,186],29:[2,186],52:[2,186],57:[2,186],60:[2,186],75:[2,186],80:[2,186],89:[2,186],94:[2,186],96:[2,186],105:[2,186],107:[2,186],108:[2,186],109:[2,186],113:[2,186],121:[2,186],124:[1,133],129:[2,186],131:[2,186],132:[2,186],135:[2,186],136:[2,186],137:[2,186],138:[2,186],139:[2,186],140:[2,186]},{5:134,28:[1,5]},{5:135,28:[1,5]},{1:[2,153],6:[2,153],28:[2,153],29:[2,153],52:[2,153],57:[2,153],60:[2,153],75:[2,153],80:[2,153],89:[2,153],94:[2,153],96:[2,153],105:[2,153],107:[2,153],108:[2,153],109:[2,153],113:[2,153],121:[2,153],129:[2,153],131:[2,153],132:[2,153],135:[2,153],136:[2,153],137:[2,153],138:[2,153],139:[2,153],140:[2,153]},{5:136,28:[1,5]},{8:137,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,138],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,100],5:139,6:[2,100],15:125,16:126,28:[1,5],29:[2,100],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:127,47:67,52:[2,100],57:[2,100],60:[2,100],61:51,62:52,64:141,66:27,67:28,68:29,75:[2,100],78:[1,74],80:[2,100],82:[1,140],85:[1,30],89:[2,100],91:[1,62],92:[1,63],93:[1,61],94:[2,100],96:[2,100],104:[1,60],105:[2,100],107:[2,100],108:[2,100],109:[2,100],113:[2,100],121:[2,100],129:[2,100],131:[2,100],132:[2,100],135:[2,100],136:[2,100],137:[2,100],138:[2,100],139:[2,100],140:[2,100]},{8:142,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{84:143,88:[1,109]},{5:144,8:145,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,5],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,51],6:[2,51],8:146,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,29:[2,51],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],105:[2,51],106:41,107:[2,51],109:[2,51],110:42,111:[1,71],112:43,113:[2,51],114:73,122:[1,44],127:39,128:[1,68],129:[2,51],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,52],6:[2,52],28:[2,52],29:[2,52],57:[2,52],80:[2,52],105:[2,52],107:[2,52],109:[2,52],113:[2,52],129:[2,52]},{1:[2,77],6:[2,77],28:[2,77],29:[2,77],43:[2,77],52:[2,77],57:[2,77],60:[2,77],69:[2,77],70:[2,77],71:[2,77],73:[2,77],75:[2,77],76:[2,77],80:[2,77],87:[2,77],88:[2,77],89:[2,77],94:[2,77],96:[2,77],105:[2,77],107:[2,77],108:[2,77],109:[2,77],113:[2,77],121:[2,77],129:[2,77],131:[2,77],132:[2,77],135:[2,77],136:[2,77],137:[2,77],138:[2,77],139:[2,77],140:[2,77]},{1:[2,78],6:[2,78],28:[2,78],29:[2,78],43:[2,78],52:[2,78],57:[2,78],60:[2,78],69:[2,78],70:[2,78],71:[2,78],73:[2,78],75:[2,78],76:[2,78],80:[2,78],87:[2,78],88:[2,78],89:[2,78],94:[2,78],96:[2,78],105:[2,78],107:[2,78],108:[2,78],109:[2,78],113:[2,78],121:[2,78],129:[2,78],131:[2,78],132:[2,78],135:[2,78],136:[2,78],137:[2,78],138:[2,78],139:[2,78],140:[2,78]},{1:[2,33],6:[2,33],28:[2,33],29:[2,33],52:[2,33],57:[2,33],60:[2,33],69:[2,33],70:[2,33],71:[2,33],73:[2,33],75:[2,33],76:[2,33],80:[2,33],87:[2,33],88:[2,33],89:[2,33],94:[2,33],96:[2,33],105:[2,33],107:[2,33],108:[2,33],109:[2,33],113:[2,33],121:[2,33],129:[2,33],131:[2,33],132:[2,33],135:[2,33],136:[2,33],137:[2,33],138:[2,33],139:[2,33],140:[2,33]},{1:[2,34],6:[2,34],28:[2,34],29:[2,34],52:[2,34],57:[2,34],60:[2,34],69:[2,34],70:[2,34],71:[2,34],73:[2,34],75:[2,34],76:[2,34],80:[2,34],87:[2,34],88:[2,34],89:[2,34],94:[2,34],96:[2,34],105:[2,34],107:[2,34],108:[2,34],109:[2,34],113:[2,34],121:[2,34],129:[2,34],131:[2,34],132:[2,34],135:[2,34],136:[2,34],137:[2,34],138:[2,34],139:[2,34],140:[2,34]},{1:[2,35],6:[2,35],28:[2,35],29:[2,35],52:[2,35],57:[2,35],60:[2,35],69:[2,35],70:[2,35],71:[2,35],73:[2,35],75:[2,35],76:[2,35],80:[2,35],87:[2,35],88:[2,35],89:[2,35],94:[2,35],96:[2,35],105:[2,35],107:[2,35],108:[2,35],109:[2,35],113:[2,35],121:[2,35],129:[2,35],131:[2,35],132:[2,35],135:[2,35],136:[2,35],137:[2,35],138:[2,35],139:[2,35],140:[2,35]},{1:[2,36],6:[2,36],28:[2,36],29:[2,36],52:[2,36],57:[2,36],60:[2,36],69:[2,36],70:[2,36],71:[2,36],73:[2,36],75:[2,36],76:[2,36],80:[2,36],87:[2,36],88:[2,36],89:[2,36],94:[2,36],96:[2,36],105:[2,36],107:[2,36],108:[2,36],109:[2,36],113:[2,36],121:[2,36],129:[2,36],131:[2,36],132:[2,36],135:[2,36],136:[2,36],137:[2,36],138:[2,36],139:[2,36],140:[2,36]},{1:[2,37],6:[2,37],28:[2,37],29:[2,37],52:[2,37],57:[2,37],60:[2,37],69:[2,37],70:[2,37],71:[2,37],73:[2,37],75:[2,37],76:[2,37],80:[2,37],87:[2,37],88:[2,37],89:[2,37],94:[2,37],96:[2,37],105:[2,37],107:[2,37],108:[2,37],109:[2,37],113:[2,37],121:[2,37],129:[2,37],131:[2,37],132:[2,37],135:[2,37],136:[2,37],137:[2,37],138:[2,37],139:[2,37],140:[2,37]},{1:[2,38],6:[2,38],28:[2,38],29:[2,38],52:[2,38],57:[2,38],60:[2,38],69:[2,38],70:[2,38],71:[2,38],73:[2,38],75:[2,38],76:[2,38],80:[2,38],87:[2,38],88:[2,38],89:[2,38],94:[2,38],96:[2,38],105:[2,38],107:[2,38],108:[2,38],109:[2,38],113:[2,38],121:[2,38],129:[2,38],131:[2,38],132:[2,38],135:[2,38],136:[2,38],137:[2,38],138:[2,38],139:[2,38],140:[2,38]},{1:[2,39],6:[2,39],28:[2,39],29:[2,39],52:[2,39],57:[2,39],60:[2,39],69:[2,39],70:[2,39],71:[2,39],73:[2,39],75:[2,39],76:[2,39],80:[2,39],87:[2,39],88:[2,39],89:[2,39],94:[2,39],96:[2,39],105:[2,39],107:[2,39],108:[2,39],109:[2,39],113:[2,39],121:[2,39],129:[2,39],131:[2,39],132:[2,39],135:[2,39],136:[2,39],137:[2,39],138:[2,39],139:[2,39],140:[2,39]},{4:147,7:4,8:6,9:7,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,148],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:149,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,153],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],90:151,91:[1,62],92:[1,63],93:[1,61],94:[1,150],97:152,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,117],6:[2,117],28:[2,117],29:[2,117],52:[2,117],57:[2,117],60:[2,117],69:[2,117],70:[2,117],71:[2,117],73:[2,117],75:[2,117],76:[2,117],80:[2,117],87:[2,117],88:[2,117],89:[2,117],94:[2,117],96:[2,117],105:[2,117],107:[2,117],108:[2,117],109:[2,117],113:[2,117],121:[2,117],129:[2,117],131:[2,117],132:[2,117],135:[2,117],136:[2,117],137:[2,117],138:[2,117],139:[2,117],140:[2,117]},{1:[2,118],6:[2,118],28:[2,118],29:[2,118],30:155,31:[1,77],52:[2,118],57:[2,118],60:[2,118],69:[2,118],70:[2,118],71:[2,118],73:[2,118],75:[2,118],76:[2,118],80:[2,118],87:[2,118],88:[2,118],89:[2,118],94:[2,118],96:[2,118],105:[2,118],107:[2,118],108:[2,118],109:[2,118],113:[2,118],121:[2,118],129:[2,118],131:[2,118],132:[2,118],135:[2,118],136:[2,118],137:[2,118],138:[2,118],139:[2,118],140:[2,118]},{28:[2,55]},{28:[2,56]},{1:[2,72],6:[2,72],28:[2,72],29:[2,72],43:[2,72],52:[2,72],57:[2,72],60:[2,72],69:[2,72],70:[2,72],71:[2,72],73:[2,72],75:[2,72],76:[2,72],80:[2,72],82:[2,72],87:[2,72],88:[2,72],89:[2,72],94:[2,72],96:[2,72],105:[2,72],107:[2,72],108:[2,72],109:[2,72],113:[2,72],121:[2,72],129:[2,72],131:[2,72],132:[2,72],133:[2,72],134:[2,72],135:[2,72],136:[2,72],137:[2,72],138:[2,72],139:[2,72],140:[2,72],141:[2,72]},{1:[2,75],6:[2,75],28:[2,75],29:[2,75],43:[2,75],52:[2,75],57:[2,75],60:[2,75],69:[2,75],70:[2,75],71:[2,75],73:[2,75],75:[2,75],76:[2,75],80:[2,75],82:[2,75],87:[2,75],88:[2,75],89:[2,75],94:[2,75],96:[2,75],105:[2,75],107:[2,75],108:[2,75],109:[2,75],113:[2,75],121:[2,75],129:[2,75],131:[2,75],132:[2,75],133:[2,75],134:[2,75],135:[2,75],136:[2,75],137:[2,75],138:[2,75],139:[2,75],140:[2,75],141:[2,75]},{8:156,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:157,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:158,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{5:159,8:160,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,5],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{30:165,31:[1,77],47:166,61:167,62:168,67:161,78:[1,74],92:[1,117],93:[1,61],116:162,117:[1,163],118:164},{115:169,119:[1,170],120:[1,171]},{6:[2,95],11:175,28:[2,95],30:176,31:[1,77],32:177,33:[1,75],34:[1,76],44:173,45:174,47:178,49:[1,50],57:[2,95],79:172,80:[2,95],92:[1,117]},{1:[2,31],6:[2,31],28:[2,31],29:[2,31],46:[2,31],52:[2,31],57:[2,31],60:[2,31],69:[2,31],70:[2,31],71:[2,31],73:[2,31],75:[2,31],76:[2,31],80:[2,31],87:[2,31],88:[2,31],89:[2,31],94:[2,31],96:[2,31],105:[2,31],107:[2,31],108:[2,31],109:[2,31],113:[2,31],121:[2,31],129:[2,31],131:[2,31],132:[2,31],135:[2,31],136:[2,31],137:[2,31],138:[2,31],139:[2,31],140:[2,31]},{1:[2,32],6:[2,32],28:[2,32],29:[2,32],46:[2,32],52:[2,32],57:[2,32],60:[2,32],69:[2,32],70:[2,32],71:[2,32],73:[2,32],75:[2,32],76:[2,32],80:[2,32],87:[2,32],88:[2,32],89:[2,32],94:[2,32],96:[2,32],105:[2,32],107:[2,32],108:[2,32],109:[2,32],113:[2,32],121:[2,32],129:[2,32],131:[2,32],132:[2,32],135:[2,32],136:[2,32],137:[2,32],138:[2,32],139:[2,32],140:[2,32]},{1:[2,30],6:[2,30],28:[2,30],29:[2,30],43:[2,30],46:[2,30],52:[2,30],57:[2,30],60:[2,30],69:[2,30],70:[2,30],71:[2,30],73:[2,30],75:[2,30],76:[2,30],80:[2,30],82:[2,30],87:[2,30],88:[2,30],89:[2,30],94:[2,30],96:[2,30],105:[2,30],107:[2,30],108:[2,30],109:[2,30],113:[2,30],119:[2,30],120:[2,30],121:[2,30],129:[2,30],131:[2,30],132:[2,30],133:[2,30],134:[2,30],135:[2,30],136:[2,30],137:[2,30],138:[2,30],139:[2,30],140:[2,30],141:[2,30]},{1:[2,6],6:[2,6],7:179,8:6,9:7,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,29:[2,6],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],105:[2,6],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,3]},{1:[2,28],6:[2,28],28:[2,28],29:[2,28],52:[2,28],57:[2,28],60:[2,28],75:[2,28],80:[2,28],89:[2,28],94:[2,28],96:[2,28],101:[2,28],102:[2,28],105:[2,28],107:[2,28],108:[2,28],109:[2,28],113:[2,28],121:[2,28],124:[2,28],126:[2,28],129:[2,28],131:[2,28],132:[2,28],135:[2,28],136:[2,28],137:[2,28],138:[2,28],139:[2,28],140:[2,28]},{6:[1,78],29:[1,180]},{1:[2,197],6:[2,197],28:[2,197],29:[2,197],52:[2,197],57:[2,197],60:[2,197],75:[2,197],80:[2,197],89:[2,197],94:[2,197],96:[2,197],105:[2,197],107:[2,197],108:[2,197],109:[2,197],113:[2,197],121:[2,197],129:[2,197],131:[2,197],132:[2,197],135:[2,197],136:[2,197],137:[2,197],138:[2,197],139:[2,197],140:[2,197]},{8:181,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:182,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:183,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:184,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:185,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:186,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:187,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:188,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,152],6:[2,152],28:[2,152],29:[2,152],52:[2,152],57:[2,152],60:[2,152],75:[2,152],80:[2,152],89:[2,152],94:[2,152],96:[2,152],105:[2,152],107:[2,152],108:[2,152],109:[2,152],113:[2,152],121:[2,152],129:[2,152],131:[2,152],132:[2,152],135:[2,152],136:[2,152],137:[2,152],138:[2,152],139:[2,152],140:[2,152]},{1:[2,157],6:[2,157],28:[2,157],29:[2,157],52:[2,157],57:[2,157],60:[2,157],75:[2,157],80:[2,157],89:[2,157],94:[2,157],96:[2,157],105:[2,157],107:[2,157],108:[2,157],109:[2,157],113:[2,157],121:[2,157],129:[2,157],131:[2,157],132:[2,157],135:[2,157],136:[2,157],137:[2,157],138:[2,157],139:[2,157],140:[2,157]},{8:189,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,151],6:[2,151],28:[2,151],29:[2,151],52:[2,151],57:[2,151],60:[2,151],75:[2,151],80:[2,151],89:[2,151],94:[2,151],96:[2,151],105:[2,151],107:[2,151],108:[2,151],109:[2,151],113:[2,151],121:[2,151],129:[2,151],131:[2,151],132:[2,151],135:[2,151],136:[2,151],137:[2,151],138:[2,151],139:[2,151],140:[2,151]},{1:[2,156],6:[2,156],28:[2,156],29:[2,156],52:[2,156],57:[2,156],60:[2,156],75:[2,156],80:[2,156],89:[2,156],94:[2,156],96:[2,156],105:[2,156],107:[2,156],108:[2,156],109:[2,156],113:[2,156],121:[2,156],129:[2,156],131:[2,156],132:[2,156],135:[2,156],136:[2,156],137:[2,156],138:[2,156],139:[2,156],140:[2,156]},{84:190,88:[1,109]},{1:[2,73],6:[2,73],28:[2,73],29:[2,73],43:[2,73],52:[2,73],57:[2,73],60:[2,73],69:[2,73],70:[2,73],71:[2,73],73:[2,73],75:[2,73],76:[2,73],80:[2,73],82:[2,73],87:[2,73],88:[2,73],89:[2,73],94:[2,73],96:[2,73],105:[2,73],107:[2,73],108:[2,73],109:[2,73],113:[2,73],121:[2,73],129:[2,73],131:[2,73],132:[2,73],133:[2,73],134:[2,73],135:[2,73],136:[2,73],137:[2,73],138:[2,73],139:[2,73],140:[2,73],141:[2,73]},{88:[2,114]},{27:192,30:191,31:[1,77],86:[1,47]},{30:193,31:[1,77]},{1:[2,88],6:[2,88],28:[2,88],29:[2,88],30:194,31:[1,77],43:[2,88],52:[2,88],57:[2,88],60:[2,88],69:[2,88],70:[2,88],71:[2,88],73:[2,88],75:[2,88],76:[2,88],80:[2,88],82:[2,88],87:[2,88],88:[2,88],89:[2,88],94:[2,88],96:[2,88],105:[2,88],107:[2,88],108:[2,88],109:[2,88],113:[2,88],121:[2,88],129:[2,88],131:[2,88],132:[2,88],133:[2,88],134:[2,88],135:[2,88],136:[2,88],137:[2,88],138:[2,88],139:[2,88],140:[2,88],141:[2,88]},{1:[2,89],6:[2,89],28:[2,89],29:[2,89],43:[2,89],52:[2,89],57:[2,89],60:[2,89],69:[2,89],70:[2,89],71:[2,89],73:[2,89],75:[2,89],76:[2,89],80:[2,89],82:[2,89],87:[2,89],88:[2,89],89:[2,89],94:[2,89],96:[2,89],105:[2,89],107:[2,89],108:[2,89],109:[2,89],113:[2,89],121:[2,89],129:[2,89],131:[2,89],132:[2,89],133:[2,89],134:[2,89],135:[2,89],136:[2,89],137:[2,89],138:[2,89],139:[2,89],140:[2,89],141:[2,89]},{8:196,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],60:[1,200],61:51,62:52,64:38,66:27,67:28,68:29,74:195,77:197,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],95:198,96:[1,199],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{72:201,73:[1,103],76:[1,104]},{84:202,88:[1,109]},{1:[2,74],6:[2,74],28:[2,74],29:[2,74],43:[2,74],52:[2,74],57:[2,74],60:[2,74],69:[2,74],70:[2,74],71:[2,74],73:[2,74],75:[2,74],76:[2,74],80:[2,74],82:[2,74],87:[2,74],88:[2,74],89:[2,74],94:[2,74],96:[2,74],105:[2,74],107:[2,74],108:[2,74],109:[2,74],113:[2,74],121:[2,74],129:[2,74],131:[2,74],132:[2,74],133:[2,74],134:[2,74],135:[2,74],136:[2,74],137:[2,74],138:[2,74],139:[2,74],140:[2,74],141:[2,74]},{6:[1,204],8:203,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,205],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,111],6:[2,111],28:[2,111],29:[2,111],52:[2,111],57:[2,111],60:[2,111],69:[2,111],70:[2,111],71:[2,111],73:[2,111],75:[2,111],76:[2,111],80:[2,111],87:[2,111],88:[2,111],89:[2,111],94:[2,111],96:[2,111],105:[2,111],107:[2,111],108:[2,111],109:[2,111],113:[2,111],121:[2,111],129:[2,111],131:[2,111],132:[2,111],135:[2,111],136:[2,111],137:[2,111],138:[2,111],139:[2,111],140:[2,111]},{8:208,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,153],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],89:[1,206],90:207,91:[1,62],92:[1,63],93:[1,61],97:152,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,57],28:[2,57],52:[1,209],56:211,57:[1,210]},{6:[2,60],28:[2,60],29:[2,60],52:[2,60],57:[2,60]},{6:[2,64],28:[2,64],29:[2,64],43:[1,213],52:[2,64],57:[2,64],60:[1,212]},{6:[2,67],28:[2,67],29:[2,67],43:[2,67],52:[2,67],57:[2,67],60:[2,67]},{6:[2,68],28:[2,68],29:[2,68],43:[2,68],52:[2,68],57:[2,68],60:[2,68]},{6:[2,69],28:[2,69],29:[2,69],43:[2,69],52:[2,69],57:[2,69],60:[2,69]},{6:[2,70],28:[2,70],29:[2,70],43:[2,70],52:[2,70],57:[2,70],60:[2,70]},{30:155,31:[1,77]},{8:208,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,153],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],90:151,91:[1,62],92:[1,63],93:[1,61],94:[1,150],97:152,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,54],6:[2,54],28:[2,54],29:[2,54],52:[2,54],57:[2,54],60:[2,54],75:[2,54],80:[2,54],89:[2,54],94:[2,54],96:[2,54],105:[2,54],107:[2,54],108:[2,54],109:[2,54],113:[2,54],121:[2,54],129:[2,54],131:[2,54],132:[2,54],135:[2,54],136:[2,54],137:[2,54],138:[2,54],139:[2,54],140:[2,54]},{1:[2,190],6:[2,190],28:[2,190],29:[2,190],52:[2,190],57:[2,190],60:[2,190],75:[2,190],80:[2,190],89:[2,190],94:[2,190],96:[2,190],105:[2,190],106:91,107:[2,190],108:[2,190],109:[2,190],112:92,113:[2,190],114:73,121:[2,190],129:[2,190],131:[2,190],132:[2,190],135:[1,82],136:[2,190],137:[2,190],138:[2,190],139:[2,190],140:[2,190]},{106:94,107:[1,69],109:[1,70],112:95,113:[1,72],114:73,129:[1,93]},{1:[2,191],6:[2,191],28:[2,191],29:[2,191],52:[2,191],57:[2,191],60:[2,191],75:[2,191],80:[2,191],89:[2,191],94:[2,191],96:[2,191],105:[2,191],106:91,107:[2,191],108:[2,191],109:[2,191],112:92,113:[2,191],114:73,121:[2,191],129:[2,191],131:[2,191],132:[2,191],135:[1,82],136:[2,191],137:[2,191],138:[2,191],139:[2,191],140:[2,191]},{1:[2,192],6:[2,192],28:[2,192],29:[2,192],52:[2,192],57:[2,192],60:[2,192],75:[2,192],80:[2,192],89:[2,192],94:[2,192],96:[2,192],105:[2,192],106:91,107:[2,192],108:[2,192],109:[2,192],112:92,113:[2,192],114:73,121:[2,192],129:[2,192],131:[2,192],132:[2,192],135:[1,82],136:[2,192],137:[2,192],138:[2,192],139:[2,192],140:[2,192]},{1:[2,193],6:[2,193],28:[2,193],29:[2,193],52:[2,193],57:[2,193],60:[2,193],69:[2,76],70:[2,76],71:[2,76],73:[2,76],75:[2,193],76:[2,76],80:[2,193],87:[2,76],88:[2,76],89:[2,193],94:[2,193],96:[2,193],105:[2,193],107:[2,193],108:[2,193],109:[2,193],113:[2,193],121:[2,193],129:[2,193],131:[2,193],132:[2,193],135:[2,193],136:[2,193],137:[2,193],138:[2,193],139:[2,193],140:[2,193]},{65:97,69:[1,99],70:[1,100],71:[1,101],72:102,73:[1,103],76:[1,104],83:96,87:[1,98],88:[2,113]},{65:106,69:[1,99],70:[1,100],71:[1,101],72:102,73:[1,103],76:[1,104],83:105,87:[1,98],88:[2,113]},{69:[2,79],70:[2,79],71:[2,79],73:[2,79],76:[2,79],87:[2,79],88:[2,79]},{1:[2,194],6:[2,194],28:[2,194],29:[2,194],52:[2,194],57:[2,194],60:[2,194],69:[2,76],70:[2,76],71:[2,76],73:[2,76],75:[2,194],76:[2,76],80:[2,194],87:[2,76],88:[2,76],89:[2,194],94:[2,194],96:[2,194],105:[2,194],107:[2,194],108:[2,194],109:[2,194],113:[2,194],121:[2,194],129:[2,194],131:[2,194],132:[2,194],135:[2,194],136:[2,194],137:[2,194],138:[2,194],139:[2,194],140:[2,194]},{1:[2,195],6:[2,195],28:[2,195],29:[2,195],52:[2,195],57:[2,195],60:[2,195],75:[2,195],80:[2,195],89:[2,195],94:[2,195],96:[2,195],105:[2,195],107:[2,195],108:[2,195],109:[2,195],113:[2,195],121:[2,195],129:[2,195],131:[2,195],132:[2,195],135:[2,195],136:[2,195],137:[2,195],138:[2,195],139:[2,195],140:[2,195]},{1:[2,196],6:[2,196],28:[2,196],29:[2,196],52:[2,196],57:[2,196],60:[2,196],75:[2,196],80:[2,196],89:[2,196],94:[2,196],96:[2,196],105:[2,196],107:[2,196],108:[2,196],109:[2,196],113:[2,196],121:[2,196],129:[2,196],131:[2,196],132:[2,196],135:[2,196],136:[2,196],137:[2,196],138:[2,196],139:[2,196],140:[2,196]},{8:214,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,215],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:216,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{5:217,28:[1,5],128:[1,218]},{1:[2,138],6:[2,138],28:[2,138],29:[2,138],52:[2,138],57:[2,138],60:[2,138],75:[2,138],80:[2,138],89:[2,138],94:[2,138],96:[2,138],100:219,101:[1,220],102:[1,221],105:[2,138],107:[2,138],108:[2,138],109:[2,138],113:[2,138],121:[2,138],129:[2,138],131:[2,138],132:[2,138],135:[2,138],136:[2,138],137:[2,138],138:[2,138],139:[2,138],140:[2,138]},{1:[2,150],6:[2,150],28:[2,150],29:[2,150],52:[2,150],57:[2,150],60:[2,150],75:[2,150],80:[2,150],89:[2,150],94:[2,150],96:[2,150],105:[2,150],107:[2,150],108:[2,150],109:[2,150],113:[2,150],121:[2,150],129:[2,150],131:[2,150],132:[2,150],135:[2,150],136:[2,150],137:[2,150],138:[2,150],139:[2,150],140:[2,150]},{1:[2,158],6:[2,158],28:[2,158],29:[2,158],52:[2,158],57:[2,158],60:[2,158],75:[2,158],80:[2,158],89:[2,158],94:[2,158],96:[2,158],105:[2,158],107:[2,158],108:[2,158],109:[2,158],113:[2,158],121:[2,158],129:[2,158],131:[2,158],132:[2,158],135:[2,158],136:[2,158],137:[2,158],138:[2,158],139:[2,158],140:[2,158]},{28:[1,222],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{123:223,125:224,126:[1,225]},{1:[2,101],6:[2,101],28:[2,101],29:[2,101],52:[2,101],57:[2,101],60:[2,101],75:[2,101],80:[2,101],89:[2,101],94:[2,101],96:[2,101],105:[2,101],107:[2,101],108:[2,101],109:[2,101],113:[2,101],121:[2,101],129:[2,101],131:[2,101],132:[2,101],135:[2,101],136:[2,101],137:[2,101],138:[2,101],139:[2,101],140:[2,101]},{8:226,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,104],5:227,6:[2,104],28:[1,5],29:[2,104],52:[2,104],57:[2,104],60:[2,104],69:[2,76],70:[2,76],71:[2,76],73:[2,76],75:[2,104],76:[2,76],80:[2,104],82:[1,228],87:[2,76],88:[2,76],89:[2,104],94:[2,104],96:[2,104],105:[2,104],107:[2,104],108:[2,104],109:[2,104],113:[2,104],121:[2,104],129:[2,104],131:[2,104],132:[2,104],135:[2,104],136:[2,104],137:[2,104],138:[2,104],139:[2,104],140:[2,104]},{1:[2,143],6:[2,143],28:[2,143],29:[2,143],52:[2,143],57:[2,143],60:[2,143],75:[2,143],80:[2,143],89:[2,143],94:[2,143],96:[2,143],105:[2,143],106:91,107:[2,143],108:[2,143],109:[2,143],112:92,113:[2,143],114:73,121:[2,143],129:[2,143],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,112],6:[2,112],28:[2,112],29:[2,112],43:[2,112],52:[2,112],57:[2,112],60:[2,112],69:[2,112],70:[2,112],71:[2,112],73:[2,112],75:[2,112],76:[2,112],80:[2,112],82:[2,112],87:[2,112],88:[2,112],89:[2,112],94:[2,112],96:[2,112],105:[2,112],107:[2,112],108:[2,112],109:[2,112],113:[2,112],121:[2,112],129:[2,112],131:[2,112],132:[2,112],133:[2,112],134:[2,112],135:[2,112],136:[2,112],137:[2,112],138:[2,112],139:[2,112],140:[2,112],141:[2,112]},{1:[2,12],6:[2,12],28:[2,12],29:[2,12],52:[2,12],57:[2,12],60:[2,12],75:[2,12],80:[2,12],89:[2,12],94:[2,12],96:[2,12],105:[2,12],107:[2,12],108:[2,12],109:[2,12],113:[2,12],121:[2,12],129:[2,12],131:[2,12],132:[2,12],135:[2,12],136:[2,12],137:[2,12],138:[2,12],139:[2,12],140:[2,12]},{1:[2,13],6:[2,13],28:[2,13],29:[2,13],52:[2,13],57:[2,13],60:[2,13],75:[2,13],80:[2,13],89:[2,13],94:[2,13],96:[2,13],105:[2,13],106:91,107:[1,69],108:[2,13],109:[1,70],112:92,113:[1,72],114:73,121:[2,13],129:[2,13],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,50],6:[2,50],29:[2,50],105:[2,50],106:91,107:[2,50],109:[2,50],112:92,113:[2,50],114:73,129:[2,50],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[1,78],105:[1,229]},{4:230,7:4,8:6,9:7,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,134],28:[2,134],57:[2,134],60:[1,232],94:[2,134],95:231,96:[1,199],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,120],6:[2,120],28:[2,120],29:[2,120],43:[2,120],52:[2,120],57:[2,120],60:[2,120],69:[2,120],70:[2,120],71:[2,120],73:[2,120],75:[2,120],76:[2,120],80:[2,120],87:[2,120],88:[2,120],89:[2,120],94:[2,120],96:[2,120],105:[2,120],107:[2,120],108:[2,120],109:[2,120],113:[2,120],119:[2,120],120:[2,120],121:[2,120],129:[2,120],131:[2,120],132:[2,120],135:[2,120],136:[2,120],137:[2,120],138:[2,120],139:[2,120],140:[2,120]},{6:[2,57],28:[2,57],56:233,57:[1,234],94:[2,57]},{6:[2,129],28:[2,129],29:[2,129],57:[2,129],89:[2,129],94:[2,129]},{8:208,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,153],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],90:235,91:[1,62],92:[1,63],93:[1,61],97:152,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,135],28:[2,135],29:[2,135],57:[2,135],89:[2,135],94:[2,135]},{1:[2,119],6:[2,119],28:[2,119],29:[2,119],43:[2,119],46:[2,119],52:[2,119],57:[2,119],60:[2,119],69:[2,119],70:[2,119],71:[2,119],73:[2,119],75:[2,119],76:[2,119],80:[2,119],82:[2,119],87:[2,119],88:[2,119],89:[2,119],94:[2,119],96:[2,119],105:[2,119],107:[2,119],108:[2,119],109:[2,119],113:[2,119],119:[2,119],120:[2,119],121:[2,119],129:[2,119],131:[2,119],132:[2,119],133:[2,119],134:[2,119],135:[2,119],136:[2,119],137:[2,119],138:[2,119],139:[2,119],140:[2,119],141:[2,119]},{5:236,28:[1,5],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,146],6:[2,146],28:[2,146],29:[2,146],52:[2,146],57:[2,146],60:[2,146],75:[2,146],80:[2,146],89:[2,146],94:[2,146],96:[2,146],105:[2,146],106:91,107:[1,69],108:[1,237],109:[1,70],112:92,113:[1,72],114:73,121:[2,146],129:[2,146],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,148],6:[2,148],28:[2,148],29:[2,148],52:[2,148],57:[2,148],60:[2,148],75:[2,148],80:[2,148],89:[2,148],94:[2,148],96:[2,148],105:[2,148],106:91,107:[1,69],108:[1,238],109:[1,70],112:92,113:[1,72],114:73,121:[2,148],129:[2,148],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,154],6:[2,154],28:[2,154],29:[2,154],52:[2,154],57:[2,154],60:[2,154],75:[2,154],80:[2,154],89:[2,154],94:[2,154],96:[2,154],105:[2,154],107:[2,154],108:[2,154],109:[2,154],113:[2,154],121:[2,154],129:[2,154],131:[2,154],132:[2,154],135:[2,154],136:[2,154],137:[2,154],138:[2,154],139:[2,154],140:[2,154]},{1:[2,155],6:[2,155],28:[2,155],29:[2,155],52:[2,155],57:[2,155],60:[2,155],75:[2,155],80:[2,155],89:[2,155],94:[2,155],96:[2,155],105:[2,155],106:91,107:[1,69],108:[2,155],109:[1,70],112:92,113:[1,72],114:73,121:[2,155],129:[2,155],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,159],6:[2,159],28:[2,159],29:[2,159],52:[2,159],57:[2,159],60:[2,159],75:[2,159],80:[2,159],89:[2,159],94:[2,159],96:[2,159],105:[2,159],107:[2,159],108:[2,159],109:[2,159],113:[2,159],121:[2,159],129:[2,159],131:[2,159],132:[2,159],135:[2,159],136:[2,159],137:[2,159],138:[2,159],139:[2,159],140:[2,159]},{119:[2,161],120:[2,161]},{30:165,31:[1,77],47:166,61:167,62:168,78:[1,74],92:[1,117],93:[1,118],116:239,118:164},{57:[1,240],119:[2,167],120:[2,167]},{57:[2,163],119:[2,163],120:[2,163]},{57:[2,164],119:[2,164],120:[2,164]},{57:[2,165],119:[2,165],120:[2,165]},{57:[2,166],119:[2,166],120:[2,166]},{1:[2,160],6:[2,160],28:[2,160],29:[2,160],52:[2,160],57:[2,160],60:[2,160],75:[2,160],80:[2,160],89:[2,160],94:[2,160],96:[2,160],105:[2,160],107:[2,160],108:[2,160],109:[2,160],113:[2,160],121:[2,160],129:[2,160],131:[2,160],132:[2,160],135:[2,160],136:[2,160],137:[2,160],138:[2,160],139:[2,160],140:[2,160]},{8:241,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:242,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,57],28:[2,57],56:243,57:[1,244],80:[2,57]},{6:[2,96],28:[2,96],29:[2,96],57:[2,96],80:[2,96]},{6:[2,43],28:[2,43],29:[2,43],46:[1,245],57:[2,43],80:[2,43]},{6:[2,46],28:[2,46],29:[2,46],57:[2,46],80:[2,46]},{6:[2,47],28:[2,47],29:[2,47],46:[2,47],57:[2,47],80:[2,47]},{6:[2,48],28:[2,48],29:[2,48],46:[2,48],57:[2,48],80:[2,48]},{6:[2,49],28:[2,49],29:[2,49],46:[2,49],57:[2,49],80:[2,49]},{1:[2,5],6:[2,5],29:[2,5],105:[2,5]},{1:[2,29],6:[2,29],28:[2,29],29:[2,29],52:[2,29],57:[2,29],60:[2,29],75:[2,29],80:[2,29],89:[2,29],94:[2,29],96:[2,29],101:[2,29],102:[2,29],105:[2,29],107:[2,29],108:[2,29],109:[2,29],113:[2,29],121:[2,29],124:[2,29],126:[2,29],129:[2,29],131:[2,29],132:[2,29],135:[2,29],136:[2,29],137:[2,29],138:[2,29],139:[2,29],140:[2,29]},{1:[2,198],6:[2,198],28:[2,198],29:[2,198],52:[2,198],57:[2,198],60:[2,198],75:[2,198],80:[2,198],89:[2,198],94:[2,198],96:[2,198],105:[2,198],106:91,107:[2,198],108:[2,198],109:[2,198],112:92,113:[2,198],114:73,121:[2,198],129:[2,198],131:[2,198],132:[2,198],135:[1,82],136:[1,85],137:[2,198],138:[2,198],139:[2,198],140:[2,198]},{1:[2,199],6:[2,199],28:[2,199],29:[2,199],52:[2,199],57:[2,199],60:[2,199],75:[2,199],80:[2,199],89:[2,199],94:[2,199],96:[2,199],105:[2,199],106:91,107:[2,199],108:[2,199],109:[2,199],112:92,113:[2,199],114:73,121:[2,199],129:[2,199],131:[2,199],132:[2,199],135:[1,82],136:[1,85],137:[2,199],138:[2,199],139:[2,199],140:[2,199]},{1:[2,200],6:[2,200],28:[2,200],29:[2,200],52:[2,200],57:[2,200],60:[2,200],75:[2,200],80:[2,200],89:[2,200],94:[2,200],96:[2,200],105:[2,200],106:91,107:[2,200],108:[2,200],109:[2,200],112:92,113:[2,200],114:73,121:[2,200],129:[2,200],131:[2,200],132:[2,200],135:[1,82],136:[2,200],137:[2,200],138:[2,200],139:[2,200],140:[2,200]},{1:[2,201],6:[2,201],28:[2,201],29:[2,201],52:[2,201],57:[2,201],60:[2,201],75:[2,201],80:[2,201],89:[2,201],94:[2,201],96:[2,201],105:[2,201],106:91,107:[2,201],108:[2,201],109:[2,201],112:92,113:[2,201],114:73,121:[2,201],129:[2,201],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[2,201],138:[2,201],139:[2,201],140:[2,201]},{1:[2,202],6:[2,202],28:[2,202],29:[2,202],52:[2,202],57:[2,202],60:[2,202],75:[2,202],80:[2,202],89:[2,202],94:[2,202],96:[2,202],105:[2,202],106:91,107:[2,202],108:[2,202],109:[2,202],112:92,113:[2,202],114:73,121:[2,202],129:[2,202],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[2,202],139:[2,202],140:[1,89]},{1:[2,203],6:[2,203],28:[2,203],29:[2,203],52:[2,203],57:[2,203],60:[2,203],75:[2,203],80:[2,203],89:[2,203],94:[2,203],96:[2,203],105:[2,203],106:91,107:[2,203],108:[2,203],109:[2,203],112:92,113:[2,203],114:73,121:[2,203],129:[2,203],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[2,203],140:[1,89]},{1:[2,204],6:[2,204],28:[2,204],29:[2,204],52:[2,204],57:[2,204],60:[2,204],75:[2,204],80:[2,204],89:[2,204],94:[2,204],96:[2,204],105:[2,204],106:91,107:[2,204],108:[2,204],109:[2,204],112:92,113:[2,204],114:73,121:[2,204],129:[2,204],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[2,204],139:[2,204],140:[2,204]},{1:[2,189],6:[2,189],28:[2,189],29:[2,189],52:[2,189],57:[2,189],60:[2,189],75:[2,189],80:[2,189],89:[2,189],94:[2,189],96:[2,189],105:[2,189],106:91,107:[1,69],108:[2,189],109:[1,70],112:92,113:[1,72],114:73,121:[2,189],129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,188],6:[2,188],28:[2,188],29:[2,188],52:[2,188],57:[2,188],60:[2,188],75:[2,188],80:[2,188],89:[2,188],94:[2,188],96:[2,188],105:[2,188],106:91,107:[1,69],108:[2,188],109:[1,70],112:92,113:[1,72],114:73,121:[2,188],129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,108],6:[2,108],28:[2,108],29:[2,108],52:[2,108],57:[2,108],60:[2,108],69:[2,108],70:[2,108],71:[2,108],73:[2,108],75:[2,108],76:[2,108],80:[2,108],87:[2,108],88:[2,108],89:[2,108],94:[2,108],96:[2,108],105:[2,108],107:[2,108],108:[2,108],109:[2,108],113:[2,108],121:[2,108],129:[2,108],131:[2,108],132:[2,108],135:[2,108],136:[2,108],137:[2,108],138:[2,108],139:[2,108],140:[2,108]},{1:[2,84],6:[2,84],28:[2,84],29:[2,84],43:[2,84],52:[2,84],57:[2,84],60:[2,84],69:[2,84],70:[2,84],71:[2,84],73:[2,84],75:[2,84],76:[2,84],80:[2,84],82:[2,84],87:[2,84],88:[2,84],89:[2,84],94:[2,84],96:[2,84],105:[2,84],107:[2,84],108:[2,84],109:[2,84],113:[2,84],121:[2,84],129:[2,84],131:[2,84],132:[2,84],133:[2,84],134:[2,84],135:[2,84],136:[2,84],137:[2,84],138:[2,84],139:[2,84],140:[2,84],141:[2,84]},{1:[2,85],6:[2,85],28:[2,85],29:[2,85],43:[2,85],52:[2,85],57:[2,85],60:[2,85],69:[2,85],70:[2,85],71:[2,85],73:[2,85],75:[2,85],76:[2,85],80:[2,85],82:[2,85],87:[2,85],88:[2,85],89:[2,85],94:[2,85],96:[2,85],105:[2,85],107:[2,85],108:[2,85],109:[2,85],113:[2,85],121:[2,85],129:[2,85],131:[2,85],132:[2,85],133:[2,85],134:[2,85],135:[2,85],136:[2,85],137:[2,85],138:[2,85],139:[2,85],140:[2,85],141:[2,85]},{1:[2,86],6:[2,86],28:[2,86],29:[2,86],43:[2,86],52:[2,86],57:[2,86],60:[2,86],69:[2,86],70:[2,86],71:[2,86],73:[2,86],75:[2,86],76:[2,86],80:[2,86],82:[2,86],87:[2,86],88:[2,86],89:[2,86],94:[2,86],96:[2,86],105:[2,86],107:[2,86],108:[2,86],109:[2,86],113:[2,86],121:[2,86],129:[2,86],131:[2,86],132:[2,86],133:[2,86],134:[2,86],135:[2,86],136:[2,86],137:[2,86],138:[2,86],139:[2,86],140:[2,86],141:[2,86]},{1:[2,87],6:[2,87],28:[2,87],29:[2,87],43:[2,87],52:[2,87],57:[2,87],60:[2,87],69:[2,87],70:[2,87],71:[2,87],73:[2,87],75:[2,87],76:[2,87],80:[2,87],82:[2,87],87:[2,87],88:[2,87],89:[2,87],94:[2,87],96:[2,87],105:[2,87],107:[2,87],108:[2,87],109:[2,87],113:[2,87],121:[2,87],129:[2,87],131:[2,87],132:[2,87],133:[2,87],134:[2,87],135:[2,87],136:[2,87],137:[2,87],138:[2,87],139:[2,87],140:[2,87],141:[2,87]},{75:[1,246]},{60:[1,200],75:[2,92],95:247,96:[1,199],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{75:[2,93]},{8:248,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,75:[2,128],78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{12:[2,122],14:[2,122],31:[2,122],33:[2,122],34:[2,122],36:[2,122],37:[2,122],38:[2,122],39:[2,122],40:[2,122],41:[2,122],48:[2,122],49:[2,122],50:[2,122],54:[2,122],55:[2,122],75:[2,122],78:[2,122],81:[2,122],85:[2,122],86:[2,122],91:[2,122],92:[2,122],93:[2,122],99:[2,122],103:[2,122],104:[2,122],107:[2,122],109:[2,122],111:[2,122],113:[2,122],122:[2,122],128:[2,122],130:[2,122],131:[2,122],132:[2,122],133:[2,122],134:[2,122]},{12:[2,123],14:[2,123],31:[2,123],33:[2,123],34:[2,123],36:[2,123],37:[2,123],38:[2,123],39:[2,123],40:[2,123],41:[2,123],48:[2,123],49:[2,123],50:[2,123],54:[2,123],55:[2,123],75:[2,123],78:[2,123],81:[2,123],85:[2,123],86:[2,123],91:[2,123],92:[2,123],93:[2,123],99:[2,123],103:[2,123],104:[2,123],107:[2,123],109:[2,123],111:[2,123],113:[2,123],122:[2,123],128:[2,123],130:[2,123],131:[2,123],132:[2,123],133:[2,123],134:[2,123]},{1:[2,91],6:[2,91],28:[2,91],29:[2,91],43:[2,91],52:[2,91],57:[2,91],60:[2,91],69:[2,91],70:[2,91],71:[2,91],73:[2,91],75:[2,91],76:[2,91],80:[2,91],82:[2,91],87:[2,91],88:[2,91],89:[2,91],94:[2,91],96:[2,91],105:[2,91],107:[2,91],108:[2,91],109:[2,91],113:[2,91],121:[2,91],129:[2,91],131:[2,91],132:[2,91],133:[2,91],134:[2,91],135:[2,91],136:[2,91],137:[2,91],138:[2,91],139:[2,91],140:[2,91],141:[2,91]},{1:[2,109],6:[2,109],28:[2,109],29:[2,109],52:[2,109],57:[2,109],60:[2,109],69:[2,109],70:[2,109],71:[2,109],73:[2,109],75:[2,109],76:[2,109],80:[2,109],87:[2,109],88:[2,109],89:[2,109],94:[2,109],96:[2,109],105:[2,109],107:[2,109],108:[2,109],109:[2,109],113:[2,109],121:[2,109],129:[2,109],131:[2,109],132:[2,109],135:[2,109],136:[2,109],137:[2,109],138:[2,109],139:[2,109],140:[2,109]},{1:[2,40],6:[2,40],28:[2,40],29:[2,40],52:[2,40],57:[2,40],60:[2,40],75:[2,40],80:[2,40],89:[2,40],94:[2,40],96:[2,40],105:[2,40],106:91,107:[2,40],108:[2,40],109:[2,40],112:92,113:[2,40],114:73,121:[2,40],129:[2,40],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{8:249,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:250,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,115],6:[2,115],28:[2,115],29:[2,115],43:[2,115],52:[2,115],57:[2,115],60:[2,115],69:[2,115],70:[2,115],71:[2,115],73:[2,115],75:[2,115],76:[2,115],80:[2,115],82:[2,115],87:[2,115],88:[2,115],89:[2,115],94:[2,115],96:[2,115],105:[2,115],107:[2,115],108:[2,115],109:[2,115],113:[2,115],121:[2,115],129:[2,115],131:[2,115],132:[2,115],133:[2,115],134:[2,115],135:[2,115],136:[2,115],137:[2,115],138:[2,115],139:[2,115],140:[2,115],141:[2,115]},{6:[2,57],28:[2,57],56:251,57:[1,234],89:[2,57]},{6:[2,134],28:[2,134],29:[2,134],57:[2,134],60:[1,252],89:[2,134],94:[2,134],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{53:253,54:[1,64],55:[1,65]},{6:[2,58],28:[2,58],29:[2,58],30:113,31:[1,77],47:114,58:254,59:112,61:115,62:116,78:[1,74],92:[1,117],93:[1,118]},{6:[1,255],28:[1,256]},{6:[2,65],28:[2,65],29:[2,65],52:[2,65],57:[2,65]},{8:257,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,205],6:[2,205],28:[2,205],29:[2,205],52:[2,205],57:[2,205],60:[2,205],75:[2,205],80:[2,205],89:[2,205],94:[2,205],96:[2,205],105:[2,205],106:91,107:[2,205],108:[2,205],109:[2,205],112:92,113:[2,205],114:73,121:[2,205],129:[2,205],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{8:258,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,207],6:[2,207],28:[2,207],29:[2,207],52:[2,207],57:[2,207],60:[2,207],75:[2,207],80:[2,207],89:[2,207],94:[2,207],96:[2,207],105:[2,207],106:91,107:[2,207],108:[2,207],109:[2,207],112:92,113:[2,207],114:73,121:[2,207],129:[2,207],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,187],6:[2,187],28:[2,187],29:[2,187],52:[2,187],57:[2,187],60:[2,187],75:[2,187],80:[2,187],89:[2,187],94:[2,187],96:[2,187],105:[2,187],107:[2,187],108:[2,187],109:[2,187],113:[2,187],121:[2,187],129:[2,187],131:[2,187],132:[2,187],135:[2,187],136:[2,187],137:[2,187],138:[2,187],139:[2,187],140:[2,187]},{8:259,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,139],6:[2,139],28:[2,139],29:[2,139],52:[2,139],57:[2,139],60:[2,139],75:[2,139],80:[2,139],89:[2,139],94:[2,139],96:[2,139],101:[1,260],105:[2,139],107:[2,139],108:[2,139],109:[2,139],113:[2,139],121:[2,139],129:[2,139],131:[2,139],132:[2,139],135:[2,139],136:[2,139],137:[2,139],138:[2,139],139:[2,139],140:[2,139]},{5:261,28:[1,5]},{30:262,31:[1,77]},{123:263,125:224,126:[1,225]},{29:[1,264],124:[1,265],125:266,126:[1,225]},{29:[2,180],124:[2,180],126:[2,180]},{8:268,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],98:267,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,102],5:269,6:[2,102],28:[1,5],29:[2,102],52:[2,102],57:[2,102],60:[2,102],75:[2,102],80:[2,102],89:[2,102],94:[2,102],96:[2,102],105:[2,102],106:91,107:[1,69],108:[2,102],109:[1,70],112:92,113:[1,72],114:73,121:[2,102],129:[2,102],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,105],6:[2,105],28:[2,105],29:[2,105],52:[2,105],57:[2,105],60:[2,105],75:[2,105],80:[2,105],89:[2,105],94:[2,105],96:[2,105],105:[2,105],107:[2,105],108:[2,105],109:[2,105],113:[2,105],121:[2,105],129:[2,105],131:[2,105],132:[2,105],135:[2,105],136:[2,105],137:[2,105],138:[2,105],139:[2,105],140:[2,105]},{8:270,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,144],6:[2,144],28:[2,144],29:[2,144],52:[2,144],57:[2,144],60:[2,144],69:[2,144],70:[2,144],71:[2,144],73:[2,144],75:[2,144],76:[2,144],80:[2,144],87:[2,144],88:[2,144],89:[2,144],94:[2,144],96:[2,144],105:[2,144],107:[2,144],108:[2,144],109:[2,144],113:[2,144],121:[2,144],129:[2,144],131:[2,144],132:[2,144],135:[2,144],136:[2,144],137:[2,144],138:[2,144],139:[2,144],140:[2,144]},{6:[1,78],29:[1,271]},{8:272,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,71],12:[2,123],14:[2,123],28:[2,71],31:[2,123],33:[2,123],34:[2,123],36:[2,123],37:[2,123],38:[2,123],39:[2,123],40:[2,123],41:[2,123],48:[2,123],49:[2,123],50:[2,123],54:[2,123],55:[2,123],57:[2,71],78:[2,123],81:[2,123],85:[2,123],86:[2,123],91:[2,123],92:[2,123],93:[2,123],94:[2,71],99:[2,123],103:[2,123],104:[2,123],107:[2,123],109:[2,123],111:[2,123],113:[2,123],122:[2,123],128:[2,123],130:[2,123],131:[2,123],132:[2,123],133:[2,123],134:[2,123]},{6:[1,274],28:[1,275],94:[1,273]},{6:[2,58],8:208,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[2,58],29:[2,58],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],89:[2,58],91:[1,62],92:[1,63],93:[1,61],94:[2,58],97:276,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,57],28:[2,57],29:[2,57],56:277,57:[1,234]},{1:[2,184],6:[2,184],28:[2,184],29:[2,184],52:[2,184],57:[2,184],60:[2,184],75:[2,184],80:[2,184],89:[2,184],94:[2,184],96:[2,184],105:[2,184],107:[2,184],108:[2,184],109:[2,184],113:[2,184],121:[2,184],124:[2,184],129:[2,184],131:[2,184],132:[2,184],135:[2,184],136:[2,184],137:[2,184],138:[2,184],139:[2,184],140:[2,184]},{8:278,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:279,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{119:[2,162],120:[2,162]},{30:165,31:[1,77],47:166,61:167,62:168,78:[1,74],92:[1,117],93:[1,118],118:280},{1:[2,169],6:[2,169],28:[2,169],29:[2,169],52:[2,169],57:[2,169],60:[2,169],75:[2,169],80:[2,169],89:[2,169],94:[2,169],96:[2,169],105:[2,169],106:91,107:[2,169],108:[1,281],109:[2,169],112:92,113:[2,169],114:73,121:[1,282],129:[2,169],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,170],6:[2,170],28:[2,170],29:[2,170],52:[2,170],57:[2,170],60:[2,170],75:[2,170],80:[2,170],89:[2,170],94:[2,170],96:[2,170],105:[2,170],106:91,107:[2,170],108:[1,283],109:[2,170],112:92,113:[2,170],114:73,121:[2,170],129:[2,170],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[1,285],28:[1,286],80:[1,284]},{6:[2,58],11:175,28:[2,58],29:[2,58],30:176,31:[1,77],32:177,33:[1,75],34:[1,76],44:287,45:174,47:178,49:[1,50],80:[2,58],92:[1,117]},{8:288,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,289],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,90],6:[2,90],28:[2,90],29:[2,90],43:[2,90],52:[2,90],57:[2,90],60:[2,90],69:[2,90],70:[2,90],71:[2,90],73:[2,90],75:[2,90],76:[2,90],80:[2,90],82:[2,90],87:[2,90],88:[2,90],89:[2,90],94:[2,90],96:[2,90],105:[2,90],107:[2,90],108:[2,90],109:[2,90],113:[2,90],121:[2,90],129:[2,90],131:[2,90],132:[2,90],133:[2,90],134:[2,90],135:[2,90],136:[2,90],137:[2,90],138:[2,90],139:[2,90],140:[2,90],141:[2,90]},{8:290,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,75:[2,126],78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{75:[2,127],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,41],6:[2,41],28:[2,41],29:[2,41],52:[2,41],57:[2,41],60:[2,41],75:[2,41],80:[2,41],89:[2,41],94:[2,41],96:[2,41],105:[2,41],106:91,107:[2,41],108:[2,41],109:[2,41],112:92,113:[2,41],114:73,121:[2,41],129:[2,41],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{29:[1,291],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[1,274],28:[1,275],89:[1,292]},{6:[2,71],28:[2,71],29:[2,71],57:[2,71],89:[2,71],94:[2,71]},{5:293,28:[1,5]},{6:[2,61],28:[2,61],29:[2,61],52:[2,61],57:[2,61]},{30:113,31:[1,77],47:114,58:294,59:112,61:115,62:116,78:[1,74],92:[1,117],93:[1,118]},{6:[2,59],28:[2,59],29:[2,59],30:113,31:[1,77],47:114,51:295,57:[2,59],58:111,59:112,61:115,62:116,78:[1,74],92:[1,117],93:[1,118]},{6:[2,66],28:[2,66],29:[2,66],52:[2,66],57:[2,66],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{29:[1,296],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{5:297,28:[1,5],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{5:298,28:[1,5]},{1:[2,140],6:[2,140],28:[2,140],29:[2,140],52:[2,140],57:[2,140],60:[2,140],75:[2,140],80:[2,140],89:[2,140],94:[2,140],96:[2,140],105:[2,140],107:[2,140],108:[2,140],109:[2,140],113:[2,140],121:[2,140],129:[2,140],131:[2,140],132:[2,140],135:[2,140],136:[2,140],137:[2,140],138:[2,140],139:[2,140],140:[2,140]},{5:299,28:[1,5]},{29:[1,300],124:[1,301],125:266,126:[1,225]},{1:[2,178],6:[2,178],28:[2,178],29:[2,178],52:[2,178],57:[2,178],60:[2,178],75:[2,178],80:[2,178],89:[2,178],94:[2,178],96:[2,178],105:[2,178],107:[2,178],108:[2,178],109:[2,178],113:[2,178],121:[2,178],129:[2,178],131:[2,178],132:[2,178],135:[2,178],136:[2,178],137:[2,178],138:[2,178],139:[2,178],140:[2,178]},{5:302,28:[1,5]},{29:[2,181],124:[2,181],126:[2,181]},{5:303,28:[1,5],57:[1,304]},{28:[2,136],57:[2,136],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,103],6:[2,103],28:[2,103],29:[2,103],52:[2,103],57:[2,103],60:[2,103],75:[2,103],80:[2,103],89:[2,103],94:[2,103],96:[2,103],105:[2,103],107:[2,103],108:[2,103],109:[2,103],113:[2,103],121:[2,103],129:[2,103],131:[2,103],132:[2,103],135:[2,103],136:[2,103],137:[2,103],138:[2,103],139:[2,103],140:[2,103]},{1:[2,106],5:305,6:[2,106],28:[1,5],29:[2,106],52:[2,106],57:[2,106],60:[2,106],75:[2,106],80:[2,106],89:[2,106],94:[2,106],96:[2,106],105:[2,106],106:91,107:[1,69],108:[2,106],109:[1,70],112:92,113:[1,72],114:73,121:[2,106],129:[2,106],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{105:[1,306]},{94:[1,307],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,121],6:[2,121],28:[2,121],29:[2,121],43:[2,121],52:[2,121],57:[2,121],60:[2,121],69:[2,121],70:[2,121],71:[2,121],73:[2,121],75:[2,121],76:[2,121],80:[2,121],87:[2,121],88:[2,121],89:[2,121],94:[2,121],96:[2,121],105:[2,121],107:[2,121],108:[2,121],109:[2,121],113:[2,121],119:[2,121],120:[2,121],121:[2,121],129:[2,121],131:[2,121],132:[2,121],135:[2,121],136:[2,121],137:[2,121],138:[2,121],139:[2,121],140:[2,121]},{8:208,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],97:308,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:208,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,28:[1,153],30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,63:154,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],90:309,91:[1,62],92:[1,63],93:[1,61],97:152,99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[2,130],28:[2,130],29:[2,130],57:[2,130],89:[2,130],94:[2,130]},{6:[1,274],28:[1,275],29:[1,310]},{1:[2,147],6:[2,147],28:[2,147],29:[2,147],52:[2,147],57:[2,147],60:[2,147],75:[2,147],80:[2,147],89:[2,147],94:[2,147],96:[2,147],105:[2,147],106:91,107:[1,69],108:[2,147],109:[1,70],112:92,113:[1,72],114:73,121:[2,147],129:[2,147],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,149],6:[2,149],28:[2,149],29:[2,149],52:[2,149],57:[2,149],60:[2,149],75:[2,149],80:[2,149],89:[2,149],94:[2,149],96:[2,149],105:[2,149],106:91,107:[1,69],108:[2,149],109:[1,70],112:92,113:[1,72],114:73,121:[2,149],129:[2,149],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{119:[2,168],120:[2,168]},{8:311,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:312,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:313,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,94],6:[2,94],28:[2,94],29:[2,94],43:[2,94],52:[2,94],57:[2,94],60:[2,94],69:[2,94],70:[2,94],71:[2,94],73:[2,94],75:[2,94],76:[2,94],80:[2,94],87:[2,94],88:[2,94],89:[2,94],94:[2,94],96:[2,94],105:[2,94],107:[2,94],108:[2,94],109:[2,94],113:[2,94],119:[2,94],120:[2,94],121:[2,94],129:[2,94],131:[2,94],132:[2,94],135:[2,94],136:[2,94],137:[2,94],138:[2,94],139:[2,94],140:[2,94]},{11:175,30:176,31:[1,77],32:177,33:[1,75],34:[1,76],44:314,45:174,47:178,49:[1,50],92:[1,117]},{6:[2,95],11:175,28:[2,95],29:[2,95],30:176,31:[1,77],32:177,33:[1,75],34:[1,76],44:173,45:174,47:178,49:[1,50],57:[2,95],79:315,92:[1,117]},{6:[2,97],28:[2,97],29:[2,97],57:[2,97],80:[2,97]},{6:[2,44],28:[2,44],29:[2,44],57:[2,44],80:[2,44],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{8:316,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{75:[2,125],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,42],6:[2,42],28:[2,42],29:[2,42],52:[2,42],57:[2,42],60:[2,42],75:[2,42],80:[2,42],89:[2,42],94:[2,42],96:[2,42],105:[2,42],107:[2,42],108:[2,42],109:[2,42],113:[2,42],121:[2,42],129:[2,42],131:[2,42],132:[2,42],135:[2,42],136:[2,42],137:[2,42],138:[2,42],139:[2,42],140:[2,42]},{1:[2,116],6:[2,116],28:[2,116],29:[2,116],43:[2,116],52:[2,116],57:[2,116],60:[2,116],69:[2,116],70:[2,116],71:[2,116],73:[2,116],75:[2,116],76:[2,116],80:[2,116],82:[2,116],87:[2,116],88:[2,116],89:[2,116],94:[2,116],96:[2,116],105:[2,116],107:[2,116],108:[2,116],109:[2,116],113:[2,116],121:[2,116],129:[2,116],131:[2,116],132:[2,116],133:[2,116],134:[2,116],135:[2,116],136:[2,116],137:[2,116],138:[2,116],139:[2,116],140:[2,116],141:[2,116]},{1:[2,53],6:[2,53],28:[2,53],29:[2,53],52:[2,53],57:[2,53],60:[2,53],75:[2,53],80:[2,53],89:[2,53],94:[2,53],96:[2,53],105:[2,53],107:[2,53],108:[2,53],109:[2,53],113:[2,53],121:[2,53],129:[2,53],131:[2,53],132:[2,53],135:[2,53],136:[2,53],137:[2,53],138:[2,53],139:[2,53],140:[2,53]},{6:[2,62],28:[2,62],29:[2,62],52:[2,62],57:[2,62]},{6:[2,57],28:[2,57],29:[2,57],56:317,57:[1,210]},{1:[2,206],6:[2,206],28:[2,206],29:[2,206],52:[2,206],57:[2,206],60:[2,206],75:[2,206],80:[2,206],89:[2,206],94:[2,206],96:[2,206],105:[2,206],107:[2,206],108:[2,206],109:[2,206],113:[2,206],121:[2,206],129:[2,206],131:[2,206],132:[2,206],135:[2,206],136:[2,206],137:[2,206],138:[2,206],139:[2,206],140:[2,206]},{1:[2,185],6:[2,185],28:[2,185],29:[2,185],52:[2,185],57:[2,185],60:[2,185],75:[2,185],80:[2,185],89:[2,185],94:[2,185],96:[2,185],105:[2,185],107:[2,185],108:[2,185],109:[2,185],113:[2,185],121:[2,185],124:[2,185],129:[2,185],131:[2,185],132:[2,185],135:[2,185],136:[2,185],137:[2,185],138:[2,185],139:[2,185],140:[2,185]},{1:[2,141],6:[2,141],28:[2,141],29:[2,141],52:[2,141],57:[2,141],60:[2,141],75:[2,141],80:[2,141],89:[2,141],94:[2,141],96:[2,141],105:[2,141],107:[2,141],108:[2,141],109:[2,141],113:[2,141],121:[2,141],129:[2,141],131:[2,141],132:[2,141],135:[2,141],136:[2,141],137:[2,141],138:[2,141],139:[2,141],140:[2,141]},{1:[2,142],6:[2,142],28:[2,142],29:[2,142],52:[2,142],57:[2,142],60:[2,142],75:[2,142],80:[2,142],89:[2,142],94:[2,142],96:[2,142],101:[2,142],105:[2,142],107:[2,142],108:[2,142],109:[2,142],113:[2,142],121:[2,142],129:[2,142],131:[2,142],132:[2,142],135:[2,142],136:[2,142],137:[2,142],138:[2,142],139:[2,142],140:[2,142]},{1:[2,176],6:[2,176],28:[2,176],29:[2,176],52:[2,176],57:[2,176],60:[2,176],75:[2,176],80:[2,176],89:[2,176],94:[2,176],96:[2,176],105:[2,176],107:[2,176],108:[2,176],109:[2,176],113:[2,176],121:[2,176],129:[2,176],131:[2,176],132:[2,176],135:[2,176],136:[2,176],137:[2,176],138:[2,176],139:[2,176],140:[2,176]},{5:318,28:[1,5]},{29:[1,319]},{6:[1,320],29:[2,182],124:[2,182],126:[2,182]},{8:321,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{1:[2,107],6:[2,107],28:[2,107],29:[2,107],52:[2,107],57:[2,107],60:[2,107],75:[2,107],80:[2,107],89:[2,107],94:[2,107],96:[2,107],105:[2,107],107:[2,107],108:[2,107],109:[2,107],113:[2,107],121:[2,107],129:[2,107],131:[2,107],132:[2,107],135:[2,107],136:[2,107],137:[2,107],138:[2,107],139:[2,107],140:[2,107]},{1:[2,145],6:[2,145],28:[2,145],29:[2,145],52:[2,145],57:[2,145],60:[2,145],69:[2,145],70:[2,145],71:[2,145],73:[2,145],75:[2,145],76:[2,145],80:[2,145],87:[2,145],88:[2,145],89:[2,145],94:[2,145],96:[2,145],105:[2,145],107:[2,145],108:[2,145],109:[2,145],113:[2,145],121:[2,145],129:[2,145],131:[2,145],132:[2,145],135:[2,145],136:[2,145],137:[2,145],138:[2,145],139:[2,145],140:[2,145]},{1:[2,124],6:[2,124],28:[2,124],29:[2,124],52:[2,124],57:[2,124],60:[2,124],69:[2,124],70:[2,124],71:[2,124],73:[2,124],75:[2,124],76:[2,124],80:[2,124],87:[2,124],88:[2,124],89:[2,124],94:[2,124],96:[2,124],105:[2,124],107:[2,124],108:[2,124],109:[2,124],113:[2,124],121:[2,124],129:[2,124],131:[2,124],132:[2,124],135:[2,124],136:[2,124],137:[2,124],138:[2,124],139:[2,124],140:[2,124]},{6:[2,131],28:[2,131],29:[2,131],57:[2,131],89:[2,131],94:[2,131]},{6:[2,57],28:[2,57],29:[2,57],56:322,57:[1,234]},{6:[2,132],28:[2,132],29:[2,132],57:[2,132],89:[2,132],94:[2,132]},{1:[2,171],6:[2,171],28:[2,171],29:[2,171],52:[2,171],57:[2,171],60:[2,171],75:[2,171],80:[2,171],89:[2,171],94:[2,171],96:[2,171],105:[2,171],106:91,107:[2,171],108:[2,171],109:[2,171],112:92,113:[2,171],114:73,121:[1,323],129:[2,171],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,173],6:[2,173],28:[2,173],29:[2,173],52:[2,173],57:[2,173],60:[2,173],75:[2,173],80:[2,173],89:[2,173],94:[2,173],96:[2,173],105:[2,173],106:91,107:[2,173],108:[1,324],109:[2,173],112:92,113:[2,173],114:73,121:[2,173],129:[2,173],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,172],6:[2,172],28:[2,172],29:[2,172],52:[2,172],57:[2,172],60:[2,172],75:[2,172],80:[2,172],89:[2,172],94:[2,172],96:[2,172],105:[2,172],106:91,107:[2,172],108:[2,172],109:[2,172],112:92,113:[2,172],114:73,121:[2,172],129:[2,172],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[2,98],28:[2,98],29:[2,98],57:[2,98],80:[2,98]},{6:[2,57],28:[2,57],29:[2,57],56:325,57:[1,244]},{29:[1,326],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[1,255],28:[1,256],29:[1,327]},{29:[1,328]},{1:[2,179],6:[2,179],28:[2,179],29:[2,179],52:[2,179],57:[2,179],60:[2,179],75:[2,179],80:[2,179],89:[2,179],94:[2,179],96:[2,179],105:[2,179],107:[2,179],108:[2,179],109:[2,179],113:[2,179],121:[2,179],129:[2,179],131:[2,179],132:[2,179],135:[2,179],136:[2,179],137:[2,179],138:[2,179],139:[2,179],140:[2,179]},{29:[2,183],124:[2,183],126:[2,183]},{28:[2,137],57:[2,137],106:91,107:[1,69],109:[1,70],112:92,113:[1,72],114:73,129:[1,90],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[1,274],28:[1,275],29:[1,329]},{8:330,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{8:331,9:121,10:22,11:23,12:[1,24],13:21,14:[1,48],15:8,16:9,17:10,18:11,19:12,20:13,21:14,22:15,23:16,24:17,25:18,26:19,27:20,30:66,31:[1,77],32:53,33:[1,75],34:[1,76],35:26,36:[1,54],37:[1,55],38:[1,56],39:[1,57],40:[1,58],41:[1,59],42:25,47:67,48:[1,49],49:[1,50],50:[1,31],53:32,54:[1,64],55:[1,65],61:51,62:52,64:38,66:27,67:28,68:29,78:[1,74],81:[1,45],85:[1,30],86:[1,47],91:[1,62],92:[1,63],93:[1,61],99:[1,40],103:[1,46],104:[1,60],106:41,107:[1,69],109:[1,70],110:42,111:[1,71],112:43,113:[1,72],114:73,122:[1,44],127:39,128:[1,68],130:[1,33],131:[1,34],132:[1,35],133:[1,36],134:[1,37]},{6:[1,285],28:[1,286],29:[1,332]},{6:[2,45],28:[2,45],29:[2,45],57:[2,45],80:[2,45]},{6:[2,63],28:[2,63],29:[2,63],52:[2,63],57:[2,63]},{1:[2,177],6:[2,177],28:[2,177],29:[2,177],52:[2,177],57:[2,177],60:[2,177],75:[2,177],80:[2,177],89:[2,177],94:[2,177],96:[2,177],105:[2,177],107:[2,177],108:[2,177],109:[2,177],113:[2,177],121:[2,177],129:[2,177],131:[2,177],132:[2,177],135:[2,177],136:[2,177],137:[2,177],138:[2,177],139:[2,177],140:[2,177]},{6:[2,133],28:[2,133],29:[2,133],57:[2,133],89:[2,133],94:[2,133]},{1:[2,174],6:[2,174],28:[2,174],29:[2,174],52:[2,174],57:[2,174],60:[2,174],75:[2,174],80:[2,174],89:[2,174],94:[2,174],96:[2,174],105:[2,174],106:91,107:[2,174],108:[2,174],109:[2,174],112:92,113:[2,174],114:73,121:[2,174],129:[2,174],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{1:[2,175],6:[2,175],28:[2,175],29:[2,175],52:[2,175],57:[2,175],60:[2,175],75:[2,175],80:[2,175],89:[2,175],94:[2,175],96:[2,175],105:[2,175],106:91,107:[2,175],108:[2,175],109:[2,175],112:92,113:[2,175],114:73,121:[2,175],129:[2,175],131:[1,84],132:[1,83],135:[1,82],136:[1,85],137:[1,86],138:[1,87],139:[1,88],140:[1,89]},{6:[2,99],28:[2,99],29:[2,99],57:[2,99],80:[2,99]}],defaultActions:{64:[2,55],65:[2,56],79:[2,3],98:[2,114],197:[2,93]},parseError:function(t,n){throw new Error(t)},parse:function(t){function d(e){r.length=r.length-2*e,i.length=i.length-e,s.length=s.length-e}function v(){var e;return e=n.lexer.lex()||1,typeof e!="number"&&(e=n.symbols_[e]||e),e}var n=this,r=[0],i=[null],s=[],o=this.table,u="",a=0,f=0,l=0,c=2,h=1;this.lexer.setInput(t),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,typeof this.lexer.yylloc=="undefined"&&(this.lexer.yylloc={});var p=this.lexer.yylloc;s.push(p),typeof this.yy.parseError=="function"&&(this.parseError=this.yy.parseError);var m,g,y,b,w,E,S={},x,T,N,C;for(;;){y=r[r.length-1],this.defaultActions[y]?b=this.defaultActions[y]:(m==null&&(m=v()),b=o[y]&&o[y][m]);if(typeof b=="undefined"||!b.length||!b[0]){if(!l){C=[];for(x in o[y])this.terminals_[x]&&x>2&&C.push("'"+this.terminals_[x]+"'");var k="";this.lexer.showPosition?k="Parse error on line "+(a+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+C.join(", ")+", got '"+this.terminals_[m]+"'":k="Parse error on line "+(a+1)+": Unexpected "+(m==1?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(k,{text:this.lexer.match,token:this.terminals_[m]||m,line:this.lexer.yylineno,loc:p,expected:C})}if(l==3){if(m==h)throw new Error(k||"Parsing halted.");f=this.lexer.yyleng,u=this.lexer.yytext,a=this.lexer.yylineno,p=this.lexer.yylloc,m=v()}for(;;){if(c.toString()in o[y])break;if(y==0)throw new Error(k||"Parsing halted.");d(1),y=r[r.length-1]}g=m,m=c,y=r[r.length-1],b=o[y]&&o[y][c],l=3}if(b[0]instanceof Array&&b.length>1)throw new Error("Parse Error: multiple actions possible at state: "+y+", token: "+m);switch(b[0]){case 1:r.push(m),i.push(this.lexer.yytext),s.push(this.lexer.yylloc),r.push(b[1]),m=null,g?(m=g,g=null):(f=this.lexer.yyleng,u=this.lexer.yytext,a=this.lexer.yylineno,p=this.lexer.yylloc,l>0&&l--);break;case 2:T=this.productions_[b[1]][1],S.$=i[i.length-T],S._$={first_line:s[s.length-(T||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(T||1)].first_column,last_column:s[s.length-1].last_column},E=this.performAction.call(S,u,f,a,this.yy,b[1],i,s);if(typeof E!="undefined")return E;T&&(r=r.slice(0,-1*T*2),i=i.slice(0,-1*T),s=s.slice(0,-1*T)),r.push(this.productions_[b[1]][0]),i.push(S.$),s.push(S._$),N=o[r[r.length-2]][r[r.length-1]],r.push(N);break;case 3:return!0}}return!0}};return undefined,e}();typeof require!="undefined"&&typeof e!="undefined"&&(e.parser=t,e.parse=function(){return t.parse.apply(t,arguments)},e.main=function(n){if(!n[1])throw new Error("Usage: "+n[0]+" FILE");if(typeof process!="undefined")var r=require("fs").readFileSync(require("path").join(process.cwd(),n[1]),"utf8");else var i=require("file").path(require("file").cwd()),r=i.join(n[1]).read({charset:"utf-8"});return e.parser.parse(r)},typeof module!="undefined"&&require.main===module&&e.main(typeof process!="undefined"?process.argv.slice(1):require("system").args))},require["./iced"]=new function(){var e=this;(function(){var t,n=[].slice;e.generator=t=function(e,t,r){var i,s,o,u,a,f;return t.transform=function(e){return e.icedTransform()},t["const"]=i={k:"__iced_k",k_noop:"__iced_k_noop",param:"__iced_p_",ns:"iced",Deferrals:"Deferrals",deferrals:"__iced_deferrals",fulfill:"_fulfill",b_while:"_break",t_while:"_while",c_while:"_continue",n_while:"_next",n_arg:"__iced_next_arg",defer_method:"defer",slot:"__slot",assign_fn:"assign_fn",autocb:"autocb",retslot:"ret",trace:"__iced_trace",passed_deferral:"__iced_passed_deferral",findDeferral:"findDeferral",lineno:"lineno",parent:"parent",filename:"filename",funcname:"funcname",catchExceptions:"catchExceptions",runtime_modes:["node","inline","window","none"]},e.makeDeferReturn=function(t,r,s,o,u){var a,f,l,c;l={};for(a in o)c=o[a],l[a]=c;return l[i.lineno]=r!=null?r[i.lineno]:void 0,f=function(){var i,o,a;return i=1<=arguments.length?n.call(arguments,0):[],r!=null&&(a=r.assign_fn)!=null&&a.apply(null,i),t?(o=t,u||(t=null),o._fulfill(s,l)):e._warn("overused deferral at "+e._trace_to_string(l))},f[i.trace]=l,f},e.__c=0,e.tickCounter=function(t){return e.__c++,e.__c%t===0?(e.__c=0,!0):!1},e.__active_trace=null,e._trace_to_string=function(e){var t;return t=e[i.funcname]||"",""+t+" ("+e[i.filename]+":"+(e[i.lineno]+1)+")"},e._warn=function(e){return typeof console!="undefined"&&console!==null?console.log("ICED warning: "+e):void 0},r.Deferrals=s=function(){function t(e,t){this.trace=t,this.continuation=e,this.count=1,this.ret=null}return t.prototype._call=function(t){var n;return this.continuation?(e.__active_trace=t,n=this.continuation,this.continuation=null,n(this.ret)):e._warn("Entered dead await at "+e._trace_to_string(t))},t.prototype._fulfill=function(t,n){var r=this;if(!(--this.count>0))return e.tickCounter(500)?typeof process!="undefined"&&process!==null?process.nextTick(function(){return r._call(n)}):setTimeout(function(){return r._call(n)},0):this._call(n)},t.prototype.defer=function(t){var n;return this.count++,n=this,e.makeDeferReturn(n,t,null,this.trace)},t}(),r.findDeferral=a=function(e){var t,n,r;for(n=0,r=e.length;n1?"_"+e+(t>1?t-1:""):"_"+(t+parseInt(e,36)).toString(36).replace(/\d/g,"a")},e.prototype.type=function(e){var t,n,r,i;i=this.variables;for(n=0,r=i.length;n1?t.__super__.compileCps.call(this,e):this.compileNode(e)},t.prototype.compile=function(e,n){return e==null&&(e={}),e.scope?t.__super__.compile.call(this,e,n):this.compileRoot(e)},t.prototype.compileNode=function(e){var n,r,i,s,o,u,a,f;this.tab=e.indent,o=e.level===_,i=[],f=this.expressions;for(u=0,a=f.length;u1&&e.level>=A?"("+r+")":r)},t.prototype.compileRoot=function(e){var t,n,r,i,s,o;return e.indent=e.bare?"":Y,e.scope=new $(null,this,null),e.level=_,this.spaced=!0,i="",e.bare||(s=function(){var e,t,i,s;i=this.expressions,s=[];for(r=e=0,t=i.length;e=k?"(void 0)":"void 0":this.value==="this"?((n=e.scope.method)!=null?n.bound:void 0)?e.scope.method.context:this.value:this.value.reserved?'"'+this.value+'"':this.icedLoopFlag&&this.icedIsJump()?this.compileIced(e):this.value,this.isStatement()?""+this.tab+t+";":t},t.prototype.toString=function(){return' "'+this.value+'"'},t}(s),e.Undefined=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return St(t,e),t.prototype.isAssignable=B,t.prototype.isComplex=B,t.prototype.compileNode=function(e){return e.level>=k?"(void 0)":"void 0"},t}(s),e.Null=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return St(t,e),t.prototype.isAssignable=B,t.prototype.isComplex=B,t.prototype.compileNode=function(){return"null"},t}(s),e.Bool=function(e){function t(e){this.val=e,t.__super__.constructor.call(this)}return St(t,e),t.prototype.isAssignable=B,t.prototype.isComplex=B,t.prototype.compileNode=function(){return this.val},t}(s),e.Return=W=function(e){function t(e,n){t.__super__.constructor.call(this),this.icedHasAutocbFlag=n,e&&!e.unwrap().isUndefined&&(this.expression=e)}return St(t,e),t.prototype.children=["expression"],t.prototype.isStatement=st,t.prototype.makeReturn=Z,t.prototype.jumps=Z,t.prototype.compile=function(e,n){var r,i;return r=(i=this.expression)!=null?i.makeReturn():void 0,!r||r instanceof t?t.__super__.compile.call(this,e,n):r.compile(e,n)},t.prototype.compileNode=function(e){var t,n,r,i,s;return this.icedHasAutocbFlag?(i=new rt(new D(ct["const"].autocb)),t=this.expression?[this.expression]:[],r=new u(i,t),s=new D("return"),n=new o([r,s]),n.compile(e)):this.tab+("return"+[this.expression?" "+this.expression.compile(e,M):void 0]+";")},t}(s),e.Value=rt=function(e){function t(e,n,r){return t.__super__.constructor.call(this),!n&&e instanceof t?e:(this.base=e,this.properties=n||[],r&&(this[r]=!0),this)}return St(t,e),t.prototype.children=["base","properties"],t.prototype.copy=function(){return new t(this.base,this.properties)},t.prototype.add=function(e){return this.properties=this.properties.concat(e),this},t.prototype.hasProperties=function(){return!!this.properties.length},t.prototype.isArray=function(){return!this.properties.length&&this.base instanceof n},t.prototype.isComplex=function(){return this.hasProperties()||this.base.isComplex()},t.prototype.isAssignable=function(){return this.hasProperties()||this.base.isAssignable()},t.prototype.isSimpleNumber=function(){return this.base instanceof D&&X.test(this.base.value)},t.prototype.isString=function(){return this.base instanceof D&&b.test(this.base.value)},t.prototype.isAtomic=function(){var e,t,n,r;r=this.properties.concat(this.base);for(t=0,n=r.length;t"+this.equals],a=p[0],i=p[1],n=this.stepNum?+this.stepNum>0?""+a+" "+this.toVar:""+i+" "+this.toVar:u?(d=[+this.fromNum,+this.toNum],r=d[0],c=d[1],d,r<=c?""+a+" "+c:""+i+" "+c):(t=""+this.fromVar+" <= "+this.toVar,""+t+" ? "+a+" "+this.toVar+" : "+i+" "+this.toVar),l=this.stepVar?""+s+" += "+this.stepVar:u?f?r<=c?"++"+s:"--"+s:r<=c?""+s+"++":""+s+"--":f?""+t+" ? ++"+s+" : --"+s:""+t+" ? "+s+"++ : "+s+"--",f&&(h=""+o+" = "+h),f&&(l=""+o+" = "+l),""+h+"; "+n+"; "+l):this.compileArray(e)},t.prototype.compileArray=function(e){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v;if(this.fromNum&&this.toNum&&Math.abs(this.fromNum-this.toNum)<=20)return f=function(){v=[];for(var e=p=+this.fromNum,t=+this.toNum;p<=t?e<=t:e>=t;p<=t?e++:e--)v.push(e);return v}.apply(this),this.exclusive&&f.pop(),"["+f.join(", ")+"]";o=this.tab+Y,s=e.scope.freeVariable("i"),l=e.scope.freeVariable("results"),a="\n"+o+l+" = [];",this.fromNum&&this.toNum?(e.index=s,n=this.compileNode(e)):(c=""+s+" = "+this.fromC+(this.toC!==this.toVar?", "+this.toC:""),r=""+this.fromVar+" <= "+this.toVar,n="var "+c+"; "+r+" ? "+s+" <"+this.equals+" "+this.toVar+" : "+s+" >"+this.equals+" "+this.toVar+"; "+r+" ? "+s+"++ : "+s+"--"),u="{ "+l+".push("+s+"); }\n"+o+"return "+l+";\n"+e.indent,i=function(e){return e!=null?e.contains(function(e){return e instanceof D&&e.value==="arguments"&&!e.asKey}):void 0};if(i(this.from)||i(this.to))t=", arguments";return"(function() {"+a+"\n"+o+"for ("+n+")"+u+"}).apply(this"+(t!=null?t:"")+")"},t}(s),e.Slice=J=function(e){function t(e){this.range=e,t.__super__.constructor.call(this)}return St(t,e),t.prototype.children=["range"],t.prototype.compileNode=function(e){var t,n,r,i,s,o;return o=this.range,i=o.to,n=o.from,r=n&&n.compile(e,M)||"0",t=i&&i.compile(e,M),i&&(!!this.range.exclusive||+t!==-1)&&(s=", "+(this.range.exclusive?t:X.test(t)?""+(+t+1):(t=i.compile(e,k),"+"+t+" + 1 || 9e9"))),".slice("+r+(s||"")+")"},t}(s),e.Obj=F=function(e){function t(e,n){this.generated=n!=null?n:!1,t.__super__.constructor.call(this),this.objects=this.properties=e||[]}return St(t,e),t.prototype.children=["properties"],t.prototype.toSlot=function(e){var t,n,i,s,o;s=this.properties,o=[];for(n=0,i=s.length;n=0?"[\n"+e.indent+t+"\n"+this.tab+"]":"["+t+"]")):"[]"},t.prototype.assigns=function(e){var t,n,r,i;i=this.objects;for(n=0,r=i.length;n=0)throw SyntaxError("variable name may not be "+e);return e&&(e=g.test(e)&&e)},n.prototype.setContext=function(e){return this.body.traverseChildren(!1,function(t){if(t.classBody)return!1;if(t instanceof D&&t.value==="this")return t.value=e;if(t instanceof l){t.klass=e;if(t.bound)return t.context=e}})},n.prototype.addBoundFunctions=function(e){var n,r,i,s,o,u;if(this.boundFuncs.length){o=this.boundFuncs,u=[];for(i=0,s=o.length;i=0);if(s&&this.context!=="object")throw SyntaxError('variable name may not be "'+o+'"');this.icedlocal=i&&i.icedlocal}return St(n,e),n.prototype.children=["variable","value"],n.prototype.isStatement=function(e){return(e!=null?e.level:void 0)===_&&this.context!=null&&xt.call(this.context,"?")>=0},n.prototype.assigns=function(e){return this[this.context==="object"?"value":"variable"].assigns(e)},n.prototype.unfoldSoak=function(e){return gt(e,this,"variable")},n.prototype.icedCpsRotate=function(){var e;if(e=this.icedCpsExprRotate(this.value))return this.value=e},n.prototype.compileNode=function(e){var t,n,r,i,s,o,u,a,f;if(t=this.variable instanceof rt){if(this.variable.isArray()||this.variable.isObject())return this.compilePatternMatch(e);if(this.variable.isSplice())return this.compileSplice(e);if((o=this.context)==="||="||o==="&&="||o==="?=")return this.compileConditional(e)}r=this.variable.compile(e,A);if(!this.context){if(!(s=this.variable.unwrapAll()).isAssignable())throw SyntaxError('"'+this.variable.compile(e)+'" cannot be assigned.');if(typeof s.hasProperties=="function"?!s.hasProperties():!void 0)this.param||this.icedlocal?e.scope.add(r,"var",this.icedlocal):e.scope.find(r)}return this.value instanceof l&&(n=P.exec(r))&&(n[1]&&(this.value.klass=n[1]),this.value.name=(u=(a=(f=n[2])!=null?f:n[3])!=null?a:n[4])!=null?u:n[5]),i=this.value.compile(e,A),this.context==="object"?""+r+": "+i:(i=r+(" "+(this.context||"=")+" ")+i,e.level<=A?i:"("+i+")")},n.prototype.compilePatternMatch=function(e){var r,i,s,o,u,a,f,l,c,h,p,d,v,m,y,b,w,E,S,x,T,C,k,L,M,P,H;y=e.level===_,w=this.value,h=this.variable.base.objects;if(!(p=h.length))return s=w.compile(e),e.level>=O?"("+s+")":s;a=this.variable.isObject();if(y&&p===1&&!((c=h[0])instanceof Q)){c instanceof n?(T=c,C=T.variable,u=C.base,c=T.value):c.base instanceof R?(k=(new rt(c.unwrapAll())).cacheReference(e),c=k[0],u=k[1]):u=a?c["this"]?c.properties[0].name:c:new D(0),r=g.test(u.unwrap().value||0),w=new rt(w),w.properties.push(new(r?t:N)(u));if(L=c.unwrap().value,xt.call(U,L)>=0)throw new SyntaxError("assignment to a reserved word: "+c.compile(e)+" = "+w.compile(e));return(new n(c,w,null,{param:this.param})).compile(e,_)}E=w.compile(e,A),i=[],m=!1;if(!g.test(E)||this.variable.assigns(E))i.push(""+(d=e.scope.freeVariable("ref"))+" = "+E),E=d;for(o=S=0,x=h.length;S=0)throw new SyntaxError("assignment to a reserved word: "+c.compile(e)+" = "+b.compile(e));i.push((new n(c,b,null,{param:this.param,subpattern:!0})).compile(e,A))}return!y&&!this.subpattern&&i.push(E),s=i.join(", "),e.level=0&&(e.isExistentialEquals=!0),(new I(this.context.slice(0,-1),t,new n(r,this.value,"="))).compile(e)},n.prototype.compileSplice=function(e){var t,n,r,i,s,o,u,a,f,l,c,h;return l=this.variable.properties.pop().range,r=l.from,u=l.to,n=l.exclusive,o=this.variable.compile(e),c=(r!=null?r.cache(e,O):void 0)||["0","0"],i=c[0],s=c[1],u?(r!=null?r.isSimpleNumber():void 0)&&u.isSimpleNumber()?(u=+u.compile(e)- +s,n||(u+=1)):(u=u.compile(e,k)+" - "+s,n||(u+=" + 1")):u="9e9",h=this.value.cache(e,A),a=h[0],f=h[1],t="[].splice.apply("+o+", ["+i+", "+u+"].concat("+a+")), "+f,e.level>_?"("+t+")":t},n}(s),e.Code=l=function(e){function i(e,t,n){i.__super__.constructor.call(this),this.params=e||[],this.body=t||new o,this.icedgen=n==="icedgen",this.bound=n==="boundfunc"||this.icedgen;if(this.bound||this.icedgen)this.context="_this";this.icedPassedDeferral=null}return St(i,e),i.prototype.children=["params","body"],i.prototype.isStatement=function(){return!!this.ctor},i.prototype.traceName=function(){var e;return e=[],this.klass&&e.push(this.klass),this.name&&e.push(this.name),e.join(".")},i.prototype.jumps=B,i.prototype.compileNode=function(e){var i,s,o,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,T,N,C,L,A,O,M,_,P,H,B,j,F,q,R,U,z,W,X;e.scope=new $(e.scope,this.body,this),e.scope.shared=ut(e,"sharedScope")||this.icedgen,e.scope.icedgen=this.icedgen,e.indent+=Y,delete e.bare,delete e.isExistentialEquals,v=[],s=[],F=this.paramNames();for(T=0,A=F.length;T=k?"("+i+")":i},i.prototype.paramNames=function(){var e,t,n,r,i;e=[],i=this.params;for(n=0,r=i.length;n=0)throw SyntaxError('parameter name "'+e+'" is not allowed')}return St(t,e),t.prototype.children=["name","value"],t.prototype.compile=function(e){return this.name.compile(e,A)},t.prototype.asReference=function(e){var t;return this.reference?this.reference:(t=this.name,t["this"]?(t=t.properties[0].name,t.value.reserved&&(t=new D(e.scope.freeVariable(t.value)))):t.isComplex()&&(t=new D(e.scope.freeVariable("arg"))),t=new rt(t),this.splat&&(t=new Q(t)),this.reference=t)},t.prototype.isComplex=function(){return this.name.isComplex()},t.prototype.names=function(e){var t,n,i,s,o,u;e==null&&(e=this.name),t=function(e){var t;return t=e.properties[0].name.value,t.reserved?[]:[t]};if(e instanceof D)return[e.value];if(e instanceof rt)return t(e);n=[],u=e.objects;for(s=0,o=u.length;s=n.length)return"";if(n.length===1)return o=n[0].compile(e,A),r?o:""+yt("slice")+".call("+o+")";i=n.slice(a);for(u=l=0,c=i.length;l1?t.expressions.unshift(new x((new R(this.guard)).invert(),new D("continue"))):this.guard&&(t=o.wrap([new x(this.guard,t)]))),t="\n"+t.compile(e,_)+"\n"+this.tab),n=i+this.tab+("while ("+this.condition.compile(e,M)+") {"+t+"}"),this.returns&&(this.icedHasAutocbFlag?(n+="\n"+this.tab+ct["const"].autocb+"("+r+");",n+="\n"+this.tab+"return;"):n+="\n"+this.tab+"return "+r+";"),n)},i}(s),e.Op=I=function(e){function i(e,n,r,s){i.__super__.constructor.call(this);if(e==="in")return new T(n,r);if(e==="do")return this.generateDo(n);if(e==="new"){if(n instanceof u&&!n["do"]&&!n.isNew)return n.newInstance();if(n instanceof l&&n.bound||n["do"])n=new R(n)}return this.operator=t[e]||e,this.first=n,this.second=r,this.flip=!!s,this}var t,n;return St(i,e),i.prototype.icedWrapContinuation=function(){return this.icedCallContinuationFlag},t={"==":"===","!=":"!==",of:"in"},n={"!==":"===","===":"!=="},i.prototype.children=["first","second"],i.prototype.isSimpleNumber=B,i.prototype.isUnary=function(){return!this.second},i.prototype.isComplex=function(){var e;return!this.isUnary()||(e=this.operator)!=="+"&&e!=="-"||this.first.isComplex()},i.prototype.isChainable=function(){var e;return(e=this.operator)==="<"||e===">"||e===">="||e==="<="||e==="==="||e==="!=="},i.prototype.icedCpsRotate=function(){var e,t;this.first&&(e=this.icedCpsExprRotate(this.first))&&(this.first=e);if(this.second&&(t=this.icedCpsExprRotate(this.second)))return this.second=t},i.prototype.invert=function(){var e,t,r,s,o;if(this.isChainable()&&this.first.isChainable()){e=!0,t=this;while(t&&t.operator)e&&(e=t.operator in n),t=t.first;if(!e)return(new R(this)).invert();t=this;while(t&&t.operator)t.invert=!t.invert,t.operator=n[t.operator],t=t.first;return this}return(s=n[this.operator])?(this.operator=s,this.first.unwrap()instanceof i&&this.first.invert(),this):this.second?(new R(this)).invert():this.operator==="!"&&(r=this.first.unwrap())instanceof i&&((o=r.operator)==="!"||o==="in"||o==="instanceof")?r:new i("!",this)},i.prototype.unfoldSoak=function(e){var t;return((t=this.operator)==="++"||t==="--"||t==="delete")&>(e,this,"first")},i.prototype.generateDo=function(e){var t,n,i,s,o,a,f,c;s=[],n=e instanceof r&&(o=e.value.unwrap())instanceof l?o:e,c=n.params||[];for(a=0,f=c.length;a=0))throw SyntaxError("prefix increment/decrement may not have eval or arguments operand");return this.isUnary()?this.compileUnary(e):n?this.compileChain(e):this.operator==="?"?this.compileExistence(e):(t=this.first.compile(e,O)+" "+this.operator+" "+this.second.compile(e,O),e.level<=O?t:"("+t+")")},i.prototype.compileChain=function(e){var t,n,r,i;return i=this.first.second.cache(e),this.first.second=i[0],r=i[1],n=this.first.compile(e,O),t=""+n+" "+(this.invert?"&&":"||")+" "+r.compile(e)+" "+this.operator+" "+this.second.compile(e,O),"("+t+")"},i.prototype.compileExistence=function(e){var t,n;return this.first.isComplex()?(n=new D(e.scope.freeVariable("ref")),t=new R(new r(n,this.first))):(t=this.first,n=t),(new x(new d(t),n,{type:"if"})).addElse(this.second).compile(e)},i.prototype.compileUnary=function(e){var t,n,r;if(e.level>=k)return(new R(this)).compile(e);n=[t=this.operator],r=t==="+"||t==="-",(t==="new"||t==="typeof"||t==="delete"||r&&this.first instanceof i&&this.first.operator===t)&&n.push(" ");if(r&&this.first instanceof i||t==="new"&&this.first.isStatement(e))this.first=new R(this.first);return n.push(this.first.compile(e,O)),this.flip&&n.reverse(),n.join("")},i.prototype.toString=function(e){return i.__super__.toString.call(this,e,this.constructor.name+" "+this.operator)},i}(s),e.In=T=function(e){function t(e,n){this.object=e,this.array=n,t.__super__.constructor.call(this)}return St(t,e),t.prototype.children=["object","array"],t.prototype.invert=H,t.prototype.compileNode=function(e){var t,n,r,i,s;if(this.array instanceof rt&&this.array.isArray()){s=this.array.base.objects;for(r=0,i=s.length;r= 0"),r===n?t:(t=r+", "+t,e.level=0)throw SyntaxError('catch variable may not be "'+this.error.value+'"');return e.scope.check(this.error.value)||e.scope.add(this.error.value,"param")," catch"+r+"{\n"+this.recovery.compile(e,_)+"\n"+this.tab+"}"}if(!this.ensure&&!this.recovery)return" catch (_error) {}"}.call(this),n=this.ensure?" finally {\n"+this.ensure.compile(e,_)+"\n"+this.tab+"}":"",""+this.tab+"try {\n"+i+"\n"+this.tab+"}"+(t||"")+n},t}(s),e.Throw=et=function(e){function t(e){this.expression=e,t.__super__.constructor.call(this)}return St(t,e),t.prototype.children=["expression"],t.prototype.isStatement=st,t.prototype.jumps=B,t.prototype.makeReturn=Z,t.prototype.compileNode=function(e){return this.tab+("throw "+this.expression.compile(e)+";")},t}(s),e.Existence=d=function(e){function t(e){this.expression=e,t.__super__.constructor.call(this)}return St(t,e),t.prototype.children=["expression"],t.prototype.invert=H,t.prototype.compileNode=function(e){var t,n,r,i;return this.expression.front=this.front,r=this.expression.compile(e,O),g.test(r)&&!e.scope.check(r)?(i=this.negated?["===","||"]:["!==","&&"],t=i[0],n=i[1],r="typeof "+r+" "+t+' "undefined" '+n+" "+r+" "+t+" null"):r=""+r+" "+(this.negated?"==":"!=")+" null",e.level<=L?r:"("+r+")"},t}(s),e.Parens=R=function(e){function t(e){this.body=e,t.__super__.constructor.call(this)}return St(t,e),t.prototype.children=["body"],t.prototype.unwrap=function(){return this.icedUnwrap(this.body)},t.prototype.isComplex=function(){return this.body.isComplex()},t.prototype.compileNode=function(e){var t,n,r;return r=this.body.unwrap(),r instanceof rt&&r.isAtomic()?(r.front=this.front,r.compile(e)):(n=r.compile(e,M),t=e.level1?t.expressions.unshift(new x((new R(this.guard)).invert(),new D("continue"))):this.guard&&(t=o.wrap([new x(this.guard,t)]))),this.pattern&&t.expressions.unshift(new r(this.name,new D(""+L+"["+h+"]"))),i+=this.pluckDirectCall(e,t),y&&(M="\n"+f+y+";"),this.object&&(s=""+h+" in "+L,this.own&&(a="\n"+f+"if (!"+yt("hasProp")+".call("+L+", "+h+")) continue;")),t=t.compile(pt(e,{indent:f}),_),t&&(t="\n"+t+"\n"),""+i+(w||"")+this.tab+"for ("+s+") {"+a+M+t+this.tab+"}"+(E||""))},i.prototype.pluckDirectCall=function(e,t){var n,i,s,o,a,f,c,h,p,d,v,m,g,y,b;i="",d=t.expressions;for(a=h=0,p=d.length;hs.length+r.length?""+this.tab+"if ("+s+") "+r.replace(/^\s+/,""):(r&&(r="\n"+r+"\n"+this.tab),u="if ("+s+") {"+r+"}",i||(u=this.tab+u),this.elseBody?u+" else "+(this.isChain?(e.indent=this.tab,e.chainChild=!0,this.elseBody.unwrap().compile(e,_)):"{\n"+this.elseBody.compile(e,_)+"\n"+this.tab+"}"):u))},t.prototype.compileExpression=function(e){var t,n,r,i;return i=this.condition.compile(e,L),n=this.bodyNode().compile(e,A),t=this.elseBodyNode()?this.elseBodyNode().compile(e,A):"void 0",r=""+i+" ? "+n+" : "+t,e.level>=L?"("+r+")":r},t.prototype.unfoldSoak=function(){return this.soak&&this},t}(s),f={wrap:function(e,n,r){var i,s,a,f,c;if(e.jumps())return e;a=new l([],o.wrap([e])),i=[];if((f=e.contains(this.literalArgs))||e.contains(this.literalThis))c=new D(f?"apply":"call"),i=[new D("this")],f&&i.push(new D("arguments")),a=new rt(a,[new t(c)]);return a.noReturn=r,s=new u(a,i),n?o.wrap([s]):s},literalArgs:function(e){return e instanceof D&&e.value==="arguments"&&!e.asKey},literalThis:function(e){return e instanceof D&&e.value==="this"&&!e.asKey||e instanceof l&&e.bound||e instanceof u&&e.isSuper}},h={wrap:function(e,t,n,r){var i,s,a,f,c,h;return h=new l([new q(new D(ct["const"].k))],o.wrap([e]),"icedgen"),i=[],n&&(n.bindName(r),i.push(n)),s=o.wrap([t]),(c=s.getSingle())&&c instanceof S&&c.canInline()?f=c.extractFunc():f=new l(i,s,"icedgen"),a=new u(h,[f]),new o([a])}},S=function(e){function t(e,n){this.func=e,n==null&&(n=null),t.__super__.constructor.call(this),this.func||(this.func=ct["const"].k),this.value=n}return St(t,e),t.prototype.children=["value"],t.prototype.assignValue=function(e){return this.value=e},t.prototype.canInline=function(){return!this.value||this.value instanceof w},t.prototype.literalFunc=function(){return new D(this.func)},t.prototype.extractFunc=function(){return new rt(this.literalFunc())},t.prototype.icedCpsRotate=function(){var e;if(this.value)if(e=this.icedCpsExprRotate(this.value))return this.value=e},t.prototype.compileNode=function(e){var t,n,r;return n=this.literalFunc(),r=e.level===_?this.value?new o([this.value,new u(n)]):new u(n):(t=this.value?[this.value]:[],new u(n,t)),r.compileNode(e)},t}(s),w=function(e){function t(){t.__super__.constructor.call(this,null,null,!1)}return St(t,e),t.counter=0,t.prototype.bindName=function(e){var n;return n=""+e.scope.freeVariable(ct["const"].param,!1)+"_"+t.counter++,this.name=new D(n)},t.prototype.compile=function(e){return this.name||this.bindName(e),t.__super__.compile.call(this,e)},t}(q),C={generate:function(e){var n,i,s,f,c,h,p,d,v,m,g,y,b,w,E,S,T,N,C,k,L,A,O,M,_,P,H,B,R,U,z,W,X,V,$,J,K,Q,G,Y,Z,et,tt,nt,it,st,ot,ut,at,ft,lt,ht,pt,dt;return $=new D("continuation"),v=new D("count"),d=new rt(new D(ct["const"].Deferrals)),et=new rt(new D(ct["const"].ns)),e&&(e.add(new t(et)),et=e),J=new rt(new D("this")),J.add(new t($)),ot=new q(J),m=new rt(new D("this")),m.add(new t(v)),ut=new rt(new D("this")),ut.add(new t(new rt(new D(ct["const"].retslot)))),n=new r(m,new rt(new D(1))),i=new r(ut,j()),E=[ot],y=new o([n,i]),b=new l(E,y),w=new rt(new D("constructor")),g=new r(w,b),R=new u(J,[ut]),H=new o([R]),S=new I("--",m),B=new I("!",S),Y=new x(B,H),ft=new o([Y]),ht=new l([],ft),dt=new rt(new D(ct["const"].fulfill)),at=new r(dt,ht),U=new I("++",m),V=new D("inner_params"),A=new D("defer_params"),O=new rt(A),p=new rt(A),s=new D(ct["const"].assign_fn),p.add(new t(s,"soak")),G=new D("apply"),p.add(new t(G,"soak")),Z=j(),f=new u(p,[Z,new rt(V)]),pt=new rt(new D("this")),pt.add(new t(new D(ct["const"].fulfill))),lt=new u(pt,[]),z=new o([f,lt]),X=[new q(V,null,!0)],W=new l(X,z,"boundfunc"),N=new o([U,W]),L=[new q(A)],C=new l(L,N),k=new rt(new D(ct["const"].defer_method)),T=new r(k,C),c=[g,at,T],it=new F(c,!0),h=new o([new rt(it)]),K=new a(null,null,h),Q=new r(d,K,"object"),st=new o([j()]),_=new l([],st),P=new rt(new D(ct["const"].findDeferral)),M=new r(P,_,"object"),tt=new F([Q,M],!0),nt=new rt(tt),new r(et,nt)}},gt=function(e,t,n){var r;if(!(r=t[n].unfoldSoak(e)))return;return t[n]=r.body,r.body=new rt(t),r},nt={"extends":function(){return"function(child, parent) { for (var key in parent) { if ("+yt("hasProp")+".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }"},bind:function(){return"function(fn, me){ return function(){ return fn.apply(me, arguments); }; }"},indexOf:function(){return"[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"},hasProp:function(){return"{}.hasOwnProperty"},slice:function(){return"[].slice"}},_=1,M=2,A=3,L=4,O=5,k=6,Y=" ",y="[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*",g=RegExp("^"+y+"$"),X=/^[+-]?\d+$/,P=RegExp("^(?:("+y+")\\.prototype(?:\\.("+y+")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|("+y+")$"),b=/^['"]/,yt=function(e){var t;return t="__"+e,$.root.assign(t,nt[e]()),t},dt=function(e,t){return e=e.replace(/\n/g,"$&"+t),e.replace(/\s+$/,"")}}).call(this)},require["./coffee-script"]=new function(){var e=this;(function(){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y={}.hasOwnProperty;o=require("fs"),c=require("path"),g=require("./lexer"),n=g.Lexer,r=g.RESERVED,l=require("./parser").parser,h=require("vm"),u=require("./iced"),e.EXTENSIONS=t=[".coffee",".iced"],a=function(e){var n,r,i;for(r=0,i=t.length;r=o.window))return u();(function(e){r=new n.Deferrals(e,{parent:t,filename:"src/icedlib.coffee",funcname:"Pipeliner.waitInQueue"}),o.cb=r.defer({lineno:88}),r._fulfill()})(f)},s(e)}(function(){o.n_out++,function(e){if(!o.delay)return e();(function(e){r=new n.Deferrals(e,{parent:t,filename:"src/icedlib.coffee",funcname:"Pipeliner.waitInQueue"}),setTimeout(r.defer({lineno:96}),o.delay),r._fulfill()})(e)}(function(){return e()})})},e.prototype.__defer=function(e,t){var r,i,o,u,a,l=this;a=s,o=n.findDeferral(arguments),function(r){u=new n.Deferrals(r,{parent:o,filename:"src/icedlib.coffee",funcname:"Pipeliner.__defer"}),i=u.defer({lineno:109}),e[0]=function(){var e,n;return e=1<=arguments.length?f.call(arguments,0):[],(n=t.assign_fn)!=null&&n.apply(null,e),i()},u._fulfill()}(function(){l.n_out--;if(l.cb)return r=l.cb,l.cb=null,r()})},e.prototype._defer=function(e){var t;return t=[],this.__defer(t,e),t[0]},e.prototype.flush=function(e){var t,r,i,s,o,u=this;i=e,t=n.findDeferral(arguments),s=[],o=function(e){var i,a,f;i=function(){return e(s)},a=function(){return o(e)},f=function(e){return s.push(e),a()};if(!u.n_out)return i();(function(e){r=new n.Deferrals(e,{parent:t,filename:"src/icedlib.coffee",funcname:"Pipeliner.flush"}),u.cb=r.defer({lineno:136}),r._fulfill()})(f)},o(i)},e}()}).call(this)},require["./coffee-script"]}();typeof define=="function"&&define.amd?(define(function(){return CoffeeScript}),define(function(){return CoffeeScript.iced})):(root.CoffeeScript=CoffeeScript,root.iced=CoffeeScript.iced)})(this); \ No newline at end of file diff --git a/EditorExtensions/Resources/Scripts/JSDocComments.js b/EditorExtensions/Resources/Scripts/JSDocComments.js new file mode 100644 index 000000000..a8987834e --- /dev/null +++ b/EditorExtensions/Resources/Scripts/JSDocComments.js @@ -0,0 +1,185 @@ +(function () { + + intellisense.addEventListener("statementcompletionhint", function (event) { + var itemValue = event.completionItem.value; + if (typeof itemValue === "function") + if (!canApplyComments(event.symbolHelp.functionHelp)) return; + //non functions will only have one documentation type, therefore, no need to check symbolHelp fileds + var comments = event.completionItem.comments; + if (!isJSDocComment(comments)) return; + parseComment(comments, event); + }); + + function canApplyComments(functionHelp) { + var signatures = functionHelp.signatures; + var signature = signatures[0]; + if (signatures.length > 1) return false; + if (signature.description && signature.description.charAt(0) != "*") return false; + if (!signature.params.every(function (param) { return !param.description; })) return false; + return true; + } + + intellisense.addEventListener("signaturehelp", function (event) { + if (!canApplyComments(event.functionHelp)) return; + if (!isJSDocComment(event.functionComments.above)) return + parseComment(event.functionComments.above, event); + }); + + intellisense.addEventListener("statementcompletion", function (event) { + var i = 0; + while (i < event.items.length) { + var item = event.items[i]; + var isHidden = false; + var comments = item.comments; + if (isJSDocComment(comments)) + isHidden = parseCommentForCompletionItem(comments, item); + if (isHidden) event.items.splice(i, 1); + else i++; + } + }); + + function isJSDocComment(comments) { + return comments.length > 0 && comments.charAt(0) == "*"; + } + + var tagPattern = /^[* ]*@(\w+)[ ]?(.*)$/img; + + function parseCommentForCompletionItem(comment, completionItem) { + ///Returns true if the cpmpletionItem should be hidden from the + /// completionItem list + var obj = {}; + var tag = null; + while (tag = tagPattern.exec(comment)) obj["_" + tag[1]] = true; + completionItem.glyph = (obj._class && "vs:GlyphGroupClass") || + (obj._constructor && "vs:GlyphGroupClass") || + (obj._namespace && "vs:GlyphGroupNamespace") || + (obj._event && "vs:GlyphGroupEvent") || + (obj._enum && "vs:GlyphGroupEnum") || + (obj._interface && "vs:GlyphGroupInterface"); + return obj._private || obj._ignore; + } + + var typePattern = /{([a-zA-Z0-9(),=.]+)}/; + var namePattern = /\[*(\w+)\]*/; + + function JSDoc(commentStringArr) { + this.params = []; + //to prevent ShowPlainComments from overwriting description field for items with JSDoc + //set the description to " ". + this.description = " "; + this.returnType = null; + this.type = null; + this._deprecated = false; + for (var i = 0; i < commentStringArr.length; i++) { + var description = commentStringArr[i]; + var desArr = description.split(" "); + this["_" + desArr[0].substr(1)] = true; + tagName = desArr[0]; + switch (tagName) { + case "@description": + desArr.splice(0, 1); + this.description = desArr.join(" "); + break; + case "@type": + this.type = desArr[1]; + break; + case "@returns": + this.returnType = typePattern.exec(desArr[1])[1]; + if (this.returnType == "void") this.returnType = ""; + break; + case "@param": + var param = {}; + var name = namePattern.exec(desArr[2]); + param.name = name[1]; + param.type = typePattern.exec(desArr[1])[1].replace("...", ""); + if (param.type.charAt(param.type.length - 1) == "=") { + param.isOptional = true; + param.type = param.type.substr(0, param.type.length - 1); + } + if (param.type.toLowerCase().indexOf("function") >= 0) { + var type = param.type; + param.type = "function"; + param.functionParas = type.slice(type.indexOf("(") + 1, type.indexOf(")")).split(","); + } + param.isOptional = param.isOptional || name[0].charAt(0) == "["; + desArr.splice(0, 3); + param.description = desArr.join(" "); + this.params.push(param); + break; + } + } + }; + + var splitAtRegExp = /[ *]*[\r\n][ *]*/; + + function processComment(commentString) { + //replace the first "*" with a "*\r\n" + commentString = commentString.replace("*", "*\r\n"); + //remove consecutive spaces + commentString = commentString.replace(/[ ]+/g, " "); + //split at each new line [strip leading "*"s and spaces] + var arr = commentString.split(splitAtRegExp); + index = 0; + while (index < arr.length) { + if (arr[index].length == 0) { + arr.splice(index, 1); + continue; + } + if (arr[index].charAt(0) != "@") { + if (index != 0) { + //remainder of a description found. concatinate it with the string above it. + arr[index] = arr[index - 1] + " " + arr[index]; + //remove the previous string from the array. + arr.splice(index - 1, 1); + } else { + //inline description found - add "@description" tag + arr[index] = "@description " + arr[index]; + } + } else { + //new tag found. continue to the next tag + index++; + } + } + return arr; + } + + function parseComment(comment, event) { + var doc = new JSDoc(processComment(comment)); + //if the completion item is a function, then do + var sig = event.functionHelp.signatures[0] || event.symbolHelp.functionHelp.signatures[0]; + var symHlp = event.symbolHelp; + if (symHlp) symHlp.description = ((doc._deprecated && "[deprecated]") || "") + (doc.description || ""); + sig.description = ((doc._deprecated && "[deprecated]") || "") + (doc.description || ""); + + if (symHlp) { + symHlp.type = doc.type; + symHlp.symbolDisplayType = doc.type; + } + sig.returnValue = new ReturnValue(); + sig.returnValue.type = doc.returnType; + sig.returnValue.elementType = doc.returnType; + for (var i = 0; i < doc.params.length; i++) { + var param = doc.params[i]; + for (var j = 0; j < sig.params.length; j++) { + //search for the right parameter to modify + if (sig.params[j].name == param.name) { + //if param type is function, set the params for the function + if (param.type.toLowerCase() == "function") { + sig.params[j].funcParamSignature = new Signature(); + sig.params[j].funcParamSignature.params = []; + for (var k = 0; k < param.functionParas.length; k++) { + var para = new Parameter(); + para.name = param.functionParas[k]; + sig.params[j].funcParamSignature.params.push(para); + } + } + sig.params[j].type = param.type; + sig.params[j].optional = param.isOptional; + sig.params[j].description = param.description; + break; + } + } + } + return doc._private || doc._ignore; + } +})(); diff --git a/EditorExtensions/Resources/Scripts/jshint.js b/EditorExtensions/Resources/Scripts/jshint.js new file mode 100644 index 000000000..9d1d0ebec --- /dev/null +++ b/EditorExtensions/Resources/Scripts/jshint.js @@ -0,0 +1,4538 @@ +/*! + * JSHint, by JSHint Community. + * + * Licensed under the same slightly modified MIT license that JSLint is. + * It stops evil-doers everywhere. + * + * JSHint is a derivative work of JSLint: + * + * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * The Software shall be used for Good, not Evil. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * JSHint was forked from 2010-12-16 edition of JSLint. + * + */ + +/* + JSHINT is a global function. It takes two parameters. + + var myResult = JSHINT(source, option); + + The first parameter is either a string or an array of strings. If it is a + string, it will be split on '\n' or '\r'. If it is an array of strings, it + is assumed that each string represents one line. The source can be a + JavaScript text or a JSON text. + + The second parameter is an optional object of options which control the + operation of JSHINT. Most of the options are booleans: They are all + optional and have a default value of false. One of the options, predef, + can be an array of names, which will be used to declare global variables, + or an object whose keys are used as global names, with a boolean value + that determines if they are assignable. + + If it checks out, JSHINT returns true. Otherwise, it returns false. + + If false, you can inspect JSHINT.errors to find out the problems. + JSHINT.errors is an array of objects containing these members: + + { + line : The line (relative to 1) at which the lint was found + character : The character (relative to 1) at which the lint was found + reason : The problem + evidence : The text line in which the problem occurred + raw : The raw message before the details were inserted + a : The first detail + b : The second detail + c : The third detail + d : The fourth detail + } + + If a fatal error was found, a null will be the last element of the + JSHINT.errors array. + + You can request a Function Report, which shows all of the functions + and the parameters and vars that they use. This can be used to find + implied global variables and other problems. The report is in HTML and + can be inserted in an HTML . + + var myReport = JSHINT.report(limited); + + If limited is true, then the report will be limited to only errors. + + You can request a data structure which contains JSHint's results. + + var myData = JSHINT.data(); + + It returns a structure with this form: + + { + errors: [ + { + line: NUMBER, + character: NUMBER, + reason: STRING, + evidence: STRING + } + ], + functions: [ + name: STRING, + line: NUMBER, + character: NUMBER, + last: NUMBER, + lastcharacter: NUMBER, + param: [ + STRING + ], + closure: [ + STRING + ], + var: [ + STRING + ], + exception: [ + STRING + ], + outer: [ + STRING + ], + unused: [ + STRING + ], + global: [ + STRING + ], + label: [ + STRING + ] + ], + globals: [ + STRING + ], + member: { + STRING: NUMBER + }, + unused: [ + { + name: STRING, + line: NUMBER + } + ], + implieds: [ + { + name: STRING, + line: NUMBER + } + ], + urls: [ + STRING + ], + json: BOOLEAN + } + + Empty arrays will not be included. + +*/ + +/*jshint + evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true, + undef: true, maxlen: 100, indent: 4, quotmark: double, unused: true +*/ + +/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)", + "(breakage)", "(character)", "(context)", "(error)", "(global)", "(identifier)", "(last)", + "(lastcharacter)", "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)", + "(statement)", "(verb)", "(tokens)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==", + "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax, + __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio, + Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas, + CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date, + Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, DOMParser, Drag, + E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event, + Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form, + FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey, + HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement, + HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement, + HTMLDivElement, HTMLDListElement, HTMLFieldSetElement, + HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement, + HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement, + HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement, + HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement, + HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement, + HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement, + HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement, + HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement, + HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement, + HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement, + HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement, + Iframe, IframeShim, Image, importScripts, Int16Array, Int32Array, Int8Array, + Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E, + MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort, + MoveAnimation, MooTools, MutationObserver, Native, NEGATIVE_INFINITY, Node, NodeFilter, + Number, Object, ObjectRange, + Option, Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype, + RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, + SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion, + ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller, + Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables, + SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template, + Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL, + VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer, + XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, + "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, + asi, atob, b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, c, + call, callee, caller, camelcase, cases, charAt, charCodeAt, character, clearInterval, + clearTimeout, close, closed, closure, comment, condition, confirm, console, constructor, + content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI, + decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document, + dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent, + eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil, + ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, forEach, + forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions, + g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict, + hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include, + indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray, + isDigit, isFinite, isNaN, iterator, java, join, jshint, + JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastcharacter, lastsemic, laxbreak, + laxcomma, latedef, lbp, led, left, length, line, load, loadClass, localStorage, location, + log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy, + moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen, + nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus, + onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param, + parent, parseFloat, parseInt, passfail, plusplus, postMessage, predef, print, process, prompt, + proto, prototype, prototypejs, provides, push, quit, quotmark, range, raw, reach, reason, regexp, + readFile, readUrl, regexdash, removeEventListener, replace, report, require, + reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right, + runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal, self, + send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice, + smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow, + supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, tokens, top, + trailing, type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, + urls, validthis, value, valueOf, var, vars, version, WebSocket, withstmt, white, window, windows, + Worker, worker, wsh*/ + +/*global exports: false */ + +// We build the application inside a function so that we produce only a single +// global variable. That function will be invoked immediately, and its return +// value is the JSHINT function itself. + +var JSHINT = (function () { + "use strict"; + + var anonname, // The guessed name for anonymous functions. + +// These are operators that should not be used with the ! operator. + + bang = { + "<" : true, + "<=" : true, + "==" : true, + "===": true, + "!==": true, + "!=" : true, + ">" : true, + ">=" : true, + "+" : true, + "-" : true, + "*" : true, + "/" : true, + "%" : true + }, + + // These are the JSHint boolean options. + boolOptions = { + asi : true, // if automatic semicolon insertion should be tolerated + bitwise : true, // if bitwise operators should not be allowed + boss : true, // if advanced usage of assignments should be allowed + browser : true, // if the standard browser globals should be predefined + camelcase : true, // if identifiers should be required in camel case + couch : true, // if CouchDB globals should be predefined + curly : true, // if curly braces around all blocks should be required + debug : true, // if debugger statements should be allowed + devel : true, // if logging globals should be predefined (console, + // alert, etc.) + dojo : true, // if Dojo Toolkit globals should be predefined + eqeqeq : true, // if === should be required + eqnull : true, // if == null comparisons should be tolerated + es5 : true, // if ES5 syntax should be allowed + esnext : true, // if es.next specific syntax should be allowed + evil : true, // if eval should be allowed + expr : true, // if ExpressionStatement should be allowed as Programs + forin : true, // if for in statements must filter + funcscope : true, // if only function scope should be used for scope tests + globalstrict: true, // if global "use strict"; should be allowed (also + // enables 'strict') + immed : true, // if immediate invocations must be wrapped in parens + iterator : true, // if the `__iterator__` property should be allowed + jquery : true, // if jQuery globals should be predefined + lastsemic : true, // if semicolons may be ommitted for the trailing + // statements inside of a one-line blocks. + latedef : true, // if the use before definition should not be tolerated + laxbreak : true, // if line breaks should not be checked + laxcomma : true, // if line breaks should not be checked around commas + loopfunc : true, // if functions should be allowed to be defined within + // loops + mootools : true, // if MooTools globals should be predefined + multistr : true, // allow multiline strings + newcap : true, // if constructor names must be capitalized + noarg : true, // if arguments.caller and arguments.callee should be + // disallowed + node : true, // if the Node.js environment globals should be + // predefined + noempty : true, // if empty blocks should be disallowed + nonew : true, // if using `new` for side-effects should be disallowed + nonstandard : true, // if non-standard (but widely adopted) globals should + // be predefined + nomen : true, // if names should be checked + onevar : true, // if only one var statement per function should be + // allowed + onecase : true, // if one case switch statements should be allowed + passfail : true, // if the scan should stop on first error + plusplus : true, // if increment/decrement should not be allowed + proto : true, // if the `__proto__` property should be allowed + prototypejs : true, // if Prototype and Scriptaculous globals should be + // predefined + regexdash : true, // if unescaped first/last dash (-) inside brackets + // should be tolerated + regexp : true, // if the . should not be allowed in regexp literals + rhino : true, // if the Rhino environment globals should be predefined + undef : true, // if variables should be declared before used + unused : true, // if variables should be always used + scripturl : true, // if script-targeted URLs should be tolerated + shadow : true, // if variable shadowing should be tolerated + smarttabs : true, // if smarttabs should be tolerated + // (http://www.emacswiki.org/emacs/SmartTabs) + strict : true, // require the "use strict"; pragma + sub : true, // if all forms of subscript notation are tolerated + supernew : true, // if `new function () { ... };` and `new Object;` + // should be tolerated + trailing : true, // if trailing whitespace rules apply + validthis : true, // if 'this' inside a non-constructor function is valid. + // This is a function scoped option only. + withstmt : true, // if with statements should be allowed + white : true, // if strict whitespace rules apply + worker : true, // if Web Worker script symbols should be allowed + wsh : true // if the Windows Scripting Host environment globals + // should be predefined + }, + + // These are the JSHint options that can take any value + // (we use this object to detect invalid options) + valOptions = { + maxlen: false, + indent: false, + maxerr: false, + predef: false, + quotmark: false //'single'|'double'|true + }, + + // These are JSHint boolean options which are shared with JSLint + // where the definition in JSHint is opposite JSLint + invertedOptions = { + bitwise : true, + forin : true, + newcap : true, + nomen : true, + plusplus : true, + regexp : true, + undef : true, + white : true, + + // Inverted and renamed, use JSHint name here + eqeqeq : true, + onevar : true + }, + + // These are JSHint boolean options which are shared with JSLint + // where the name has been changed but the effect is unchanged + renamedOptions = { + eqeq : "eqeqeq", + vars : "onevar", + windows : "wsh" + }, + + + // browser contains a set of global names which are commonly provided by a + // web browser environment. + browser = { + ArrayBuffer : false, + ArrayBufferView : false, + Audio : false, + addEventListener : false, + applicationCache : false, + atob : false, + blur : false, + btoa : false, + clearInterval : false, + clearTimeout : false, + close : false, + closed : false, + DataView : false, + DOMParser : false, + defaultStatus : false, + document : false, + event : false, + FileReader : false, + Float32Array : false, + Float64Array : false, + FormData : false, + focus : false, + frames : false, + getComputedStyle : false, + HTMLElement : false, + HTMLAnchorElement : false, + HTMLBaseElement : false, + HTMLBlockquoteElement : false, + HTMLBodyElement : false, + HTMLBRElement : false, + HTMLButtonElement : false, + HTMLCanvasElement : false, + HTMLDirectoryElement : false, + HTMLDivElement : false, + HTMLDListElement : false, + HTMLFieldSetElement : false, + HTMLFontElement : false, + HTMLFormElement : false, + HTMLFrameElement : false, + HTMLFrameSetElement : false, + HTMLHeadElement : false, + HTMLHeadingElement : false, + HTMLHRElement : false, + HTMLHtmlElement : false, + HTMLIFrameElement : false, + HTMLImageElement : false, + HTMLInputElement : false, + HTMLIsIndexElement : false, + HTMLLabelElement : false, + HTMLLayerElement : false, + HTMLLegendElement : false, + HTMLLIElement : false, + HTMLLinkElement : false, + HTMLMapElement : false, + HTMLMenuElement : false, + HTMLMetaElement : false, + HTMLModElement : false, + HTMLObjectElement : false, + HTMLOListElement : false, + HTMLOptGroupElement : false, + HTMLOptionElement : false, + HTMLParagraphElement : false, + HTMLParamElement : false, + HTMLPreElement : false, + HTMLQuoteElement : false, + HTMLScriptElement : false, + HTMLSelectElement : false, + HTMLStyleElement : false, + HTMLTableCaptionElement : false, + HTMLTableCellElement : false, + HTMLTableColElement : false, + HTMLTableElement : false, + HTMLTableRowElement : false, + HTMLTableSectionElement : false, + HTMLTextAreaElement : false, + HTMLTitleElement : false, + HTMLUListElement : false, + HTMLVideoElement : false, + history : false, + Int16Array : false, + Int32Array : false, + Int8Array : false, + Image : false, + length : false, + localStorage : false, + location : false, + MessageChannel : false, + MessageEvent : false, + MessagePort : false, + moveBy : false, + moveTo : false, + MutationObserver : false, + name : false, + Node : false, + NodeFilter : false, + navigator : false, + onbeforeunload : true, + onblur : true, + onerror : true, + onfocus : true, + onload : true, + onresize : true, + onunload : true, + open : false, + openDatabase : false, + opener : false, + Option : false, + parent : false, + print : false, + removeEventListener : false, + resizeBy : false, + resizeTo : false, + screen : false, + scroll : false, + scrollBy : false, + scrollTo : false, + sessionStorage : false, + setInterval : false, + setTimeout : false, + SharedWorker : false, + status : false, + top : false, + Uint16Array : false, + Uint32Array : false, + Uint8Array : false, + WebSocket : false, + window : false, + Worker : false, + XMLHttpRequest : false, + XMLSerializer : false, + XPathEvaluator : false, + XPathException : false, + XPathExpression : false, + XPathNamespace : false, + XPathNSResolver : false, + XPathResult : false + }, + + couch = { + "require" : false, + respond : false, + getRow : false, + emit : false, + send : false, + start : false, + sum : false, + log : false, + exports : false, + module : false, + provides : false + }, + + declared, // Globals that were declared using /*global ... */ syntax. + + devel = { + alert : false, + confirm : false, + console : false, + Debug : false, + opera : false, + prompt : false + }, + + dojo = { + dojo : false, + dijit : false, + dojox : false, + define : false, + "require" : false + }, + + funct, // The current function + + functionicity = [ + "closure", "exception", "global", "label", + "outer", "unused", "var" + ], + + functions, // All of the functions + + global, // The global scope + implied, // Implied globals + inblock, + indent, + jsonmode, + + jquery = { + "$" : false, + jQuery : false + }, + + lines, + lookahead, + member, + membersOnly, + + mootools = { + "$" : false, + "$$" : false, + Assets : false, + Browser : false, + Chain : false, + Class : false, + Color : false, + Cookie : false, + Core : false, + Document : false, + DomReady : false, + DOMReady : false, + Drag : false, + Element : false, + Elements : false, + Event : false, + Events : false, + Fx : false, + Group : false, + Hash : false, + HtmlTable : false, + Iframe : false, + IframeShim : false, + InputValidator : false, + instanceOf : false, + Keyboard : false, + Locale : false, + Mask : false, + MooTools : false, + Native : false, + Options : false, + OverText : false, + Request : false, + Scroller : false, + Slick : false, + Slider : false, + Sortables : false, + Spinner : false, + Swiff : false, + Tips : false, + Type : false, + typeOf : false, + URI : false, + Window : false + }, + + nexttoken, + + node = { + __filename : false, + __dirname : false, + Buffer : false, + console : false, + exports : true, // In Node it is ok to exports = module.exports = foo(); + GLOBAL : false, + global : false, + module : false, + process : false, + require : false, + setTimeout : false, + clearTimeout : false, + setInterval : false, + clearInterval : false + }, + + noreach, + option, + predefined, // Global variables defined by option + prereg, + prevtoken, + + prototypejs = { + "$" : false, + "$$" : false, + "$A" : false, + "$F" : false, + "$H" : false, + "$R" : false, + "$break" : false, + "$continue" : false, + "$w" : false, + Abstract : false, + Ajax : false, + Class : false, + Enumerable : false, + Element : false, + Event : false, + Field : false, + Form : false, + Hash : false, + Insertion : false, + ObjectRange : false, + PeriodicalExecuter: false, + Position : false, + Prototype : false, + Selector : false, + Template : false, + Toggle : false, + Try : false, + Autocompleter : false, + Builder : false, + Control : false, + Draggable : false, + Draggables : false, + Droppables : false, + Effect : false, + Sortable : false, + SortableObserver : false, + Sound : false, + Scriptaculous : false + }, + + quotmark, + + rhino = { + defineClass : false, + deserialize : false, + gc : false, + help : false, + importPackage: false, + "java" : false, + load : false, + loadClass : false, + print : false, + quit : false, + readFile : false, + readUrl : false, + runCommand : false, + seal : false, + serialize : false, + spawn : false, + sync : false, + toint32 : false, + version : false + }, + + scope, // The current scope + stack, + + // standard contains the global names that are provided by the + // ECMAScript standard. + standard = { + Array : false, + Boolean : false, + Date : false, + decodeURI : false, + decodeURIComponent : false, + encodeURI : false, + encodeURIComponent : false, + Error : false, + "eval" : false, + EvalError : false, + Function : false, + hasOwnProperty : false, + isFinite : false, + isNaN : false, + JSON : false, + Math : false, + Number : false, + Object : false, + parseInt : false, + parseFloat : false, + RangeError : false, + ReferenceError : false, + RegExp : false, + String : false, + SyntaxError : false, + TypeError : false, + URIError : false + }, + + // widely adopted global names that are not part of ECMAScript standard + nonstandard = { + escape : false, + unescape : false + }, + + directive, + syntax = {}, + tab, + token, + urls, + useESNextSyntax, + warnings, + + worker = { + importScripts : true, + postMessage : true, + self : true + }, + + wsh = { + ActiveXObject : true, + Enumerator : true, + GetObject : true, + ScriptEngine : true, + ScriptEngineBuildVersion : true, + ScriptEngineMajorVersion : true, + ScriptEngineMinorVersion : true, + VBArray : true, + WSH : true, + WScript : true, + XDomainRequest : true + }; + + // Regular expressions. Some of these are stupidly long. + var ax, cx, tx, nx, nxg, lx, ix, jx, ft; + (function () { + /*jshint maxlen:300 */ + + // unsafe comment or string + ax = /@cc|<\/?|script|\]\s*\]|<\s*!|</i; + + // unsafe characters that are silently deleted by one or more browsers + cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; + + // token + tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/; + + // characters in strings that need escapement + nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; + nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + + // star slash + lx = /\*\/|\/\*/; + + // identifier + ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; + + // javascript url + jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; + + // catches /* falls through */ comments + ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/; + }()); + + function F() {} // Used by Object.create + + function is_own(object, name) { + // The object.hasOwnProperty method fails when the property under consideration + // is named 'hasOwnProperty'. So we have to use this more convoluted form. + return Object.prototype.hasOwnProperty.call(object, name); + } + + function checkOption(name, t) { + if (valOptions[name] === undefined && boolOptions[name] === undefined) { + warning("Bad option: '" + name + "'.", t); + } + } + + function isString(obj) { + return Object.prototype.toString.call(obj) === "[object String]"; + } + + // Provide critical ES5 functions to ES3. + + if (typeof Array.isArray !== "function") { + Array.isArray = function (o) { + return Object.prototype.toString.apply(o) === "[object Array]"; + }; + } + + if (!Array.prototype.forEach) { + Array.prototype.forEach = function (fn, scope) { + var len = this.length; + + for (var i = 0; i < len; i++) { + fn.call(scope || this, this[i], i, this); + } + }; + } + + if (typeof Object.create !== "function") { + Object.create = function (o) { + F.prototype = o; + return new F(); + }; + } + + if (typeof Object.keys !== "function") { + Object.keys = function (o) { + var a = [], k; + for (k in o) { + if (is_own(o, k)) { + a.push(k); + } + } + return a; + }; + } + + // Non standard methods + + function isAlpha(str) { + return (str >= "a" && str <= "z\uffff") || + (str >= "A" && str <= "Z\uffff"); + } + + function isDigit(str) { + return (str >= "0" && str <= "9"); + } + + function supplant(str, data) { + return str.replace(/\{([^{}]*)\}/g, function (a, b) { + var r = data[b]; + return typeof r === "string" || typeof r === "number" ? r : a; + }); + } + + function combine(t, o) { + var n; + for (n in o) { + if (is_own(o, n)) { + t[n] = o[n]; + } + } + } + + function assume() { + if (option.couch) { + combine(predefined, couch); + } + + if (option.rhino) { + combine(predefined, rhino); + } + + if (option.prototypejs) { + combine(predefined, prototypejs); + } + + if (option.node) { + combine(predefined, node); + option.globalstrict = true; + } + + if (option.devel) { + combine(predefined, devel); + } + + if (option.dojo) { + combine(predefined, dojo); + } + + if (option.browser) { + combine(predefined, browser); + } + + if (option.nonstandard) { + combine(predefined, nonstandard); + } + + if (option.jquery) { + combine(predefined, jquery); + } + + if (option.mootools) { + combine(predefined, mootools); + } + + if (option.worker) { + combine(predefined, worker); + } + + if (option.wsh) { + combine(predefined, wsh); + } + + if (option.esnext) { + useESNextSyntax(); + } + + if (option.globalstrict && option.strict !== false) { + option.strict = true; + } + } + + + // Produce an error warning. + function quit(message, line, chr) { + var percentage = Math.floor((line / lines.length) * 100); + + throw { + name: "JSHintError", + line: line, + character: chr, + message: message + " (" + percentage + "% scanned).", + raw: message + }; + } + + function isundef(scope, m, t, a) { + return JSHINT.undefs.push([scope, m, t, a]); + } + + function warning(m, t, a, b, c, d) { + var ch, l, w; + t = t || nexttoken; + if (t.id === "(end)") { // `~ + t = token; + } + l = t.line || 0; + ch = t.from || 0; + w = { + id: "(error)", + raw: m, + evidence: lines[l - 1] || "", + line: l, + character: ch, + a: a, + b: b, + c: c, + d: d + }; + w.reason = supplant(m, w); + JSHINT.errors.push(w); + if (option.passfail) { + quit("Stopping. ", l, ch); + } + warnings += 1; + if (warnings >= option.maxerr) { + quit("Too many errors.", l, ch); + } + return w; + } + + function warningAt(m, l, ch, a, b, c, d) { + return warning(m, { + line: l, + from: ch + }, a, b, c, d); + } + + function error(m, t, a, b, c, d) { + warning(m, t, a, b, c, d); + } + + function errorAt(m, l, ch, a, b, c, d) { + return error(m, { + line: l, + from: ch + }, a, b, c, d); + } + + + +// lexical analysis and token construction + + var lex = (function lex() { + var character, from, line, s; + +// Private lex methods + + function nextLine() { + var at, + tw; // trailing whitespace check + + if (line >= lines.length) + return false; + + character = 1; + s = lines[line]; + line += 1; + + // If smarttabs option is used check for spaces followed by tabs only. + // Otherwise check for any occurence of mixed tabs and spaces. + // Tabs and one space followed by block comment is allowed. + if (option.smarttabs) + at = s.search(/ \t/); + else + at = s.search(/ \t|\t [^\*]/); + + if (at >= 0) + warningAt("Mixed spaces and tabs.", line, at + 1); + + s = s.replace(/\t/g, tab); + at = s.search(cx); + + if (at >= 0) + warningAt("Unsafe character.", line, at); + + if (option.maxlen && option.maxlen < s.length) + warningAt("Line too long.", line, s.length); + + // Check for trailing whitespaces + tw = option.trailing && s.match(/^(.*?)\s+$/); + if (tw && !/^\s+$/.test(s)) { + warningAt("Trailing whitespace.", line, tw[1].length + 1); + } + return true; + } + +// Produce a token object. The token inherits from a syntax symbol. + + function it(type, value) { + var i, t; + + function checkName(name) { + if (!option.proto && name === "__proto__") { + warningAt("The '{a}' property is deprecated.", line, from, name); + return; + } + + if (!option.iterator && name === "__iterator__") { + warningAt("'{a}' is only available in JavaScript 1.7.", line, from, name); + return; + } + + // Check for dangling underscores unless we're in Node + // environment and this identifier represents built-in + // Node globals with underscores. + + var hasDangling = /^(_+.*|.*_+)$/.test(name); + + if (option.nomen && hasDangling && name !== "_") { + if (option.node && token.id !== "." && /^(__dirname|__filename)$/.test(name)) + return; + + warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", name); + return; + } + + // Check for non-camelcase names. Names like MY_VAR and + // _myVar are okay though. + + if (option.camelcase) { + if (name.replace(/^_+/, "").indexOf("_") > -1 && !name.match(/^[A-Z0-9_]*$/)) { + warningAt("Identifier '{a}' is not in camel case.", line, from, value); + } + } + } + + if (type === "(color)" || type === "(range)") { + t = {type: type}; + } else if (type === "(punctuator)" || + (type === "(identifier)" && is_own(syntax, value))) { + t = syntax[value] || syntax["(error)"]; + } else { + t = syntax[type]; + } + + t = Object.create(t); + + if (type === "(string)" || type === "(range)") { + if (!option.scripturl && jx.test(value)) { + warningAt("Script URL.", line, from); + } + } + + if (type === "(identifier)") { + t.identifier = true; + checkName(value); + } + + t.value = value; + t.line = line; + t.character = character; + t.from = from; + i = t.id; + if (i !== "(endline)") { + prereg = i && + (("(,=:[!&|?{};".indexOf(i.charAt(i.length - 1)) >= 0) || + i === "return" || + i === "case"); + } + return t; + } + + // Public lex methods + return { + init: function (source) { + if (typeof source === "string") { + lines = source + .replace(/\r\n/g, "\n") + .replace(/\r/g, "\n") + .split("\n"); + } else { + lines = source; + } + + // If the first line is a shebang (#!), make it a blank and move on. + // Shebangs are used by Node scripts. + if (lines[0] && lines[0].substr(0, 2) === "#!") + lines[0] = ""; + + line = 0; + nextLine(); + from = 1; + }, + + range: function (begin, end) { + var c, value = ""; + from = character; + if (s.charAt(0) !== begin) { + errorAt("Expected '{a}' and instead saw '{b}'.", + line, character, begin, s.charAt(0)); + } + for (;;) { + s = s.slice(1); + character += 1; + c = s.charAt(0); + switch (c) { + case "": + errorAt("Missing '{a}'.", line, character, c); + break; + case end: + s = s.slice(1); + character += 1; + return it("(range)", value); + case "\\": + warningAt("Unexpected '{a}'.", line, character, c); + } + value += c; + } + + }, + + + // token -- this is called by advance to get the next token + token: function () { + var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n; + + function match(x) { + var r = x.exec(s), r1; + if (r) { + l = r[0].length; + r1 = r[1]; + c = r1.charAt(0); + s = s.substr(l); + from = character + l - r1.length; + character += l; + return r1; + } + } + + function string(x) { + var c, j, r = "", allowNewLine = false; + + if (jsonmode && x !== "\"") { + warningAt("Strings must use doublequote.", + line, character); + } + + if (option.quotmark) { + if (option.quotmark === "single" && x !== "'") { + warningAt("Strings must use singlequote.", + line, character); + } else if (option.quotmark === "double" && x !== "\"") { + warningAt("Strings must use doublequote.", + line, character); + } else if (option.quotmark === true) { + quotmark = quotmark || x; + if (quotmark !== x) { + warningAt("Mixed double and single quotes.", + line, character); + } + } + } + + function esc(n) { + var i = parseInt(s.substr(j + 1, n), 16); + j += n; + if (i >= 32 && i <= 126 && + i !== 34 && i !== 92 && i !== 39) { + warningAt("Unnecessary escapement.", line, character); + } + character += n; + c = String.fromCharCode(i); + } + j = 0; +unclosedString: for (;;) { + while (j >= s.length) { + j = 0; + + var cl = line, cf = from; + if (!nextLine()) { + errorAt("Unclosed string.", cl, cf); + break unclosedString; + } + + if (allowNewLine) { + allowNewLine = false; + } else { + warningAt("Unclosed string.", cl, cf); + } + } + c = s.charAt(j); + if (c === x) { + character += 1; + s = s.substr(j + 1); + return it("(string)", r, x); + } + if (c < " ") { + if (c === "\n" || c === "\r") { + break; + } + warningAt("Control character in string: {a}.", + line, character + j, s.slice(0, j)); + } else if (c === "\\") { + j += 1; + character += 1; + c = s.charAt(j); + n = s.charAt(j + 1); + switch (c) { + case "\\": + case "\"": + case "/": + break; + case "\'": + if (jsonmode) { + warningAt("Avoid \\'.", line, character); + } + break; + case "b": + c = "\b"; + break; + case "f": + c = "\f"; + break; + case "n": + c = "\n"; + break; + case "r": + c = "\r"; + break; + case "t": + c = "\t"; + break; + case "0": + c = "\0"; + // Octal literals fail in strict mode + // check if the number is between 00 and 07 + // where 'n' is the token next to 'c' + if (n >= 0 && n <= 7 && directive["use strict"]) { + warningAt( + "Octal literals are not allowed in strict mode.", + line, character); + } + break; + case "u": + esc(4); + break; + case "v": + if (jsonmode) { + warningAt("Avoid \\v.", line, character); + } + c = "\v"; + break; + case "x": + if (jsonmode) { + warningAt("Avoid \\x-.", line, character); + } + esc(2); + break; + case "": + // last character is escape character + // always allow new line if escaped, but show + // warning if option is not set + allowNewLine = true; + if (option.multistr) { + if (jsonmode) { + warningAt("Avoid EOL escapement.", line, character); + } + c = ""; + character -= 1; + break; + } + warningAt("Bad escapement of EOL. Use option multistr if needed.", + line, character); + break; + default: + warningAt("Bad escapement.", line, character); + } + } + r += c; + character += 1; + j += 1; + } + } + + for (;;) { + if (!s) { + return it(nextLine() ? "(endline)" : "(end)", ""); + } + t = match(tx); + if (!t) { + t = ""; + c = ""; + while (s && s < "!") { + s = s.substr(1); + } + if (s) { + errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1)); + s = ""; + } + } else { + + // identifier + + if (isAlpha(c) || c === "_" || c === "$") { + return it("(identifier)", t); + } + + // number + + if (isDigit(c)) { + if (!isFinite(Number(t))) { + warningAt("Bad number '{a}'.", + line, character, t); + } + if (isAlpha(s.substr(0, 1))) { + warningAt("Missing space after '{a}'.", + line, character, t); + } + if (c === "0") { + d = t.substr(1, 1); + if (isDigit(d)) { + if (token.id !== ".") { + warningAt("Don't use extra leading zeros '{a}'.", + line, character, t); + } + } else if (jsonmode && (d === "x" || d === "X")) { + warningAt("Avoid 0x-. '{a}'.", + line, character, t); + } + } + if (t.substr(t.length - 1) === ".") { + warningAt( +"A trailing decimal point can be confused with a dot '{a}'.", line, character, t); + } + return it("(number)", t); + } + switch (t) { + + // string + + case "\"": + case "'": + return string(t); + + // // comment + + case "//": + s = ""; + token.comment = true; + break; + + // /* comment + + case "/*": + for (;;) { + i = s.search(lx); + if (i >= 0) { + break; + } + if (!nextLine()) { + errorAt("Unclosed comment.", line, character); + } + } + character += i + 2; + if (s.substr(i, 1) === "/") { + errorAt("Nested comment.", line, character); + } + s = s.substr(i + 2); + token.comment = true; + break; + + // /*members /*jshint /*global + + case "/*members": + case "/*member": + case "/*jshint": + case "/*jslint": + case "/*global": + case "*/": + return { + value: t, + type: "special", + line: line, + character: character, + from: from + }; + + case "": + break; + // / + case "/": + if (token.id === "/=") { + errorAt("A regular expression literal can be confused with '/='.", + line, from); + } + if (prereg) { + depth = 0; + captures = 0; + l = 0; + for (;;) { + b = true; + c = s.charAt(l); + l += 1; + switch (c) { + case "": + errorAt("Unclosed regular expression.", line, from); + return quit("Stopping.", line, from); + case "/": + if (depth > 0) { + warningAt("{a} unterminated regular expression " + + "group(s).", line, from + l, depth); + } + c = s.substr(0, l - 1); + q = { + g: true, + i: true, + m: true + }; + while (q[s.charAt(l)] === true) { + q[s.charAt(l)] = false; + l += 1; + } + character += l; + s = s.substr(l); + q = s.charAt(0); + if (q === "/" || q === "*") { + errorAt("Confusing regular expression.", + line, from); + } + return it("(regexp)", c); + case "\\": + c = s.charAt(l); + if (c < " ") { + warningAt( +"Unexpected control character in regular expression.", line, from + l); + } else if (c === "<") { + warningAt( +"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); + } + l += 1; + break; + case "(": + depth += 1; + b = false; + if (s.charAt(l) === "?") { + l += 1; + switch (s.charAt(l)) { + case ":": + case "=": + case "!": + l += 1; + break; + default: + warningAt( +"Expected '{a}' and instead saw '{b}'.", line, from + l, ":", s.charAt(l)); + } + } else { + captures += 1; + } + break; + case "|": + b = false; + break; + case ")": + if (depth === 0) { + warningAt("Unescaped '{a}'.", + line, from + l, ")"); + } else { + depth -= 1; + } + break; + case " ": + q = 1; + while (s.charAt(l) === " ") { + l += 1; + q += 1; + } + if (q > 1) { + warningAt( +"Spaces are hard to count. Use {{a}}.", line, from + l, q); + } + break; + case "[": + c = s.charAt(l); + if (c === "^") { + l += 1; + if (option.regexp) { + warningAt("Insecure '{a}'.", + line, from + l, c); + } else if (s.charAt(l) === "]") { + errorAt("Unescaped '{a}'.", + line, from + l, "^"); + } + } + if (c === "]") { + warningAt("Empty class.", line, + from + l - 1); + } + isLiteral = false; + isInRange = false; +klass: do { + c = s.charAt(l); + l += 1; + switch (c) { + case "[": + case "^": + warningAt("Unescaped '{a}'.", + line, from + l, c); + if (isInRange) { + isInRange = false; + } else { + isLiteral = true; + } + break; + case "-": + if (isLiteral && !isInRange) { + isLiteral = false; + isInRange = true; + } else if (isInRange) { + isInRange = false; + } else if (s.charAt(l) === "]") { + isInRange = true; + } else { + if (option.regexdash !== (l === 2 || (l === 3 && + s.charAt(1) === "^"))) { + warningAt("Unescaped '{a}'.", + line, from + l - 1, "-"); + } + isLiteral = true; + } + break; + case "]": + if (isInRange && !option.regexdash) { + warningAt("Unescaped '{a}'.", + line, from + l - 1, "-"); + } + break klass; + case "\\": + c = s.charAt(l); + if (c < " ") { + warningAt( +"Unexpected control character in regular expression.", line, from + l); + } else if (c === "<") { + warningAt( +"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); + } + l += 1; + + // \w, \s and \d are never part of a character range + if (/[wsd]/i.test(c)) { + if (isInRange) { + warningAt("Unescaped '{a}'.", + line, from + l, "-"); + isInRange = false; + } + isLiteral = false; + } else if (isInRange) { + isInRange = false; + } else { + isLiteral = true; + } + break; + case "/": + warningAt("Unescaped '{a}'.", + line, from + l - 1, "/"); + + if (isInRange) { + isInRange = false; + } else { + isLiteral = true; + } + break; + case "<": + if (isInRange) { + isInRange = false; + } else { + isLiteral = true; + } + break; + default: + if (isInRange) { + isInRange = false; + } else { + isLiteral = true; + } + } + } while (c); + break; + case ".": + if (option.regexp) { + warningAt("Insecure '{a}'.", line, + from + l, c); + } + break; + case "]": + case "?": + case "{": + case "}": + case "+": + case "*": + warningAt("Unescaped '{a}'.", line, + from + l, c); + } + if (b) { + switch (s.charAt(l)) { + case "?": + case "+": + case "*": + l += 1; + if (s.charAt(l) === "?") { + l += 1; + } + break; + case "{": + l += 1; + c = s.charAt(l); + if (c < "0" || c > "9") { + warningAt( +"Expected a number and instead saw '{a}'.", line, from + l, c); + } + l += 1; + low = +c; + for (;;) { + c = s.charAt(l); + if (c < "0" || c > "9") { + break; + } + l += 1; + low = +c + (low * 10); + } + high = low; + if (c === ",") { + l += 1; + high = Infinity; + c = s.charAt(l); + if (c >= "0" && c <= "9") { + l += 1; + high = +c; + for (;;) { + c = s.charAt(l); + if (c < "0" || c > "9") { + break; + } + l += 1; + high = +c + (high * 10); + } + } + } + if (s.charAt(l) !== "}") { + warningAt( +"Expected '{a}' and instead saw '{b}'.", line, from + l, "}", c); + } else { + l += 1; + } + if (s.charAt(l) === "?") { + l += 1; + } + if (low > high) { + warningAt( +"'{a}' should not be greater than '{b}'.", line, from + l, low, high); + } + } + } + } + c = s.substr(0, l - 1); + character += l; + s = s.substr(l); + return it("(regexp)", c); + } + return it("(punctuator)", t); + + // punctuator + + case "#": + return it("(punctuator)", t); + default: + return it("(punctuator)", t); + } + } + } + } + }; + }()); + + + function addlabel(t, type, token) { + + if (t === "hasOwnProperty") { + warning("'hasOwnProperty' is a really bad name."); + } + + // Define t in the current function in the current scope. + if (is_own(funct, t) && !funct["(global)"]) { + if (funct[t] === true) { + if (option.latedef) + warning("'{a}' was used before it was defined.", nexttoken, t); + } else { + if (!option.shadow && type !== "exception") + warning("'{a}' is already defined.", nexttoken, t); + } + } + + funct[t] = type; + + if (token) { + funct["(tokens)"][t] = token; + } + + if (funct["(global)"]) { + global[t] = funct; + if (is_own(implied, t)) { + if (option.latedef) + warning("'{a}' was used before it was defined.", nexttoken, t); + delete implied[t]; + } + } else { + scope[t] = funct; + } + } + + + function doOption() { + var nt = nexttoken; + var o = nt.value; + var quotmarkValue = option.quotmark; + var predef = {}; + var b, obj, filter, t, tn, v; + + switch (o) { + case "*/": + error("Unbegun comment."); + break; + case "/*members": + case "/*member": + o = "/*members"; + if (!membersOnly) { + membersOnly = {}; + } + obj = membersOnly; + option.quotmark = false; + break; + case "/*jshint": + case "/*jslint": + obj = option; + filter = boolOptions; + break; + case "/*global": + obj = predef; + break; + default: + error("What?"); + } + + t = lex.token(); +loop: for (;;) { + for (;;) { + if (t.type === "special" && t.value === "*/") { + break loop; + } + if (t.id !== "(endline)" && t.id !== ",") { + break; + } + t = lex.token(); + } + if (t.type !== "(string)" && t.type !== "(identifier)" && + o !== "/*members") { + error("Bad option.", t); + } + + v = lex.token(); + if (v.id === ":") { + v = lex.token(); + + if (obj === membersOnly) { + error("Expected '{a}' and instead saw '{b}'.", t, "*/", ":"); + } + + if (o === "/*jshint") { + checkOption(t.value, t); + } + + if (t.value === "indent" && (o === "/*jshint" || o === "/*jslint")) { + b = +v.value; + if (typeof b !== "number" || !isFinite(b) || b <= 0 || + Math.floor(b) !== b) { + error("Expected a small integer and instead saw '{a}'.", + v, v.value); + } + obj.white = true; + obj.indent = b; + } else if (t.value === "maxerr" && (o === "/*jshint" || o === "/*jslint")) { + b = +v.value; + if (typeof b !== "number" || !isFinite(b) || b <= 0 || + Math.floor(b) !== b) { + error("Expected a small integer and instead saw '{a}'.", + v, v.value); + } + obj.maxerr = b; + } else if (t.value === "maxlen" && (o === "/*jshint" || o === "/*jslint")) { + b = +v.value; + if (typeof b !== "number" || !isFinite(b) || b <= 0 || + Math.floor(b) !== b) { + error("Expected a small integer and instead saw '{a}'.", + v, v.value); + } + obj.maxlen = b; + } else if (t.value === "validthis") { + if (funct["(global)"]) { + error("Option 'validthis' can't be used in a global scope."); + } else { + if (v.value === "true" || v.value === "false") + obj[t.value] = v.value === "true"; + else + error("Bad option value.", v); + } + } else if (t.value === "quotmark" && (o === "/*jshint")) { + switch (v.value) { + case "true": + obj.quotmark = true; + break; + case "false": + obj.quotmark = false; + break; + case "double": + case "single": + obj.quotmark = v.value; + break; + default: + error("Bad option value.", v); + } + } else if (v.value === "true" || v.value === "false") { + if (o === "/*jslint") { + tn = renamedOptions[t.value] || t.value; + obj[tn] = v.value === "true"; + if (invertedOptions[tn] !== undefined) { + obj[tn] = !obj[tn]; + } + } else { + obj[t.value] = v.value === "true"; + } + } else { + error("Bad option value.", v); + } + t = lex.token(); + } else { + if (o === "/*jshint" || o === "/*jslint") { + error("Missing option value.", t); + } + obj[t.value] = false; + t = v; + } + } + + if (o === "/*members") { + option.quotmark = quotmarkValue; + } + + combine(predefined, predef); + + for (var key in predef) { + if (is_own(predef, key)) { + declared[key] = nt; + } + } + + if (filter) { + assume(); + } + } + + +// We need a peek function. If it has an argument, it peeks that much farther +// ahead. It is used to distinguish +// for ( var i in ... +// from +// for ( var i = ... + + function peek(p) { + var i = p || 0, j = 0, t; + + while (j <= i) { + t = lookahead[j]; + if (!t) { + t = lookahead[j] = lex.token(); + } + j += 1; + } + return t; + } + + + +// Produce the next token. It looks for programming errors. + + function advance(id, t) { + switch (token.id) { + case "(number)": + if (nexttoken.id === ".") { + warning("A dot following a number can be confused with a decimal point.", token); + } + break; + case "-": + if (nexttoken.id === "-" || nexttoken.id === "--") { + warning("Confusing minusses."); + } + break; + case "+": + if (nexttoken.id === "+" || nexttoken.id === "++") { + warning("Confusing plusses."); + } + break; + } + + if (token.type === "(string)" || token.identifier) { + anonname = token.value; + } + + if (id && nexttoken.id !== id) { + if (t) { + if (nexttoken.id === "(end)") { + warning("Unmatched '{a}'.", t, t.id); + } else { + warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", + nexttoken, id, t.id, t.line, nexttoken.value); + } + } else if (nexttoken.type !== "(identifier)" || + nexttoken.value !== id) { + warning("Expected '{a}' and instead saw '{b}'.", + nexttoken, id, nexttoken.value); + } + } + + prevtoken = token; + token = nexttoken; + for (;;) { + nexttoken = lookahead.shift() || lex.token(); + if (nexttoken.id === "(end)" || nexttoken.id === "(error)") { + return; + } + if (nexttoken.type === "special") { + doOption(); + } else { + if (nexttoken.id !== "(endline)") { + break; + } + } + } + } + + +// This is the heart of JSHINT, the Pratt parser. In addition to parsing, it +// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is +// like .nud except that it is only used on the first token of a statement. +// Having .fud makes it much easier to define statement-oriented languages like +// JavaScript. I retained Pratt's nomenclature. + +// .nud Null denotation +// .fud First null denotation +// .led Left denotation +// lbp Left binding power +// rbp Right binding power + +// They are elements of the parsing method called Top Down Operator Precedence. + + function expression(rbp, initial) { + var left, isArray = false, isObject = false; + + if (nexttoken.id === "(end)") + error("Unexpected early end of program.", token); + + advance(); + if (initial) { + anonname = "anonymous"; + funct["(verb)"] = token.value; + } + if (initial === true && token.fud) { + left = token.fud(); + } else { + if (token.nud) { + left = token.nud(); + } else { + if (nexttoken.type === "(number)" && token.id === ".") { + warning("A leading decimal point can be confused with a dot: '.{a}'.", + token, nexttoken.value); + advance(); + return token; + } else { + error("Expected an identifier and instead saw '{a}'.", + token, token.id); + } + } + while (rbp < nexttoken.lbp) { + isArray = token.value === "Array"; + isObject = token.value === "Object"; + + // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() + // Line breaks in IfStatement heads exist to satisfy the checkJSHint + // "Line too long." error. + if (left && (left.value || (left.first && left.first.value))) { + // If the left.value is not "new", or the left.first.value is a "." + // then safely assume that this is not "new Array()" and possibly + // not "new Object()"... + if (left.value !== "new" || + (left.first && left.first.value && left.first.value === ".")) { + isArray = false; + // ...In the case of Object, if the left.value and token.value + // are not equal, then safely assume that this not "new Object()" + if (left.value !== token.value) { + isObject = false; + } + } + } + + advance(); + if (isArray && token.id === "(" && nexttoken.id === ")") + warning("Use the array literal notation [].", token); + if (isObject && token.id === "(" && nexttoken.id === ")") + warning("Use the object literal notation {}.", token); + if (token.led) { + left = token.led(left); + } else { + error("Expected an operator and instead saw '{a}'.", + token, token.id); + } + } + } + return left; + } + + +// Functions for conformance of style. + + function adjacent(left, right) { + left = left || token; + right = right || nexttoken; + if (option.white) { + if (left.character !== right.from && left.line === right.line) { + left.from += (left.character - left.from); + warning("Unexpected space after '{a}'.", left, left.value); + } + } + } + + function nobreak(left, right) { + left = left || token; + right = right || nexttoken; + if (option.white && (left.character !== right.from || left.line !== right.line)) { + warning("Unexpected space before '{a}'.", right, right.value); + } + } + + function nospace(left, right) { + left = left || token; + right = right || nexttoken; + if (option.white && !left.comment) { + if (left.line === right.line) { + adjacent(left, right); + } + } + } + + function nonadjacent(left, right) { + if (option.white) { + left = left || token; + right = right || nexttoken; + if (left.value === ";" && right.value === ";") { + return; + } + if (left.line === right.line && left.character === right.from) { + left.from += (left.character - left.from); + warning("Missing space after '{a}'.", + left, left.value); + } + } + } + + function nobreaknonadjacent(left, right) { + left = left || token; + right = right || nexttoken; + if (!option.laxbreak && left.line !== right.line) { + warning("Bad line breaking before '{a}'.", right, right.id); + } else if (option.white) { + left = left || token; + right = right || nexttoken; + if (left.character === right.from) { + left.from += (left.character - left.from); + warning("Missing space after '{a}'.", + left, left.value); + } + } + } + + function indentation(bias) { + var i; + if (option.white && nexttoken.id !== "(end)") { + i = indent + (bias || 0); + if (nexttoken.from !== i) { + warning( +"Expected '{a}' to have an indentation at {b} instead at {c}.", + nexttoken, nexttoken.value, i, nexttoken.from); + } + } + } + + function nolinebreak(t) { + t = t || token; + if (t.line !== nexttoken.line) { + warning("Line breaking error '{a}'.", t, t.value); + } + } + + + function comma() { + if (token.line !== nexttoken.line) { + if (!option.laxcomma) { + if (comma.first) { + warning("Comma warnings can be turned off with 'laxcomma'"); + comma.first = false; + } + warning("Bad line breaking before '{a}'.", token, nexttoken.id); + } + } else if (!token.comment && token.character !== nexttoken.from && option.white) { + token.from += (token.character - token.from); + warning("Unexpected space after '{a}'.", token, token.value); + } + advance(","); + nonadjacent(token, nexttoken); + } + + +// Functional constructors for making the symbols that will be inherited by +// tokens. + + function symbol(s, p) { + var x = syntax[s]; + if (!x || typeof x !== "object") { + syntax[s] = x = { + id: s, + lbp: p, + value: s + }; + } + return x; + } + + + function delim(s) { + return symbol(s, 0); + } + + + function stmt(s, f) { + var x = delim(s); + x.identifier = x.reserved = true; + x.fud = f; + return x; + } + + + function blockstmt(s, f) { + var x = stmt(s, f); + x.block = true; + return x; + } + + + function reserveName(x) { + var c = x.id.charAt(0); + if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { + x.identifier = x.reserved = true; + } + return x; + } + + + function prefix(s, f) { + var x = symbol(s, 150); + reserveName(x); + x.nud = (typeof f === "function") ? f : function () { + this.right = expression(150); + this.arity = "unary"; + if (this.id === "++" || this.id === "--") { + if (option.plusplus) { + warning("Unexpected use of '{a}'.", this, this.id); + } else if ((!this.right.identifier || this.right.reserved) && + this.right.id !== "." && this.right.id !== "[") { + warning("Bad operand.", this); + } + } + return this; + }; + return x; + } + + + function type(s, f) { + var x = delim(s); + x.type = s; + x.nud = f; + return x; + } + + + function reserve(s, f) { + var x = type(s, f); + x.identifier = x.reserved = true; + return x; + } + + + function reservevar(s, v) { + return reserve(s, function () { + if (typeof v === "function") { + v(this); + } + return this; + }); + } + + + function infix(s, f, p, w) { + var x = symbol(s, p); + reserveName(x); + x.led = function (left) { + if (!w) { + nobreaknonadjacent(prevtoken, token); + nonadjacent(token, nexttoken); + } + if (s === "in" && left.id === "!") { + warning("Confusing use of '{a}'.", left, "!"); + } + if (typeof f === "function") { + return f(left, this); + } else { + this.left = left; + this.right = expression(p); + return this; + } + }; + return x; + } + + + function relation(s, f) { + var x = symbol(s, 100); + x.led = function (left) { + nobreaknonadjacent(prevtoken, token); + nonadjacent(token, nexttoken); + var right = expression(100); + if ((left && left.id === "NaN") || (right && right.id === "NaN")) { + warning("Use the isNaN function to compare with NaN.", this); + } else if (f) { + f.apply(this, [left, right]); + } + if (left.id === "!") { + warning("Confusing use of '{a}'.", left, "!"); + } + if (right.id === "!") { + warning("Confusing use of '{a}'.", right, "!"); + } + this.left = left; + this.right = right; + return this; + }; + return x; + } + + + function isPoorRelation(node) { + return node && + ((node.type === "(number)" && +node.value === 0) || + (node.type === "(string)" && node.value === "") || + (node.type === "null" && !option.eqnull) || + node.type === "true" || + node.type === "false" || + node.type === "undefined"); + } + + + function assignop(s) { + symbol(s, 20).exps = true; + return infix(s, function (left, that) { + that.left = left; + if (predefined[left.value] === false && + scope[left.value]["(global)"] === true) { + warning("Read only.", left); + } else if (left["function"]) { + warning("'{a}' is a function.", left, left.value); + } + if (left) { + if (option.esnext && funct[left.value] === "const") { + warning("Attempting to override '{a}' which is a constant", left, left.value); + } + if (left.id === "." || left.id === "[") { + if (!left.left || left.left.value === "arguments") { + warning("Bad assignment.", that); + } + that.right = expression(19); + return that; + } else if (left.identifier && !left.reserved) { + if (funct[left.value] === "exception") { + warning("Do not assign to the exception parameter.", left); + } + that.right = expression(19); + return that; + } + if (left === syntax["function"]) { + warning( +"Expected an identifier in an assignment and instead saw a function invocation.", + token); + } + } + error("Bad assignment.", that); + }, 20); + } + + + function bitwise(s, f, p) { + var x = symbol(s, p); + reserveName(x); + x.led = (typeof f === "function") ? f : function (left) { + if (option.bitwise) { + warning("Unexpected use of '{a}'.", this, this.id); + } + this.left = left; + this.right = expression(p); + return this; + }; + return x; + } + + + function bitwiseassignop(s) { + symbol(s, 20).exps = true; + return infix(s, function (left, that) { + if (option.bitwise) { + warning("Unexpected use of '{a}'.", that, that.id); + } + nonadjacent(prevtoken, token); + nonadjacent(token, nexttoken); + if (left) { + if (left.id === "." || left.id === "[" || + (left.identifier && !left.reserved)) { + expression(19); + return that; + } + if (left === syntax["function"]) { + warning( +"Expected an identifier in an assignment, and instead saw a function invocation.", + token); + } + return that; + } + error("Bad assignment.", that); + }, 20); + } + + + function suffix(s) { + var x = symbol(s, 150); + x.led = function (left) { + if (option.plusplus) { + warning("Unexpected use of '{a}'.", this, this.id); + } else if ((!left.identifier || left.reserved) && + left.id !== "." && left.id !== "[") { + warning("Bad operand.", this); + } + this.left = left; + return this; + }; + return x; + } + + + // fnparam means that this identifier is being defined as a function + // argument (see identifier()) + function optionalidentifier(fnparam) { + if (nexttoken.identifier) { + advance(); + if (token.reserved && !option.es5) { + // `undefined` as a function param is a common pattern to protect + // against the case when somebody does `undefined = true` and + // help with minification. More info: https://gist.github.com/315916 + if (!fnparam || token.value !== "undefined") { + warning("Expected an identifier and instead saw '{a}' (a reserved word).", + token, token.id); + } + } + return token.value; + } + } + + // fnparam means that this identifier is being defined as a function + // argument + function identifier(fnparam) { + var i = optionalidentifier(fnparam); + if (i) { + return i; + } + if (token.id === "function" && nexttoken.id === "(") { + warning("Missing name in function declaration."); + } else { + error("Expected an identifier and instead saw '{a}'.", + nexttoken, nexttoken.value); + } + } + + + function reachable(s) { + var i = 0, t; + if (nexttoken.id !== ";" || noreach) { + return; + } + for (;;) { + t = peek(i); + if (t.reach) { + return; + } + if (t.id !== "(endline)") { + if (t.id === "function") { + if (!option.latedef) { + break; + } + warning( +"Inner functions should be listed at the top of the outer function.", t); + break; + } + warning("Unreachable '{a}' after '{b}'.", t, t.value, s); + break; + } + i += 1; + } + } + + + function statement(noindent) { + var i = indent, r, s = scope, t = nexttoken; + + if (t.id === ";") { + advance(";"); + return; + } + +// Is this a labelled statement? + + if (t.identifier && !t.reserved && peek().id === ":") { + advance(); + advance(":"); + scope = Object.create(s); + addlabel(t.value, "label"); + if (!nexttoken.labelled) { + warning("Label '{a}' on {b} statement.", + nexttoken, t.value, nexttoken.value); + } + if (jx.test(t.value + ":")) { + warning("Label '{a}' looks like a javascript url.", + t, t.value); + } + nexttoken.label = t.value; + t = nexttoken; + } + +// Parse the statement. + + if (!noindent) { + indentation(); + } + r = expression(0, true); + + // Look for the final semicolon. + if (!t.block) { + if (!option.expr && (!r || !r.exps)) { + warning("Expected an assignment or function call and instead saw an expression.", + token); + } else if (option.nonew && r.id === "(" && r.left.id === "new") { + warning("Do not use 'new' for side effects."); + } + + if (nexttoken.id === ",") { + return comma(); + } + + if (nexttoken.id !== ";") { + if (!option.asi) { + // If this is the last statement in a block that ends on + // the same line *and* option lastsemic is on, ignore the warning. + // Otherwise, complain about missing semicolon. + if (!option.lastsemic || nexttoken.id !== "}" || + nexttoken.line !== token.line) { + warningAt("Missing semicolon.", token.line, token.character); + } + } + } else { + adjacent(token, nexttoken); + advance(";"); + nonadjacent(token, nexttoken); + } + } + +// Restore the indentation. + + indent = i; + scope = s; + return r; + } + + + function statements(startLine) { + var a = [], p; + + while (!nexttoken.reach && nexttoken.id !== "(end)") { + if (nexttoken.id === ";") { + p = peek(); + if (!p || p.id !== "(") { + warning("Unnecessary semicolon."); + } + advance(";"); + } else { + a.push(statement(startLine === nexttoken.line)); + } + } + return a; + } + + + /* + * read all directives + * recognizes a simple form of asi, but always + * warns, if it is used + */ + function directives() { + var i, p, pn; + + for (;;) { + if (nexttoken.id === "(string)") { + p = peek(0); + if (p.id === "(endline)") { + i = 1; + do { + pn = peek(i); + i = i + 1; + } while (pn.id === "(endline)"); + + if (pn.id !== ";") { + if (pn.id !== "(string)" && pn.id !== "(number)" && + pn.id !== "(regexp)" && pn.identifier !== true && + pn.id !== "}") { + break; + } + warning("Missing semicolon.", nexttoken); + } else { + p = pn; + } + } else if (p.id === "}") { + // directive with no other statements, warn about missing semicolon + warning("Missing semicolon.", p); + } else if (p.id !== ";") { + break; + } + + indentation(); + advance(); + if (directive[token.value]) { + warning("Unnecessary directive \"{a}\".", token, token.value); + } + + if (token.value === "use strict") { + option.newcap = true; + option.undef = true; + } + + // there's no directive negation, so always set to true + directive[token.value] = true; + + if (p.id === ";") { + advance(";"); + } + continue; + } + break; + } + } + + + /* + * Parses a single block. A block is a sequence of statements wrapped in + * braces. + * + * ordinary - true for everything but function bodies and try blocks. + * stmt - true if block can be a single statement (e.g. in if/for/while). + * isfunc - true if block is a function body + */ + function block(ordinary, stmt, isfunc) { + var a, + b = inblock, + old_indent = indent, + m, + s = scope, + t, + line, + d; + + inblock = ordinary; + if (!ordinary || !option.funcscope) scope = Object.create(scope); + nonadjacent(token, nexttoken); + t = nexttoken; + + if (nexttoken.id === "{") { + advance("{"); + line = token.line; + if (nexttoken.id !== "}") { + indent += option.indent; + while (!ordinary && nexttoken.from > indent) { + indent += option.indent; + } + + if (isfunc) { + m = {}; + for (d in directive) { + if (is_own(directive, d)) { + m[d] = directive[d]; + } + } + directives(); + + if (option.strict && funct["(context)"]["(global)"]) { + if (!m["use strict"] && !directive["use strict"]) { + warning("Missing \"use strict\" statement."); + } + } + } + + a = statements(line); + + if (isfunc) { + directive = m; + } + + indent -= option.indent; + if (line !== nexttoken.line) { + indentation(); + } + } else if (line !== nexttoken.line) { + indentation(); + } + advance("}", t); + indent = old_indent; + } else if (!ordinary) { + error("Expected '{a}' and instead saw '{b}'.", + nexttoken, "{", nexttoken.value); + } else { + if (!stmt || option.curly) + warning("Expected '{a}' and instead saw '{b}'.", + nexttoken, "{", nexttoken.value); + + noreach = true; + indent += option.indent; + // test indentation only if statement is in new line + a = [statement(nexttoken.line === token.line)]; + indent -= option.indent; + noreach = false; + } + funct["(verb)"] = null; + if (!ordinary || !option.funcscope) scope = s; + inblock = b; + if (ordinary && option.noempty && (!a || a.length === 0)) { + warning("Empty block."); + } + return a; + } + + + function countMember(m) { + if (membersOnly && typeof membersOnly[m] !== "boolean") { + warning("Unexpected /*member '{a}'.", token, m); + } + if (typeof member[m] === "number") { + member[m] += 1; + } else { + member[m] = 1; + } + } + + + function note_implied(token) { + var name = token.value, line = token.line, a = implied[name]; + if (typeof a === "function") { + a = false; + } + + if (!a) { + a = [line]; + implied[name] = a; + } else if (a[a.length - 1] !== line) { + a.push(line); + } + } + + + // Build the syntax table by declaring the syntactic elements of the language. + + type("(number)", function () { + return this; + }); + + type("(string)", function () { + return this; + }); + + syntax["(identifier)"] = { + type: "(identifier)", + lbp: 0, + identifier: true, + nud: function () { + var v = this.value, + s = scope[v], + f; + + if (typeof s === "function") { + // Protection against accidental inheritance. + s = undefined; + } else if (typeof s === "boolean") { + f = funct; + funct = functions[0]; + addlabel(v, "var"); + s = funct; + funct = f; + } + + // The name is in scope and defined in the current function. + if (funct === s) { + // Change 'unused' to 'var', and reject labels. + switch (funct[v]) { + case "unused": + funct[v] = "var"; + break; + case "unction": + funct[v] = "function"; + this["function"] = true; + break; + case "function": + this["function"] = true; + break; + case "label": + warning("'{a}' is a statement label.", token, v); + break; + } + } else if (funct["(global)"]) { + // The name is not defined in the function. If we are in the global + // scope, then we have an undefined variable. + // + // Operators typeof and delete do not raise runtime errors even if + // the base object of a reference is null so no need to display warning + // if we're inside of typeof or delete. + + if (option.undef && typeof predefined[v] !== "boolean") { + // Attempting to subscript a null reference will throw an + // error, even within the typeof and delete operators + if (!(anonname === "typeof" || anonname === "delete") || + (nexttoken && (nexttoken.value === "." || nexttoken.value === "["))) { + + isundef(funct, "'{a}' is not defined.", token, v); + } + } + + note_implied(token); + } else { + // If the name is already defined in the current + // function, but not as outer, then there is a scope error. + + switch (funct[v]) { + case "closure": + case "function": + case "var": + case "unused": + warning("'{a}' used out of scope.", token, v); + break; + case "label": + warning("'{a}' is a statement label.", token, v); + break; + case "outer": + case "global": + break; + default: + // If the name is defined in an outer function, make an outer entry, + // and if it was unused, make it var. + if (s === true) { + funct[v] = true; + } else if (s === null) { + warning("'{a}' is not allowed.", token, v); + note_implied(token); + } else if (typeof s !== "object") { + // Operators typeof and delete do not raise runtime errors even + // if the base object of a reference is null so no need to + // display warning if we're inside of typeof or delete. + if (option.undef) { + // Attempting to subscript a null reference will throw an + // error, even within the typeof and delete operators + if (!(anonname === "typeof" || anonname === "delete") || + (nexttoken && + (nexttoken.value === "." || nexttoken.value === "["))) { + + isundef(funct, "'{a}' is not defined.", token, v); + } + } + funct[v] = true; + note_implied(token); + } else { + switch (s[v]) { + case "function": + case "unction": + this["function"] = true; + s[v] = "closure"; + funct[v] = s["(global)"] ? "global" : "outer"; + break; + case "var": + case "unused": + s[v] = "closure"; + funct[v] = s["(global)"] ? "global" : "outer"; + break; + case "closure": + funct[v] = s["(global)"] ? "global" : "outer"; + break; + case "label": + warning("'{a}' is a statement label.", token, v); + } + } + } + } + return this; + }, + led: function () { + error("Expected an operator and instead saw '{a}'.", + nexttoken, nexttoken.value); + } + }; + + type("(regexp)", function () { + return this; + }); + + +// ECMAScript parser + + delim("(endline)"); + delim("(begin)"); + delim("(end)").reach = true; + delim(""); + delim("(error)").reach = true; + delim("}").reach = true; + delim(")"); + delim("]"); + delim("\"").reach = true; + delim("'").reach = true; + delim(";"); + delim(":").reach = true; + delim(","); + delim("#"); + delim("@"); + reserve("else"); + reserve("case").reach = true; + reserve("catch"); + reserve("default").reach = true; + reserve("finally"); + reservevar("arguments", function (x) { + if (directive["use strict"] && funct["(global)"]) { + warning("Strict violation.", x); + } + }); + reservevar("eval"); + reservevar("false"); + reservevar("Infinity"); + reservevar("NaN"); + reservevar("null"); + reservevar("this", function (x) { + if (directive["use strict"] && !option.validthis && ((funct["(statement)"] && + funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { + warning("Possible strict violation.", x); + } + }); + reservevar("true"); + reservevar("undefined"); + assignop("=", "assign", 20); + assignop("+=", "assignadd", 20); + assignop("-=", "assignsub", 20); + assignop("*=", "assignmult", 20); + assignop("/=", "assigndiv", 20).nud = function () { + error("A regular expression literal can be confused with '/='."); + }; + assignop("%=", "assignmod", 20); + bitwiseassignop("&=", "assignbitand", 20); + bitwiseassignop("|=", "assignbitor", 20); + bitwiseassignop("^=", "assignbitxor", 20); + bitwiseassignop("<<=", "assignshiftleft", 20); + bitwiseassignop(">>=", "assignshiftright", 20); + bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); + infix("?", function (left, that) { + that.left = left; + that.right = expression(10); + advance(":"); + that["else"] = expression(10); + return that; + }, 30); + + infix("||", "or", 40); + infix("&&", "and", 50); + bitwise("|", "bitor", 70); + bitwise("^", "bitxor", 80); + bitwise("&", "bitand", 90); + relation("==", function (left, right) { + var eqnull = option.eqnull && (left.value === "null" || right.value === "null"); + + if (!eqnull && option.eqeqeq) + warning("Expected '{a}' and instead saw '{b}'.", this, "===", "=="); + else if (isPoorRelation(left)) + warning("Use '{a}' to compare with '{b}'.", this, "===", left.value); + else if (isPoorRelation(right)) + warning("Use '{a}' to compare with '{b}'.", this, "===", right.value); + + return this; + }); + relation("==="); + relation("!=", function (left, right) { + var eqnull = option.eqnull && + (left.value === "null" || right.value === "null"); + + if (!eqnull && option.eqeqeq) { + warning("Expected '{a}' and instead saw '{b}'.", + this, "!==", "!="); + } else if (isPoorRelation(left)) { + warning("Use '{a}' to compare with '{b}'.", + this, "!==", left.value); + } else if (isPoorRelation(right)) { + warning("Use '{a}' to compare with '{b}'.", + this, "!==", right.value); + } + return this; + }); + relation("!=="); + relation("<"); + relation(">"); + relation("<="); + relation(">="); + bitwise("<<", "shiftleft", 120); + bitwise(">>", "shiftright", 120); + bitwise(">>>", "shiftrightunsigned", 120); + infix("in", "in", 120); + infix("instanceof", "instanceof", 120); + infix("+", function (left, that) { + var right = expression(130); + if (left && right && left.id === "(string)" && right.id === "(string)") { + left.value += right.value; + left.character = right.character; + if (!option.scripturl && jx.test(left.value)) { + warning("JavaScript URL.", left); + } + return left; + } + that.left = left; + that.right = right; + return that; + }, 130); + prefix("+", "num"); + prefix("+++", function () { + warning("Confusing pluses."); + this.right = expression(150); + this.arity = "unary"; + return this; + }); + infix("+++", function (left) { + warning("Confusing pluses."); + this.left = left; + this.right = expression(130); + return this; + }, 130); + infix("-", "sub", 130); + prefix("-", "neg"); + prefix("---", function () { + warning("Confusing minuses."); + this.right = expression(150); + this.arity = "unary"; + return this; + }); + infix("---", function (left) { + warning("Confusing minuses."); + this.left = left; + this.right = expression(130); + return this; + }, 130); + infix("*", "mult", 140); + infix("/", "div", 140); + infix("%", "mod", 140); + + suffix("++", "postinc"); + prefix("++", "preinc"); + syntax["++"].exps = true; + + suffix("--", "postdec"); + prefix("--", "predec"); + syntax["--"].exps = true; + prefix("delete", function () { + var p = expression(0); + if (!p || (p.id !== "." && p.id !== "[")) { + warning("Variables should not be deleted."); + } + this.first = p; + return this; + }).exps = true; + + prefix("~", function () { + if (option.bitwise) { + warning("Unexpected '{a}'.", this, "~"); + } + expression(150); + return this; + }); + + prefix("!", function () { + this.right = expression(150); + this.arity = "unary"; + if (bang[this.right.id] === true) { + warning("Confusing use of '{a}'.", this, "!"); + } + return this; + }); + prefix("typeof", "typeof"); + prefix("new", function () { + var c = expression(155), i; + if (c && c.id !== "function") { + if (c.identifier) { + c["new"] = true; + switch (c.value) { + case "Number": + case "String": + case "Boolean": + case "Math": + case "JSON": + warning("Do not use {a} as a constructor.", token, c.value); + break; + case "Function": + if (!option.evil) { + warning("The Function constructor is eval."); + } + break; + case "Date": + case "RegExp": + break; + default: + if (c.id !== "function") { + i = c.value.substr(0, 1); + if (option.newcap && (i < "A" || i > "Z")) { + warning("A constructor name should start with an uppercase letter.", + token); + } + } + } + } else { + if (c.id !== "." && c.id !== "[" && c.id !== "(") { + warning("Bad constructor.", token); + } + } + } else { + if (!option.supernew) + warning("Weird construction. Delete 'new'.", this); + } + adjacent(token, nexttoken); + if (nexttoken.id !== "(" && !option.supernew) { + warning("Missing '()' invoking a constructor.", + token, token.value); + } + this.first = c; + return this; + }); + syntax["new"].exps = true; + + prefix("void").exps = true; + + infix(".", function (left, that) { + adjacent(prevtoken, token); + nobreak(); + var m = identifier(); + if (typeof m === "string") { + countMember(m); + } + that.left = left; + that.right = m; + if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { + if (option.noarg) + warning("Avoid arguments.{a}.", left, m); + else if (directive["use strict"]) + error("Strict violation."); + } else if (!option.evil && left && left.value === "document" && + (m === "write" || m === "writeln")) { + warning("document.write can be a form of eval.", left); + } + if (!option.evil && (m === "eval" || m === "execScript")) { + warning("eval is evil."); + } + return that; + }, 160, true); + + infix("(", function (left, that) { + if (prevtoken.id !== "}" && prevtoken.id !== ")") { + nobreak(prevtoken, token); + } + nospace(); + if (option.immed && !left.immed && left.id === "function") { + warning("Wrap an immediate function invocation in parentheses " + + "to assist the reader in understanding that the expression " + + "is the result of a function, and not the function itself."); + } + var n = 0, + p = []; + if (left) { + if (left.type === "(identifier)") { + if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { + if (left.value !== "Number" && left.value !== "String" && + left.value !== "Boolean" && + left.value !== "Date") { + if (left.value === "Math") { + warning("Math is not a function.", left); + } else if (option.newcap) { + warning( +"Missing 'new' prefix when invoking a constructor.", left); + } + } + } + } + } + if (nexttoken.id !== ")") { + for (;;) { + p[p.length] = expression(10); + n += 1; + if (nexttoken.id !== ",") { + break; + } + comma(); + } + } + advance(")"); + nospace(prevtoken, token); + if (typeof left === "object") { + if (left.value === "parseInt" && n === 1) { + warning("Missing radix parameter.", left); + } + if (!option.evil) { + if (left.value === "eval" || left.value === "Function" || + left.value === "execScript") { + warning("eval is evil.", left); + } else if (p[0] && p[0].id === "(string)" && + (left.value === "setTimeout" || + left.value === "setInterval")) { + warning( + "Implied eval is evil. Pass a function instead of a string.", left); + } + } + if (!left.identifier && left.id !== "." && left.id !== "[" && + left.id !== "(" && left.id !== "&&" && left.id !== "||" && + left.id !== "?") { + warning("Bad invocation.", left); + } + } + that.left = left; + return that; + }, 155, true).exps = true; + + prefix("(", function () { + nospace(); + if (nexttoken.id === "function") { + nexttoken.immed = true; + } + var v = expression(0); + advance(")", this); + nospace(prevtoken, token); + if (option.immed && v.id === "function") { + if (nexttoken.id === "(" || + (nexttoken.id === "." && (peek().value === "call" || peek().value === "apply"))) { + warning( +"Move the invocation into the parens that contain the function.", nexttoken); + } else { + warning( +"Do not wrap function literals in parens unless they are to be immediately invoked.", + this); + } + } + return v; + }); + + infix("[", function (left, that) { + nobreak(prevtoken, token); + nospace(); + var e = expression(0), s; + if (e && e.type === "(string)") { + if (!option.evil && (e.value === "eval" || e.value === "execScript")) { + warning("eval is evil.", that); + } + countMember(e.value); + if (!option.sub && ix.test(e.value)) { + s = syntax[e.value]; + if (!s || !s.reserved) { + warning("['{a}'] is better written in dot notation.", + e, e.value); + } + } + } + advance("]", that); + nospace(prevtoken, token); + that.left = left; + that.right = e; + return that; + }, 160, true); + + prefix("[", function () { + var b = token.line !== nexttoken.line; + this.first = []; + if (b) { + indent += option.indent; + if (nexttoken.from === indent + option.indent) { + indent += option.indent; + } + } + while (nexttoken.id !== "(end)") { + while (nexttoken.id === ",") { + warning("Extra comma."); + advance(","); + } + if (nexttoken.id === "]") { + break; + } + if (b && token.line !== nexttoken.line) { + indentation(); + } + this.first.push(expression(10)); + if (nexttoken.id === ",") { + comma(); + if (nexttoken.id === "]" && !option.es5) { + warning("Extra comma.", token); + break; + } + } else { + break; + } + } + if (b) { + indent -= option.indent; + indentation(); + } + advance("]", this); + return this; + }, 160); + + + function property_name() { + var id = optionalidentifier(true); + if (!id) { + if (nexttoken.id === "(string)") { + id = nexttoken.value; + advance(); + } else if (nexttoken.id === "(number)") { + id = nexttoken.value.toString(); + advance(); + } + } + return id; + } + + + function functionparams() { + var i, t = nexttoken, p = []; + advance("("); + nospace(); + if (nexttoken.id === ")") { + advance(")"); + return; + } + for (;;) { + i = identifier(true); + p.push(i); + addlabel(i, "unused", token); + if (nexttoken.id === ",") { + comma(); + } else { + advance(")", t); + nospace(prevtoken, token); + return p; + } + } + } + + + function doFunction(i, statement) { + var f, + oldOption = option, + oldScope = scope; + + option = Object.create(option); + scope = Object.create(scope); + + funct = { + "(name)" : i || "\"" + anonname + "\"", + "(line)" : nexttoken.line, + "(character)": nexttoken.character, + "(context)" : funct, + "(breakage)" : 0, + "(loopage)" : 0, + "(scope)" : scope, + "(statement)": statement, + "(tokens)" : {} + }; + f = funct; + token.funct = funct; + functions.push(funct); + if (i) { + addlabel(i, "function"); + } + funct["(params)"] = functionparams(); + + block(false, false, true); + scope = oldScope; + option = oldOption; + funct["(last)"] = token.line; + funct["(lastcharacter)"] = token.character; + funct = funct["(context)"]; + return f; + } + + + (function (x) { + x.nud = function () { + var b, f, i, p, t; + var props = {}; // All properties, including accessors + + function saveProperty(name, token) { + if (props[name] && is_own(props, name)) + warning("Duplicate member '{a}'.", nexttoken, i); + else + props[name] = {}; + + props[name].basic = true; + props[name].basicToken = token; + } + + function saveSetter(name, token) { + if (props[name] && is_own(props, name)) { + if (props[name].basic || props[name].setter) + warning("Duplicate member '{a}'.", nexttoken, i); + } else { + props[name] = {}; + } + + props[name].setter = true; + props[name].setterToken = token; + } + + function saveGetter(name) { + if (props[name] && is_own(props, name)) { + if (props[name].basic || props[name].getter) + warning("Duplicate member '{a}'.", nexttoken, i); + } else { + props[name] = {}; + } + + props[name].getter = true; + props[name].getterToken = token; + } + + b = token.line !== nexttoken.line; + if (b) { + indent += option.indent; + if (nexttoken.from === indent + option.indent) { + indent += option.indent; + } + } + for (;;) { + if (nexttoken.id === "}") { + break; + } + if (b) { + indentation(); + } + if (nexttoken.value === "get" && peek().id !== ":") { + advance("get"); + if (!option.es5) { + error("get/set are ES5 features."); + } + i = property_name(); + if (!i) { + error("Missing property name."); + } + saveGetter(i); + t = nexttoken; + adjacent(token, nexttoken); + f = doFunction(); + p = f["(params)"]; + if (p) { + warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i); + } + adjacent(token, nexttoken); + } else if (nexttoken.value === "set" && peek().id !== ":") { + advance("set"); + if (!option.es5) { + error("get/set are ES5 features."); + } + i = property_name(); + if (!i) { + error("Missing property name."); + } + saveSetter(i, nexttoken); + t = nexttoken; + adjacent(token, nexttoken); + f = doFunction(); + p = f["(params)"]; + if (!p || p.length !== 1) { + warning("Expected a single parameter in set {a} function.", t, i); + } + } else { + i = property_name(); + saveProperty(i, nexttoken); + if (typeof i !== "string") { + break; + } + advance(":"); + nonadjacent(token, nexttoken); + expression(10); + } + + countMember(i); + if (nexttoken.id === ",") { + comma(); + if (nexttoken.id === ",") { + warning("Extra comma.", token); + } else if (nexttoken.id === "}" && !option.es5) { + warning("Extra comma.", token); + } + } else { + break; + } + } + if (b) { + indent -= option.indent; + indentation(); + } + advance("}", this); + + // Check for lonely setters if in the ES5 mode. + if (option.es5) { + for (var name in props) { + if (is_own(props, name) && props[name].setter && !props[name].getter) { + warning("Setter is defined without getter.", props[name].setterToken); + } + } + } + return this; + }; + x.fud = function () { + error("Expected to see a statement and instead saw a block.", token); + }; + }(delim("{"))); + +// This Function is called when esnext option is set to true +// it adds the `const` statement to JSHINT + + useESNextSyntax = function () { + var conststatement = stmt("const", function (prefix) { + var id, name, value; + + this.first = []; + for (;;) { + nonadjacent(token, nexttoken); + id = identifier(); + if (funct[id] === "const") { + warning("const '" + id + "' has already been declared"); + } + if (funct["(global)"] && predefined[id] === false) { + warning("Redefinition of '{a}'.", token, id); + } + addlabel(id, "const"); + if (prefix) { + break; + } + name = token; + this.first.push(token); + + if (nexttoken.id !== "=") { + warning("const " + + "'{a}' is initialized to 'undefined'.", token, id); + } + + if (nexttoken.id === "=") { + nonadjacent(token, nexttoken); + advance("="); + nonadjacent(token, nexttoken); + if (nexttoken.id === "undefined") { + warning("It is not necessary to initialize " + + "'{a}' to 'undefined'.", token, id); + } + if (peek(0).id === "=" && nexttoken.identifier) { + error("Constant {a} was not declared correctly.", + nexttoken, nexttoken.value); + } + value = expression(0); + name.first = value; + } + + if (nexttoken.id !== ",") { + break; + } + comma(); + } + return this; + }); + conststatement.exps = true; + }; + + var varstatement = stmt("var", function (prefix) { + // JavaScript does not have block scope. It only has function scope. So, + // declaring a variable in a block can have unexpected consequences. + var id, name, value; + + if (funct["(onevar)"] && option.onevar) { + warning("Too many var statements."); + } else if (!funct["(global)"]) { + funct["(onevar)"] = true; + } + + this.first = []; + + for (;;) { + nonadjacent(token, nexttoken); + id = identifier(); + + if (option.esnext && funct[id] === "const") { + warning("const '" + id + "' has already been declared"); + } + + if (funct["(global)"] && predefined[id] === false) { + warning("Redefinition of '{a}'.", token, id); + } + + addlabel(id, "unused", token); + + if (prefix) { + break; + } + + name = token; + this.first.push(token); + + if (nexttoken.id === "=") { + nonadjacent(token, nexttoken); + advance("="); + nonadjacent(token, nexttoken); + if (nexttoken.id === "undefined") { + warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id); + } + if (peek(0).id === "=" && nexttoken.identifier) { + error("Variable {a} was not declared correctly.", + nexttoken, nexttoken.value); + } + value = expression(0); + name.first = value; + } + if (nexttoken.id !== ",") { + break; + } + comma(); + } + return this; + }); + varstatement.exps = true; + + blockstmt("function", function () { + if (inblock) { + warning("Function declarations should not be placed in blocks. " + + "Use a function expression or move the statement to the top of " + + "the outer function.", token); + + } + var i = identifier(); + if (option.esnext && funct[i] === "const") { + warning("const '" + i + "' has already been declared"); + } + adjacent(token, nexttoken); + addlabel(i, "unction", token); + + doFunction(i, true); + if (nexttoken.id === "(" && nexttoken.line === token.line) { + error( +"Function declarations are not invocable. Wrap the whole function invocation in parens."); + } + return this; + }); + + prefix("function", function () { + var i = optionalidentifier(); + if (i) { + adjacent(token, nexttoken); + } else { + nonadjacent(token, nexttoken); + } + doFunction(i); + if (!option.loopfunc && funct["(loopage)"]) { + warning("Don't make functions within a loop."); + } + return this; + }); + + blockstmt("if", function () { + var t = nexttoken; + advance("("); + nonadjacent(this, t); + nospace(); + expression(20); + if (nexttoken.id === "=") { + if (!option.boss) + warning("Expected a conditional expression and instead saw an assignment."); + advance("="); + expression(20); + } + advance(")", t); + nospace(prevtoken, token); + block(true, true); + if (nexttoken.id === "else") { + nonadjacent(token, nexttoken); + advance("else"); + if (nexttoken.id === "if" || nexttoken.id === "switch") { + statement(true); + } else { + block(true, true); + } + } + return this; + }); + + blockstmt("try", function () { + var b, e, s; + + block(false); + if (nexttoken.id === "catch") { + advance("catch"); + nonadjacent(token, nexttoken); + advance("("); + s = scope; + scope = Object.create(s); + e = nexttoken.value; + if (nexttoken.type !== "(identifier)") { + warning("Expected an identifier and instead saw '{a}'.", + nexttoken, e); + } else { + addlabel(e, "exception"); + } + advance(); + advance(")"); + block(false); + b = true; + scope = s; + } + if (nexttoken.id === "finally") { + advance("finally"); + block(false); + return; + } else if (!b) { + error("Expected '{a}' and instead saw '{b}'.", + nexttoken, "catch", nexttoken.value); + } + return this; + }); + + blockstmt("while", function () { + var t = nexttoken; + funct["(breakage)"] += 1; + funct["(loopage)"] += 1; + advance("("); + nonadjacent(this, t); + nospace(); + expression(20); + if (nexttoken.id === "=") { + if (!option.boss) + warning("Expected a conditional expression and instead saw an assignment."); + advance("="); + expression(20); + } + advance(")", t); + nospace(prevtoken, token); + block(true, true); + funct["(breakage)"] -= 1; + funct["(loopage)"] -= 1; + return this; + }).labelled = true; + + blockstmt("with", function () { + var t = nexttoken; + if (directive["use strict"]) { + error("'with' is not allowed in strict mode.", token); + } else if (!option.withstmt) { + warning("Don't use 'with'.", token); + } + + advance("("); + nonadjacent(this, t); + nospace(); + expression(0); + advance(")", t); + nospace(prevtoken, token); + block(true, true); + + return this; + }); + + blockstmt("switch", function () { + var t = nexttoken, + g = false; + funct["(breakage)"] += 1; + advance("("); + nonadjacent(this, t); + nospace(); + this.condition = expression(20); + advance(")", t); + nospace(prevtoken, token); + nonadjacent(token, nexttoken); + t = nexttoken; + advance("{"); + nonadjacent(token, nexttoken); + indent += option.indent; + this.cases = []; + for (;;) { + switch (nexttoken.id) { + case "case": + switch (funct["(verb)"]) { + case "break": + case "case": + case "continue": + case "return": + case "switch": + case "throw": + break; + default: + // You can tell JSHint that you don't use break intentionally by + // adding a comment /* falls through */ on a line just before + // the next `case`. + if (!ft.test(lines[nexttoken.line - 2])) { + warning( + "Expected a 'break' statement before 'case'.", + token); + } + } + indentation(-option.indent); + advance("case"); + this.cases.push(expression(20)); + g = true; + advance(":"); + funct["(verb)"] = "case"; + break; + case "default": + switch (funct["(verb)"]) { + case "break": + case "continue": + case "return": + case "throw": + break; + default: + if (!ft.test(lines[nexttoken.line - 2])) { + warning( + "Expected a 'break' statement before 'default'.", + token); + } + } + indentation(-option.indent); + advance("default"); + g = true; + advance(":"); + break; + case "}": + indent -= option.indent; + indentation(); + advance("}", t); + if (this.cases.length === 1 || this.condition.id === "true" || + this.condition.id === "false") { + if (!option.onecase) + warning("This 'switch' should be an 'if'.", this); + } + funct["(breakage)"] -= 1; + funct["(verb)"] = undefined; + return; + case "(end)": + error("Missing '{a}'.", nexttoken, "}"); + return; + default: + if (g) { + switch (token.id) { + case ",": + error("Each value should have its own case label."); + return; + case ":": + g = false; + statements(); + break; + default: + error("Missing ':' on a case clause.", token); + return; + } + } else { + if (token.id === ":") { + advance(":"); + error("Unexpected '{a}'.", token, ":"); + statements(); + } else { + error("Expected '{a}' and instead saw '{b}'.", + nexttoken, "case", nexttoken.value); + return; + } + } + } + } + }).labelled = true; + + stmt("debugger", function () { + if (!option.debug) { + warning("All 'debugger' statements should be removed."); + } + return this; + }).exps = true; + + (function () { + var x = stmt("do", function () { + funct["(breakage)"] += 1; + funct["(loopage)"] += 1; + this.first = block(true); + advance("while"); + var t = nexttoken; + nonadjacent(token, t); + advance("("); + nospace(); + expression(20); + if (nexttoken.id === "=") { + if (!option.boss) + warning("Expected a conditional expression and instead saw an assignment."); + advance("="); + expression(20); + } + advance(")", t); + nospace(prevtoken, token); + funct["(breakage)"] -= 1; + funct["(loopage)"] -= 1; + return this; + }); + x.labelled = true; + x.exps = true; + }()); + + blockstmt("for", function () { + var s, t = nexttoken; + funct["(breakage)"] += 1; + funct["(loopage)"] += 1; + advance("("); + nonadjacent(this, t); + nospace(); + if (peek(nexttoken.id === "var" ? 1 : 0).id === "in") { + if (nexttoken.id === "var") { + advance("var"); + varstatement.fud.call(varstatement, true); + } else { + switch (funct[nexttoken.value]) { + case "unused": + funct[nexttoken.value] = "var"; + break; + case "var": + break; + default: + warning("Bad for in variable '{a}'.", + nexttoken, nexttoken.value); + } + advance(); + } + advance("in"); + expression(20); + advance(")", t); + s = block(true, true); + if (option.forin && s && (s.length > 1 || typeof s[0] !== "object" || + s[0].value !== "if")) { + warning("The body of a for in should be wrapped in an if statement to filter " + + "unwanted properties from the prototype.", this); + } + funct["(breakage)"] -= 1; + funct["(loopage)"] -= 1; + return this; + } else { + if (nexttoken.id !== ";") { + if (nexttoken.id === "var") { + advance("var"); + varstatement.fud.call(varstatement); + } else { + for (;;) { + expression(0, "for"); + if (nexttoken.id !== ",") { + break; + } + comma(); + } + } + } + nolinebreak(token); + advance(";"); + if (nexttoken.id !== ";") { + expression(20); + if (nexttoken.id === "=") { + if (!option.boss) + warning("Expected a conditional expression and instead saw an assignment."); + advance("="); + expression(20); + } + } + nolinebreak(token); + advance(";"); + if (nexttoken.id === ";") { + error("Expected '{a}' and instead saw '{b}'.", + nexttoken, ")", ";"); + } + if (nexttoken.id !== ")") { + for (;;) { + expression(0, "for"); + if (nexttoken.id !== ",") { + break; + } + comma(); + } + } + advance(")", t); + nospace(prevtoken, token); + block(true, true); + funct["(breakage)"] -= 1; + funct["(loopage)"] -= 1; + return this; + } + }).labelled = true; + + + stmt("break", function () { + var v = nexttoken.value; + + if (funct["(breakage)"] === 0) + warning("Unexpected '{a}'.", nexttoken, this.value); + + if (!option.asi) + nolinebreak(this); + + if (nexttoken.id !== ";") { + if (token.line === nexttoken.line) { + if (funct[v] !== "label") { + warning("'{a}' is not a statement label.", nexttoken, v); + } else if (scope[v] !== funct) { + warning("'{a}' is out of scope.", nexttoken, v); + } + this.first = nexttoken; + advance(); + } + } + reachable("break"); + return this; + }).exps = true; + + + stmt("continue", function () { + var v = nexttoken.value; + + if (funct["(breakage)"] === 0) + warning("Unexpected '{a}'.", nexttoken, this.value); + + if (!option.asi) + nolinebreak(this); + + if (nexttoken.id !== ";") { + if (token.line === nexttoken.line) { + if (funct[v] !== "label") { + warning("'{a}' is not a statement label.", nexttoken, v); + } else if (scope[v] !== funct) { + warning("'{a}' is out of scope.", nexttoken, v); + } + this.first = nexttoken; + advance(); + } + } else if (!funct["(loopage)"]) { + warning("Unexpected '{a}'.", nexttoken, this.value); + } + reachable("continue"); + return this; + }).exps = true; + + + stmt("return", function () { + if (this.line === nexttoken.line) { + if (nexttoken.id === "(regexp)") + warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator."); + + if (nexttoken.id !== ";" && !nexttoken.reach) { + nonadjacent(token, nexttoken); + if (peek().value === "=" && !option.boss) { + warningAt("Did you mean to return a conditional instead of an assignment?", + token.line, token.character + 1); + } + this.first = expression(0); + } + } else if (!option.asi) { + nolinebreak(this); // always warn (Line breaking error) + } + reachable("return"); + return this; + }).exps = true; + + + stmt("throw", function () { + nolinebreak(this); + nonadjacent(token, nexttoken); + this.first = expression(20); + reachable("throw"); + return this; + }).exps = true; + +// Superfluous reserved words + + reserve("class"); + reserve("const"); + reserve("enum"); + reserve("export"); + reserve("extends"); + reserve("import"); + reserve("super"); + + reserve("let"); + reserve("yield"); + reserve("implements"); + reserve("interface"); + reserve("package"); + reserve("private"); + reserve("protected"); + reserve("public"); + reserve("static"); + + +// Parse JSON + + function jsonValue() { + + function jsonObject() { + var o = {}, t = nexttoken; + advance("{"); + if (nexttoken.id !== "}") { + for (;;) { + if (nexttoken.id === "(end)") { + error("Missing '}' to match '{' from line {a}.", + nexttoken, t.line); + } else if (nexttoken.id === "}") { + warning("Unexpected comma.", token); + break; + } else if (nexttoken.id === ",") { + error("Unexpected comma.", nexttoken); + } else if (nexttoken.id !== "(string)") { + warning("Expected a string and instead saw {a}.", + nexttoken, nexttoken.value); + } + if (o[nexttoken.value] === true) { + warning("Duplicate key '{a}'.", + nexttoken, nexttoken.value); + } else if ((nexttoken.value === "__proto__" && + !option.proto) || (nexttoken.value === "__iterator__" && + !option.iterator)) { + warning("The '{a}' key may produce unexpected results.", + nexttoken, nexttoken.value); + } else { + o[nexttoken.value] = true; + } + advance(); + advance(":"); + jsonValue(); + if (nexttoken.id !== ",") { + break; + } + advance(","); + } + } + advance("}"); + } + + function jsonArray() { + var t = nexttoken; + advance("["); + if (nexttoken.id !== "]") { + for (;;) { + if (nexttoken.id === "(end)") { + error("Missing ']' to match '[' from line {a}.", + nexttoken, t.line); + } else if (nexttoken.id === "]") { + warning("Unexpected comma.", token); + break; + } else if (nexttoken.id === ",") { + error("Unexpected comma.", nexttoken); + } + jsonValue(); + if (nexttoken.id !== ",") { + break; + } + advance(","); + } + } + advance("]"); + } + + switch (nexttoken.id) { + case "{": + jsonObject(); + break; + case "[": + jsonArray(); + break; + case "true": + case "false": + case "null": + case "(number)": + case "(string)": + advance(); + break; + case "-": + advance("-"); + if (token.character !== nexttoken.from) { + warning("Unexpected space after '-'.", token); + } + adjacent(token, nexttoken); + advance("(number)"); + break; + default: + error("Expected a JSON value.", nexttoken); + } + } + + + // The actual JSHINT function itself. + var itself = function (s, o, g) { + var a, i, k, x, + optionKeys, + newOptionObj = {}; + + JSHINT.errors = []; + JSHINT.undefs = []; + + predefined = Object.create(standard); + declared = Object.create(null); + combine(predefined, g || {}); + + if (!isString(s) && !Array.isArray(s)) { + errorAt("Input is neither a string nor an array of strings.", 0); + return false; + } + + if (isString(s) && /^\s*$/g.test(s)) { + errorAt("Input is an empty string.", 0); + return false; + } + + if (s.length === 0) { + errorAt("Input is an empty array.", 0); + return false; + } + + if (o) { + a = o.predef; + if (a) { + if (Array.isArray(a)) { + for (i = 0; i < a.length; i += 1) { + predefined[a[i]] = true; + } + } else if (typeof a === "object") { + k = Object.keys(a); + for (i = 0; i < k.length; i += 1) { + predefined[k[i]] = !!a[k[i]]; + } + } + } + optionKeys = Object.keys(o); + for (x = 0; x < optionKeys.length; x++) { + newOptionObj[optionKeys[x]] = o[optionKeys[x]]; + } + } + + option = newOptionObj; + + option.indent = option.indent || 4; + option.maxerr = option.maxerr || 50; + + tab = ""; + for (i = 0; i < option.indent; i += 1) { + tab += " "; + } + indent = 1; + global = Object.create(predefined); + scope = global; + funct = { + "(global)": true, + "(name)": "(global)", + "(scope)": scope, + "(breakage)": 0, + "(loopage)": 0, + "(tokens)": {} + }; + functions = [funct]; + urls = []; + stack = null; + member = {}; + membersOnly = null; + implied = {}; + inblock = false; + lookahead = []; + jsonmode = false; + warnings = 0; + lex.init(s); + prereg = true; + directive = {}; + + prevtoken = token = nexttoken = syntax["(begin)"]; + + // Check options + for (var name in o) { + if (is_own(o, name)) { + checkOption(name, token); + } + } + + assume(); + + // combine the passed globals after we've assumed all our options + combine(predefined, g || {}); + + //reset values + comma.first = true; + quotmark = undefined; + + try { + advance(); + switch (nexttoken.id) { + case "{": + case "[": + option.laxbreak = true; + jsonmode = true; + jsonValue(); + break; + default: + directives(); + if (directive["use strict"] && !option.globalstrict) { + warning("Use the function form of \"use strict\".", prevtoken); + } + + statements(); + } + advance((nexttoken && nexttoken.value !== ".") ? "(end)" : undefined); + + var markDefined = function (name, context) { + do { + if (typeof context[name] === "string") { + // JSHINT marks unused variables as 'unused' and + // unused function declaration as 'unction'. This + // code changes such instances back 'var' and + // 'closure' so that the code in JSHINT.data() + // doesn't think they're unused. + + if (context[name] === "unused") + context[name] = "var"; + else if (context[name] === "unction") + context[name] = "closure"; + + return true; + } + + context = context["(context)"]; + } while (context); + + return false; + }; + + var clearImplied = function (name, line) { + if (!implied[name]) + return; + + var newImplied = []; + for (var i = 0; i < implied[name].length; i += 1) { + if (implied[name][i] !== line) + newImplied.push(implied[name][i]); + } + + if (newImplied.length === 0) + delete implied[name]; + else + implied[name] = newImplied; + }; + + var checkUnused = function (func, key) { + var type = func[key]; + var token = func["(tokens)"][key]; + + if (key.charAt(0) === "(") + return; + + // 'undefined' is a special case for (function (window, undefined) { ... })(); + // patterns. + + if (key === "undefined") + return; + + if (type !== "unused" && type !== "unction") + return; + + warningAt("'{a}' is defined but never used.", token.line, token.character, key); + }; + + // Check queued 'x is not defined' instances to see if they're still undefined. + for (i = 0; i < JSHINT.undefs.length; i += 1) { + k = JSHINT.undefs[i].slice(0); + + if (markDefined(k[2].value, k[0])) { + clearImplied(k[2].value, k[2].line); + } else { + warning.apply(warning, k.slice(1)); + } + } + + if (option.unused) { + functions.forEach(function (func) { + for (var key in func) { + if (is_own(func, key)) { + checkUnused(func, key); + } + } + }); + + for (var key in declared) { + if (is_own(declared, key)) { + if (!is_own(global, key)) { + warningAt("'{a}' is defined but never used.", + declared[key].line, declared[key].character, key); + } + } + } + } + } catch (e) { + if (e) { + var nt = nexttoken || {}; + JSHINT.errors.push({ + raw : e.raw, + reason : e.message, + line : e.line || nt.line, + character : e.character || nt.from + }, null); + } + } + + return JSHINT.errors.length === 0; + }; + + // Data summary. + itself.data = function () { + var data = { + functions: [], + options: option + }; + var implieds = []; + var members = []; + var unused = []; + var fu, f, i, j, n, v, globals; + + if (itself.errors.length) { + data.errors = itself.errors; + } + + if (jsonmode) { + data.json = true; + } + + for (n in implied) { + if (is_own(implied, n)) { + implieds.push({ + name: n, + line: implied[n] + }); + } + } + + if (implieds.length > 0) { + data.implieds = implieds; + } + + if (urls.length > 0) { + data.urls = urls; + } + + globals = Object.keys(scope); + if (globals.length > 0) { + data.globals = globals; + } + + for (i = 1; i < functions.length; i += 1) { + f = functions[i]; + fu = {}; + + for (j = 0; j < functionicity.length; j += 1) { + fu[functionicity[j]] = []; + } + + for (n in f) { + if (is_own(f, n) && n.charAt(0) !== "(") { + v = f[n]; + + if (v === "unction") { + v = "unused"; + } + + if (Array.isArray(fu[v])) { + fu[v].push(n); + + if (v === "unused") { + unused.push({ + name: n, + line: f["(line)"], + "function": f["(name)"] + }); + } + } + } + } + + for (j = 0; j < functionicity.length; j += 1) { + if (fu[functionicity[j]].length === 0) { + delete fu[functionicity[j]]; + } + } + + fu.name = f["(name)"]; + fu.param = f["(params)"]; + fu.line = f["(line)"]; + fu.character = f["(character)"]; + fu.last = f["(last)"]; + fu.lastcharacter = f["(lastcharacter)"]; + data.functions.push(fu); + } + + if (unused.length > 0) { + data.unused = unused; + } + + members = []; + for (n in member) { + if (typeof member[n] === "number") { + data.member = member; + break; + } + } + + return data; + }; + + itself.jshint = itself; + + return itself; +}()); + +// Make JSHINT a Node module, if possible. +if (typeof exports === "object" && exports) { + exports.JSHINT = JSHINT; +} diff --git a/EditorExtensions/Resources/Scripts/less-1.3.0.js b/EditorExtensions/Resources/Scripts/less-1.3.0.js new file mode 100644 index 000000000..aac4fea23 --- /dev/null +++ b/EditorExtensions/Resources/Scripts/less-1.3.0.js @@ -0,0 +1,9 @@ +// +// LESS - Leaner CSS v1.3.3 +// http://lesscss.org +// +// Copyright (c) 2009-2013, Alexis Sellier +// Licensed under the Apache 2.0 License. +// +(function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,r,i){t&&S(t.toCSS(),r,i.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=t.contents||{},u=t.files||{},a=b(t.href,e.location.href),f=a.url,c=l&&l.getItem(f),h=l&&l.getItem(f+":timestamp"),p={css:c,timestamp:h},d;r.relativeUrls?r.rootpath?t.entryPath?d=b(r.rootpath+y(a.path,t.entryPath)).path:d=r.rootpath:d=a.path:r.rootpath?d=r.rootpath:t.entryPath?d=t.entryPath:d=a.path,x(f,t.type,function(e,l){v+=e.replace(/@import .+?;/ig,"");if(!i&&p&&l&&(new Date(l)).valueOf()===(new Date(p.timestamp)).valueOf())S(p.css,t),n(null,null,e,t,{local:!0,remaining:s},f);else try{o[f]=e,(new r.Parser({optimization:r.optimization,paths:[a.path],entryPath:t.entryPath||a.path,mime:t.type,filename:f,rootpath:d,relativeUrls:t.relativeUrls,contents:o,files:u,dumpLineNumbers:r.dumpLineNumbers})).parse(e,function(r,i){if(r)return k(r,f);try{n(r,i,e,t,{local:!1,lastModified:l,remaining:s},f),N(document.getElementById("less-error-message:"+E(f)))}catch(r){k(r,f)}})}catch(c){k(c,f)}},function(e,t){throw new Error("Couldn't load "+t+" ("+e+")")})}function E(e){return e.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r,i=t.href||"",s="less:"+(t.title||E(i));if((r=document.getElementById(s))===null){r=document.createElement("style"),r.type="text/css",t.media&&(r.media=t.media),r.id=s;var o=t&&t.nextSibling||null;(o||document.getElementsByTagName("head")[0]).parentNode.insertBefore(r,o)}if(r.styleSheet)try{r.styleSheet.cssText=e}catch(u){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(e){r.childNodes.length>0?r.firstChild.nodeValue!==e.nodeValue&&r.replaceChild(e,r.firstChild):r.appendChild(e)})(document.createTextNode(e));if(n&&l){C("saving "+i+" to cache.");try{l.setItem(i,e),l.setItem(i+":timestamp",n)}catch(u){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,t){var n="less-error-message:"+E(t),i='
  • {content}
  • ',s=document.createElement("div"),o,u,a=[],f=e.filename||t,l=f.match(/([^\/]+(\?.*)?)$/)[1];s.id=n,s.className="less-error-message",u="

    "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+="
    "+e.stack.split("\n").slice(1).join("
    "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+a.join("")+"
    "),s.innerHTML=u,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={}),t.rootpath=t.rootpath||"",t.files||(t.files={});var v=function(){},m=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r,s){i.queue.splice(i.queue.indexOf(e),1);var o=s in i.files;i.files[s]=r,t&&!i.error&&(i.error=t),n(t,r,o),i.queue.length===0&&v(i.error)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x,t);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e=x||e,e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/)||E(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)||E(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.rootpath)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=E(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},unicodeDescriptor:function(){var e;if(e=E(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a=[],f,l,c,h,p,d,v,m=o,b=s.charAt(o),w,S,C=!1;if(b!=="."&&b!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){p=[];while(c=E(this.expression)){h=null,S=c;if(c.value.length==1){var k=c.value[0];k instanceof i.Variable&&E(":")&&(p.length>0&&(d&&T("Cannot mix ; and , as delimiter types"),v=!0),S=x(this.expression),h=w=k.name)}p.push(S),a.push({name:h,value:S});if(E(","))continue;if(E(";")||d)v&&T("Cannot mix ; and , as delimiter types"),d=!0,p.length>1&&(S=new i.Value(p)),u.push({name:w,value:S}),w=null,p=[],v=!1}x(")")}f=d?u:a,E(this.important)&&(C=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,f,m,t.filename,C);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*\}/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{E(this.comment);if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0,t.push({variadic:!0});break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(",")||E(";"));E(")")||(l=o,y()),E(this.comment),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^()@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable)||E(this.selector))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"||t==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),E(")")?new i.Selector([new i.Element("",e,o)]):null;while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n)},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,n,r=o;g();var s=E(/^@import(?:-(once))?\s+/);if(s&&(e=E(this.entities.quoted)||E(this.entities.url))){n=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,n,s[1]==="once",r,t.rootpath)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=E(this["import"])||E(this.media))return n;g(),e=E(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(E(/^[^{]+/)||"").trim());if(c){if(r=E(this.block))return new i.Directive(e,r)}else if((n=p?E(this.expression):E(this.entity))&&E(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=A(o,s,t)),d}y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/[*\/]/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),w({href:e,title:e,type:r.mime,contents:r.contents,files:r.files,rootpath:r.rootpath,entryPath:r.entryPath,relativeUrls:r.relativeUrls},function(e,i,s,o,u,a){e&&typeof r.errback=="function"?r.errback.call(null,a,t,n,r):n.call(null,e,i,a)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t,n){return t instanceof e.Dimension&&t.unit=="%"?parseFloat(t.value*n/100):r(t)}function r(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function i(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,i,s,o){var u=[t,i,s].map(function(e){return n(e,256)});return o=r(o),new e.Color(u,o)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=r(e)%360/360,t=r(t),n=r(n),i=r(i);var s=n<=.5?n*(t+1):n+t-n*t,o=n*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,i){e=r(e)%360/360*360,t=r(t),n=r(n),i=r(i);var s,o;s=Math.floor(e/60%6),o=e/60-s;var u=[n,n*(1-t),n*(1-o*t),n*(1-(1-o)*t)],a=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(u[a[s][0]]*255,u[a[s][1]]*255,u[a[s][2]]*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var r=e.toHSL();return r.s+=n.value/100,r.s=i(r.s),t(r)},desaturate:function(e,n){var r=e.toHSL();return r.s-=n.value/100,r.s=i(r.s),t(r)},lighten:function(e,n){var r=e.toHSL();return r.l+=n.value/100,r.l=i(r.l),t(r)},darken:function(e,n){var r=e.toHSL();return r.l-=n.value/100,r.l=i(r.l),t(r)},fadein:function(e,n){var r=e.toHSL();return r.a+=n.value/100,r.a=i(r.a),t(r)},fadeout:function(e,n){var r=e.toHSL();return r.a-=n.value/100,r.a=i(r.a),t(r)},fade:function(e,n){var r=e.toHSL();return r.a=n.value/100,r.a=i(r.a),t(r)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return e.rgb?(typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s,o){var u=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),this.rootpath=o,t instanceof e.Quoted?this.path=/(\.[a-z]*$)|([\?;].*)$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css([\?;].*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&u.once&&(u.skip=r),u.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?(typeof this._path.value=="string"&&!/^(?:[a-z-]+:|\/)/.test(this._path.value)&&(this._path.value=this.rootpath+this._path.value),"@import "+this._path.toCSS()+t+";\n"):""},eval:function(t){var n,r=this.features&&this.features.eval(t);return this.skip?[]:this.css?this:(n=new e.Ruleset([],this.root.rules.slice(0)),n.evalImports(t),this.features?new e.Media(n.rules,this.features.value):n.rules)}}}(n("../tree")),function(e){e.JavaScript=function(e,t,n){this.escaped=n,this.expression=e,this.index=t},e.JavaScript.prototype={eval:function(t){var n,r=this,i={},s=this.expression.replace(/@\{([\w-]+)\}/g,function(n,i){return e.jsify((new e.Variable("@"+i,r.index)).eval(t))});try{s=new Function("return ("+s+")")}catch(o){throw{message:"JavaScript evaluation error: `"+s+"`",index:this.index}}for(var u in t.frames[0].variables())i[u.slice(1)]={value:t.frames[0].variables()[u].value,toJS:function(){return this.value.eval(t).toCSS()}};try{n=s.call(i)}catch(o){throw{message:"JavaScript evaluation error: '"+o.name+": "+o.message+"'",index:this.index}}return typeof n=="string"?new e.Quoted('"'+n+'"',n,this.escaped,this.index):Array.isArray(n)?new e.Anonymous(n.join(", ")):new e.Anonymous(n)}}}(n("../tree")),function(e){e.Keyword=function(e){this.value=e},e.Keyword.prototype={eval:function(){return this},toCSS:function(){return this.value},compare:function(t){return t instanceof e.Keyword?t.value===this.value?0:1:-1}},e.True=new e.Keyword("true"),e.False=new e.Keyword("false")}(n("../tree")),function(e){e.Media=function(t,n){var r=this.emptySelectors();this.features=new e.Value(n),this.ruleset=new e.Ruleset(r,t),this.ruleset.allowImports=!0},e.Media.prototype={toCSS:function(e,t){var n=this.features.toCSS(t);return this.ruleset.root=e.length===0||e[0].multiMedia,"@media "+n+(t.compress?"{":" {\n ")+this.ruleset.toCSS(e,t).trim().replace(/\n/g,"\n ")+(t.compress?"}":"\n}\n")},eval:function(t){t.mediaBlocks||(t.mediaBlocks=[],t.mediaPath=[]);var n=new e.Media([],[]);return this.debugInfo&&(this.ruleset.debugInfo=this.debugInfo,n.debugInfo=this.debugInfo),n.features=this.features.eval(t),t.mediaPath.push(n),t.mediaBlocks.push(n),t.frames.unshift(this.ruleset),n.ruleset=this.ruleset.eval(t),t.frames.shift(),t.mediaPath.pop(),t.mediaPath.length===0?n.evalTop(t):n.evalNested(t)},variable:function(t){return e.Ruleset.prototype.variable.call(this.ruleset,t)},find:function(){return e.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return e.Ruleset.prototype.rulesets.apply(this.ruleset)},emptySelectors:function(){var t=new e.Element("","&",0);return[new e.Selector([t])]},evalTop:function(t){var n=this;if(t.mediaBlocks.length>1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d + + + + + // vank: updated to LESS 1.3.1 + + diff --git a/EditorExtensions/Resources/alphabatize.png b/EditorExtensions/Resources/alphabatize.png new file mode 100644 index 000000000..4435fd344 Binary files /dev/null and b/EditorExtensions/Resources/alphabatize.png differ diff --git a/EditorExtensions/Resources/cross_browser.png b/EditorExtensions/Resources/cross_browser.png new file mode 100644 index 000000000..fa736d87d Binary files /dev/null and b/EditorExtensions/Resources/cross_browser.png differ diff --git a/EditorExtensions/Resources/embed.png b/EditorExtensions/Resources/embed.png new file mode 100644 index 000000000..21c04b2a8 Binary files /dev/null and b/EditorExtensions/Resources/embed.png differ diff --git a/EditorExtensions/Resources/extract.png b/EditorExtensions/Resources/extract.png new file mode 100644 index 000000000..9056c027e Binary files /dev/null and b/EditorExtensions/Resources/extract.png differ diff --git a/EditorExtensions/Resources/graph_atdir.png b/EditorExtensions/Resources/graph_atdir.png new file mode 100644 index 000000000..d47ccfca4 Binary files /dev/null and b/EditorExtensions/Resources/graph_atdir.png differ diff --git a/EditorExtensions/Resources/graph_class.png b/EditorExtensions/Resources/graph_class.png new file mode 100644 index 000000000..d06f787ce Binary files /dev/null and b/EditorExtensions/Resources/graph_class.png differ diff --git a/EditorExtensions/Resources/graph_id.png b/EditorExtensions/Resources/graph_id.png new file mode 100644 index 000000000..3f133ebc1 Binary files /dev/null and b/EditorExtensions/Resources/graph_id.png differ diff --git a/EditorExtensions/Resources/graph_parent.png b/EditorExtensions/Resources/graph_parent.png new file mode 100644 index 000000000..c332387ee Binary files /dev/null and b/EditorExtensions/Resources/graph_parent.png differ diff --git a/EditorExtensions/Resources/no_skull.png b/EditorExtensions/Resources/no_skull.png new file mode 100644 index 000000000..5bf4b6ae5 Binary files /dev/null and b/EditorExtensions/Resources/no_skull.png differ diff --git a/EditorExtensions/Resources/nopreview.png b/EditorExtensions/Resources/nopreview.png new file mode 100644 index 000000000..9a656d64e Binary files /dev/null and b/EditorExtensions/Resources/nopreview.png differ diff --git a/EditorExtensions/Resources/nuget.png b/EditorExtensions/Resources/nuget.png new file mode 100644 index 000000000..3202a0e74 Binary files /dev/null and b/EditorExtensions/Resources/nuget.png differ diff --git a/EditorExtensions/Resources/numbers.png b/EditorExtensions/Resources/numbers.png new file mode 100644 index 000000000..e27ed1b19 Binary files /dev/null and b/EditorExtensions/Resources/numbers.png differ diff --git a/EditorExtensions/Resources/palette.png b/EditorExtensions/Resources/palette.png new file mode 100644 index 000000000..0c2864f73 Binary files /dev/null and b/EditorExtensions/Resources/palette.png differ diff --git a/EditorExtensions/Resources/skull.png b/EditorExtensions/Resources/skull.png new file mode 100644 index 000000000..d35cb20b0 Binary files /dev/null and b/EditorExtensions/Resources/skull.png differ diff --git a/EditorExtensions/Resources/sort.png b/EditorExtensions/Resources/sort.png new file mode 100644 index 000000000..0a9fcba4c Binary files /dev/null and b/EditorExtensions/Resources/sort.png differ diff --git a/EditorExtensions/Resources/vsgallery.png b/EditorExtensions/Resources/vsgallery.png new file mode 100644 index 000000000..2750e25c9 Binary files /dev/null and b/EditorExtensions/Resources/vsgallery.png differ diff --git a/EditorExtensions/Resources/warning.png b/EditorExtensions/Resources/warning.png new file mode 100644 index 000000000..7e24d3f83 Binary files /dev/null and b/EditorExtensions/Resources/warning.png differ diff --git a/EditorExtensions/Schemas/Browsers/BrowserSchemaFilter.cs b/EditorExtensions/Schemas/Browsers/BrowserSchemaFilter.cs new file mode 100644 index 000000000..2f4665822 --- /dev/null +++ b/EditorExtensions/Schemas/Browsers/BrowserSchemaFilter.cs @@ -0,0 +1,46 @@ +using Microsoft.CSS.Editor; +using Microsoft.CSS.Editor.Schemas; +using Microsoft.VisualStudio.Utilities; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Text; + +namespace MadsKristensen.EditorExtensions.Schemas +{ + [Export(typeof(ICssSchemaModuleProvider))] + [Name("BrowserSchemaFilter")] + [Order(Before = "User Schemas")] + class BrowserSchemaFilter : ICssSchemaModuleProvider + { + private byte[] _emptyModule = Encoding.UTF8.GetBytes(""); + + public Stream GetModuleStream(string name) + { + if (name.Contains("vendor") && BrowserStore.Browsers.Count > 0) + { + if (!BrowserStore.Browsers.Contains("IE") && name.Contains("-ms.")) + { + return new MemoryStream(_emptyModule); + } + + if (!BrowserStore.Browsers.Contains("FF") && name.Contains("-moz.")) + { + return new MemoryStream(_emptyModule); + } + + if (!BrowserStore.Browsers.Contains("O") && name.Contains("-o.")) + { + return new MemoryStream(_emptyModule); + } + + if (!BrowserStore.Browsers.Contains("C") && !BrowserStore.Browsers.Contains("S") && name.Contains("-webkit.")) + { + return new MemoryStream(_emptyModule); + } + } + + return null; + } + } +} diff --git a/EditorExtensions/Schemas/Browsers/BrowserSelector.xaml b/EditorExtensions/Schemas/Browsers/BrowserSelector.xaml new file mode 100644 index 000000000..f443e1b1a --- /dev/null +++ b/EditorExtensions/Schemas/Browsers/BrowserSelector.xaml @@ -0,0 +1,19 @@ + + + + +