From 6663fbeaf1932f2744b37c03f4b0eba179657338 Mon Sep 17 00:00:00 2001 From: Darren Kopp Date: Mon, 9 Sep 2013 15:05:03 -0600 Subject: [PATCH] fixes and cleanup - cleanup logging - add option to control whether intellisense is enabled or not - ditch some old code. --- .../Compiler/BackgroundParsingTask.cs | 4 - .../Editor/CommentSelectionCommandHandler.cs | 87 ++++++++ SassyStudio.2012/Editor/DocumentListener.cs | 6 +- .../ContextProviders/MixinContextProvider.cs | 8 +- .../ValueProviders/MixinsProvider.cs | 2 - .../Intellisense/CompletionCommandHandler.cs | 11 +- .../Intellisense/SassCompletionSource.cs | 6 +- SassyStudio.2012/Options/ScssOptions.cs | 5 + SassyStudio.2012/SassyStudio.2012.csproj | 7 +- .../Scss/Commands/CommentSelection.cs | 74 ------- .../Scss/ScssViewCreationListener.cs | 29 --- .../Taggers/DeprecatedFunctionalityTagger.cs | 79 ------- .../Scss/Taggers/MultilineTagger.cs | 194 ------------------ .../Scss/Taggers/ScssOutliningTagger.cs | 165 --------------- .../Taggers/ScssOutliningTaggingProvider.cs | 26 --- .../Parsing/MixinReference.cs | 2 + 16 files changed, 110 insertions(+), 595 deletions(-) create mode 100644 SassyStudio.2012/Editor/CommentSelectionCommandHandler.cs delete mode 100644 SassyStudio.2012/Scss/Commands/CommentSelection.cs delete mode 100644 SassyStudio.2012/Scss/ScssViewCreationListener.cs delete mode 100644 SassyStudio.2012/Scss/Taggers/DeprecatedFunctionalityTagger.cs delete mode 100644 SassyStudio.2012/Scss/Taggers/MultilineTagger.cs delete mode 100644 SassyStudio.2012/Scss/Taggers/ScssOutliningTagger.cs delete mode 100644 SassyStudio.2012/Scss/Taggers/ScssOutliningTaggingProvider.cs diff --git a/SassyStudio.2012/Compiler/BackgroundParsingTask.cs b/SassyStudio.2012/Compiler/BackgroundParsingTask.cs index ba5d96b..43416c6 100644 --- a/SassyStudio.2012/Compiler/BackgroundParsingTask.cs +++ b/SassyStudio.2012/Compiler/BackgroundParsingTask.cs @@ -48,8 +48,6 @@ void ProcessRequests() source.Refresh(); if (source.Exists) { - Logger.Log(string.Format("Background Parse: {0}", source.FullName)); - ISassStylesheet stylesheet = null; var textManager = new FileTextManager(source); using (var scope = textManager.Open()) @@ -60,8 +58,6 @@ void ProcessRequests() if (stylesheet != null) request.Document.Update(stylesheet); - - Logger.Log(string.Format("Background Parse Complete: {0}", source.FullName)); } } catch (Exception ex) diff --git a/SassyStudio.2012/Editor/CommentSelectionCommandHandler.cs b/SassyStudio.2012/Editor/CommentSelectionCommandHandler.cs new file mode 100644 index 0000000..e23a890 --- /dev/null +++ b/SassyStudio.2012/Editor/CommentSelectionCommandHandler.cs @@ -0,0 +1,87 @@ +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using System; +using System.Collections.Generic; + +namespace SassyStudio.Editor +{ + class CommentSelectionCommandHandler : VSCommandTarget + { + readonly ITextBuffer Buffer; + public CommentSelectionCommandHandler(IVsTextView vsTextView, IWpfTextView textView) + : base(vsTextView, textView) + { + Buffer = textView.TextBuffer; + } + + protected override bool Execute(VSConstants.VSStd2KCmdID command, uint options, IntPtr pvaIn, IntPtr pvaOut) + { + if (TextView.Selection.IsEmpty) return false; + + + var snapshot = Buffer.CurrentSnapshot; + int start = TextView.Selection.Start.Position.Position; + int end = TextView.Selection.End.Position.Position; + + // TODO: pre-process the input and determine start position of left-most + // text just like visual studio does + + using (var edit = Buffer.CreateEdit()) + { + while (start < end) + { + var line = snapshot.GetLineFromPosition(start); + var text = line.GetText(); + switch (command) + { + case VSConstants.VSStd2KCmdID.COMMENTBLOCK: + case VSConstants.VSStd2KCmdID.COMMENT_BLOCK: + { + if (!string.IsNullOrEmpty(text)) + edit.Insert(line.Start.Position, "//"); + + break; + } + case VSConstants.VSStd2KCmdID.UNCOMMENTBLOCK: + case VSConstants.VSStd2KCmdID.UNCOMMENT_BLOCK: + { + if (text.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + edit.Delete(line.Start.Position, 2); + + break; + } + } + + start = line.EndIncludingLineBreak.Position; + } + + edit.Apply(); + } + + return true; + } + + protected override IEnumerable SupportedCommands + { + get + { + yield return VSConstants.VSStd2KCmdID.COMMENTBLOCK; + yield return VSConstants.VSStd2KCmdID.COMMENT_BLOCK; + yield return VSConstants.VSStd2KCmdID.UNCOMMENT_BLOCK; + yield return VSConstants.VSStd2KCmdID.UNCOMMENTBLOCK; + } + } + + protected override VSConstants.VSStd2KCmdID ConvertFromCommandId(uint id) + { + return (VSConstants.VSStd2KCmdID)id; + } + + protected override uint ConvertFromCommand(VSConstants.VSStd2KCmdID command) + { + return (uint)command; + } + } +} diff --git a/SassyStudio.2012/Editor/DocumentListener.cs b/SassyStudio.2012/Editor/DocumentListener.cs index 36e7ef4..5e0d7a5 100644 --- a/SassyStudio.2012/Editor/DocumentListener.cs +++ b/SassyStudio.2012/Editor/DocumentListener.cs @@ -32,8 +32,10 @@ public void VsTextViewCreated(IVsTextView textViewAdapter) var textView = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); textView.Closed += OnClosed; - // register command handler for completion - textView.Properties.GetOrCreateSingletonProperty(() => new CompletionCommandHandler(CompletionBroker, textViewAdapter, textView)); + textView.Properties.GetOrCreateSingletonProperty(() => new CommentSelectionCommandHandler(textViewAdapter, textView)); + + if (SassyStudioPackage.Instance.Options.Scss.EnableExperimentalIntellisense) + textView.Properties.GetOrCreateSingletonProperty(() => new CompletionCommandHandler(CompletionBroker, textViewAdapter, textView)); } void OnClosed(object sender, EventArgs e) diff --git a/SassyStudio.2012/Editor/Intellisense/Completion/ContextProviders/MixinContextProvider.cs b/SassyStudio.2012/Editor/Intellisense/Completion/ContextProviders/MixinContextProvider.cs index c9a5547..b7193df 100644 --- a/SassyStudio.2012/Editor/Intellisense/Completion/ContextProviders/MixinContextProvider.cs +++ b/SassyStudio.2012/Editor/Intellisense/Completion/ContextProviders/MixinContextProvider.cs @@ -16,6 +16,10 @@ public IEnumerable GetContext(ParseItem current, int { yield return SassCompletionContextType.MixinDirective; } + else if (current is MixinDefinitionBody) + { + yield return SassCompletionContextType.MixinBody; + } else if (current is RuleBlock) { yield return SassCompletionContextType.IncludeDirective; @@ -41,10 +45,6 @@ public IEnumerable GetContext(ParseItem current, int yield return SassCompletionContextType.IncludeDirectiveMixinArgumentValue; } - else if (current is MixinDefinitionBody) - { - yield return SassCompletionContextType.MixinBody; - } } } } diff --git a/SassyStudio.2012/Editor/Intellisense/Completion/ValueProviders/MixinsProvider.cs b/SassyStudio.2012/Editor/Intellisense/Completion/ValueProviders/MixinsProvider.cs index 6d1061c..63ea26e 100644 --- a/SassyStudio.2012/Editor/Intellisense/Completion/ValueProviders/MixinsProvider.cs +++ b/SassyStudio.2012/Editor/Intellisense/Completion/ValueProviders/MixinsProvider.cs @@ -14,7 +14,6 @@ public IEnumerable SupportedContexts { get { - yield return SassCompletionContextType.IncludeDirective; yield return SassCompletionContextType.IncludeDirectiveMixinName; } } @@ -23,7 +22,6 @@ public IEnumerable GetCompletions(SassCompletionContextType ty { switch (type) { - case SassCompletionContextType.IncludeDirective: case SassCompletionContextType.IncludeDirectiveMixinName: return context.Cache.GetMixins(context.Position); } diff --git a/SassyStudio.2012/Editor/Intellisense/CompletionCommandHandler.cs b/SassyStudio.2012/Editor/Intellisense/CompletionCommandHandler.cs index 934689f..d0f6463 100644 --- a/SassyStudio.2012/Editor/Intellisense/CompletionCommandHandler.cs +++ b/SassyStudio.2012/Editor/Intellisense/CompletionCommandHandler.cs @@ -168,12 +168,10 @@ private bool Complete(bool force = false) // only commit if something selected or forced to commit if (Session.SelectedCompletionSet.SelectionStatus.IsSelected || force) { - Logger.Log("Committed."); Session.Commit(); return true; } - Logger.Log("dismissed"); // we couldn't commit, so dismiss Session.Dismiss(); } @@ -194,7 +192,6 @@ private bool Dismiss(ICompletionSession session) private void OnSessionDismissed(object sender, EventArgs e) { - Logger.Log("Dismissed event."); var session = sender as ICompletionSession; session.Dismissed -= OnSessionDismissed; @@ -261,8 +258,7 @@ private bool IsTerminalCharacter(char typed) private int GetCompletionStart(ITextSnapshot snapshot, ITextSnapshotLine line, int position) { - Logger.Log(string.Format("Scanning for word boundary. Line = '{0}', Position = '{1}'", line.LineNumber, position)); - int start = position--; + int start = position; while (start > line.Start.Position) { // stop once we hit whitespace @@ -273,10 +269,7 @@ private int GetCompletionStart(ITextSnapshot snapshot, ITextSnapshotLine line, i } } - start = Math.Max(start, line.Start.Position); - - Logger.Log(string.Format("Start of completion set to {0}", start)); - return start; + return Math.Max(start, line.Start.Position); } private bool Ignore(VSCommand command, char typed) diff --git a/SassyStudio.2012/Editor/Intellisense/SassCompletionSource.cs b/SassyStudio.2012/Editor/Intellisense/SassCompletionSource.cs index 323ee4c..9bdb8a0 100644 --- a/SassyStudio.2012/Editor/Intellisense/SassCompletionSource.cs +++ b/SassyStudio.2012/Editor/Intellisense/SassCompletionSource.cs @@ -81,7 +81,11 @@ private IEnumerable CalculateApplicableContexts(IComp private ICompletionContext CreateCompletionContext(ISassStylesheet stylesheet, int position) { - var current = stylesheet.Children.FindItemContainingPosition(position) ?? (stylesheet as Stylesheet); + var current = stylesheet.Children.FindItemContainingPosition(Math.Max(0, position-1)); + if (current != null && !current.IsUnclosed) + current = stylesheet.Children.FindItemContainingPosition(position); + + current = current ?? (stylesheet as Stylesheet); return new CompletionContext { diff --git a/SassyStudio.2012/Options/ScssOptions.cs b/SassyStudio.2012/Options/ScssOptions.cs index 173cfd3..4433d1b 100644 --- a/SassyStudio.2012/Options/ScssOptions.cs +++ b/SassyStudio.2012/Options/ScssOptions.cs @@ -46,5 +46,10 @@ public override void LoadSettingsFromStorage() [Description("When enabled, comments will be added to the .css file specifying the file and line number where the values originated from.")] [Category("SCSS")] public bool IncludeSourceComments { get; set; } + + [LocDisplayName("Experimental Intellisense")] + [Description("When enabled, statement completion will be enabled for variables, functions, mixins and keywords.")] + [Category("Intellisense")] + public bool EnableExperimentalIntellisense { get; set; } } } diff --git a/SassyStudio.2012/SassyStudio.2012.csproj b/SassyStudio.2012/SassyStudio.2012.csproj index 79b8a7b..9a84662 100644 --- a/SassyStudio.2012/SassyStudio.2012.csproj +++ b/SassyStudio.2012/SassyStudio.2012.csproj @@ -60,6 +60,7 @@ + @@ -117,7 +118,6 @@ - @@ -134,11 +134,6 @@ - - - - - diff --git a/SassyStudio.2012/Scss/Commands/CommentSelection.cs b/SassyStudio.2012/Scss/Commands/CommentSelection.cs deleted file mode 100644 index 9fe1761..0000000 --- a/SassyStudio.2012/Scss/Commands/CommentSelection.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Microsoft.VisualStudio.OLE.Interop; -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; -using System.Threading.Tasks; -using VSCommandIdConstants = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using SassyStudio.Commands; - -namespace SassyStudio.Scss.Commands -{ - class CommentSelection : CommandTargetBase - { - readonly ITextBuffer Buffer; - public CommentSelection(IVsTextView adapter, IWpfTextView textView) - : base(adapter, textView, typeof(VSCommandIdConstants).GUID, (uint)VSCommandIdConstants.COMMENTBLOCK, (uint)VSCommandIdConstants.COMMENT_BLOCK, (uint)VSCommandIdConstants.UNCOMMENT_BLOCK, (uint)VSCommandIdConstants.UNCOMMENTBLOCK) - { - Buffer = textView.TextBuffer; - } - - protected override bool IsEnabled() - { - return true; - } - - protected override bool Execute(uint commandId, uint execOptions, IntPtr pvaIn, IntPtr pvaOut) - { - if (TextView.Selection.IsEmpty) return false; - - - var snapshot = Buffer.CurrentSnapshot; - int start = TextView.Selection.Start.Position.Position; - int end = TextView.Selection.End.Position.Position; - - using (var edit = Buffer.CreateEdit()) - { - while (start < end) - { - var line = snapshot.GetLineFromPosition(start); - var text = line.GetText(); - switch (commandId) - { - case (uint)VSCommandIdConstants.COMMENTBLOCK: - case (uint)VSCommandIdConstants.COMMENT_BLOCK: - { - if (!string.IsNullOrEmpty(text)) - edit.Insert(line.Start.Position, "//"); - - break; - } - case (uint)VSCommandIdConstants.UNCOMMENTBLOCK: - case (uint)VSCommandIdConstants.UNCOMMENT_BLOCK: - { - if (text.StartsWith("//", StringComparison.OrdinalIgnoreCase)) - edit.Delete(line.Start.Position, 2); - - break; - } - default: break; - } - - start = line.EndIncludingLineBreak.Position; - } - - edit.Apply(); - } - - return true; - } - } -} diff --git a/SassyStudio.2012/Scss/ScssViewCreationListener.cs b/SassyStudio.2012/Scss/ScssViewCreationListener.cs deleted file mode 100644 index cf73531..0000000 --- a/SassyStudio.2012/Scss/ScssViewCreationListener.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudio.Utilities; -using SassyStudio.Scss.Commands; -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SassyStudio.Scss -{ - [Export(typeof(IVsTextViewCreationListener))] - [ContentType(ScssContentTypeDefinition.ScssContentType)] - [TextViewRole(PredefinedTextViewRoles.Document)] - class ScssViewCreationListener : IVsTextViewCreationListener - { - [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal IVsEditorAdaptersFactoryService EditorAdaptersFactoryService { get; set; } - - public void VsTextViewCreated(IVsTextView textViewAdapter) - { - var view = EditorAdaptersFactoryService.GetWpfTextView(textViewAdapter); - view.Properties.GetOrCreateSingletonProperty(() => new CommentSelection(textViewAdapter, view)); - } - } -} diff --git a/SassyStudio.2012/Scss/Taggers/DeprecatedFunctionalityTagger.cs b/SassyStudio.2012/Scss/Taggers/DeprecatedFunctionalityTagger.cs deleted file mode 100644 index 0513a5a..0000000 --- a/SassyStudio.2012/Scss/Taggers/DeprecatedFunctionalityTagger.cs +++ /dev/null @@ -1,79 +0,0 @@ -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; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace SassyStudio.Scss.Taggers -{ - //[Export(typeof(ITaggerProvider))] - //[TagType(typeof(IErrorTag))] - //[ContentType(ScssContentTypeDefinition.ScssContentType)] - class DeprecatedFunctionalityTaggingProvider : ITaggerProvider - { - public ITagger CreateTagger(ITextBuffer buffer) where T : ITag - { - if (buffer != null) - return buffer.Properties.GetOrCreateSingletonProperty(() => new DeprecatedFunctionalityTagger()) as ITagger; - - return null; - } - } - - class DeprecatedFunctionalityTagger : ITagger - { - readonly Tuple[] WarningProviders; - public DeprecatedFunctionalityTagger() - { - WarningProviders = new[] { - CreateProvider(@"\!(?!default|important)[a-z0-9-_]+", "Variables in the form !name are no longer supported. Use the $name syntax instead."), - CreateProvider(@"(?:\!|\$)[a-z0-9-_]+(?=\s*=[^=]+)", "Variable assignment using '=' is no longer supported. Use the $name: value syntax instead.") - }; - } - - public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) - { - var checkedLines = new HashSet(); - foreach (var span in spans) - { - var line = span.Start.GetContainingLine(); - if (checkedLines.Add(line.LineNumber)) - { - var position = span.Start.Position; - var text = line.GetTextIncludingLineBreak(); - - foreach (var warning in FindWarnings(span, text).Where(x => span.IntersectsWith(x.Span))) - yield return warning; - } - } - } - - private IEnumerable> FindWarnings(SnapshotSpan source, string text) - { - foreach (var provider in WarningProviders) - { - var regex = provider.Item1; - var match = regex.Match(text); - while (match.Success) - { - var span = new SnapshotSpan(source.Snapshot, new Span(source.Start + match.Index, match.Length)); - yield return new TagSpan(span, new ErrorTag("Warning", provider.Item2)); - - match = match.NextMatch(); - } - } - } - - private static Tuple CreateProvider(string pattern, string message) - { - return Tuple.Create(new Regex(pattern, RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase), message); - } - - public event EventHandler TagsChanged { add { } remove { } } - } -} diff --git a/SassyStudio.2012/Scss/Taggers/MultilineTagger.cs b/SassyStudio.2012/Scss/Taggers/MultilineTagger.cs deleted file mode 100644 index 802412a..0000000 --- a/SassyStudio.2012/Scss/Taggers/MultilineTagger.cs +++ /dev/null @@ -1,194 +0,0 @@ -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; -using Microsoft.VisualStudio.Text.Tagging; -using Microsoft.VisualStudio.Utilities; -using SassyStudio.Scss.Classifications; -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SassyStudio.Scss.Taggers -{ - //[Export(typeof(ITaggerProvider))] - //[TagType(typeof(IClassificationTag))] - //[ContentType(ScssContentTypeDefinition.ScssContentType)] - class MultilineTaggerProvider : ITaggerProvider - { - [Import, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal IClassificationTypeRegistryService Registry { get; set; } - - public ITagger CreateTagger(ITextBuffer buffer) where T : ITag - { - return buffer.Properties.GetOrCreateSingletonProperty(() => new MultilineTagger(buffer, Registry.GetClassificationType(ScssClassificationTypes.Comment))) as ITagger; - } - } - - class MultilineTagger : ITagger - { - readonly ITextBuffer Buffer; - readonly ClassificationTag Tag; - - public MultilineTagger(ITextBuffer buffer, IClassificationType commentType) - { - Tag = new ClassificationTag(commentType); - CurrentSnapshot = buffer.CurrentSnapshot; - CurrentComments = new List(); - Buffer = buffer; - Buffer.ChangedLowPriority += OnBufferChanged; - - Task.Run(() => this.Parse()); - } - - private ITextSnapshot CurrentSnapshot { get; set; } - private IReadOnlyCollection CurrentComments { get; set; } - - public event EventHandler TagsChanged; - - public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) - { - if (spans.Count == 0) yield break; - - var snapshot = CurrentSnapshot; - var comments = CurrentComments; - - var startLine = spans[0].Start.GetContainingLine().LineNumber; - var endLine = spans[spans.Count - 1].End.GetContainingLine().LineNumber; - - foreach (var region in comments.Where(x => x.StartLine <= endLine && x.EndLine >= startLine)) - { - var span = AsSnapshotSpan(region, snapshot); - - yield return new TagSpan(span, Tag); - } - } - - private void Parse() - { - var snapshot = Buffer.CurrentSnapshot; - var comments = GetComments(snapshot); - - var originalSpans = GetSpans(CurrentComments, CurrentSnapshot, snapshot); - var currentSpans = GetSpans(comments, snapshot, snapshot); - - // figure out who has changed (added or removed) - var unchanged = originalSpans.Intersect(currentSpans).ToList(); - var added = currentSpans.Except(unchanged); - var removed = originalSpans.Except(unchanged); - - // get normalized view or the range of what has ben added / removed - var changed = new NormalizedSnapshotSpanCollection( - added.Concat(removed).Select(span => new SnapshotSpan(snapshot, span)) - ); - - // update our regions and snapshots - CurrentSnapshot = snapshot; - CurrentComments = comments; - - var tagsChanged = this.TagsChanged; - if (tagsChanged != null && changed.Count > 0) - { - foreach (var span in changed) - tagsChanged(this, new SnapshotSpanEventArgs(span)); - } - } - - private void OnBufferChanged(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(() => Parse()); - } - - static IReadOnlyCollection GetComments(ITextSnapshot snapshot) - { - var results = new List(); - - CommentRegion current = null; - foreach (var line in snapshot.Lines) - { - var text = line.GetText(); - for (int i = 0; i < text.Length; i++) - { - char c = text[i]; - if (c == '/') - { - // already in comment, this won't break us out until we get a * - if (current != null) continue; - // eager scan ahead by 1+ character (if not a match, won't matter anyway - if ((i + 1) < text.Length) - { - char n = text[++i]; - // double forward slash means we can stop attempting to parse - if (n == '/') break; - if (n == '*') - { - current = new CommentRegion - { - StartLine = line.LineNumber, - StartOffset = i-1 // offset the ++ - }; - } - } - } - else if (c == '*') - { - // not in a comment, this won't matter - if (current == null) continue; - if ((i + 1) < text.Length) - { - char n = text[++i]; - if (n == '/') - { - // capture ending information, add to results and reset - current.EndLine = line.LineNumber; - current.EndOffset = i - 1; // offset the ++ - results.Add(current); - current = null; - } - } - } - } - } - - if (current != null) - { - var lastLine = snapshot.Lines.Last(); - current.EndLine = lastLine.LineNumber; - current.EndOffset = lastLine.End.Position; - results.Add(current); - current = null; - } - - return results; - } - - private static IEnumerable GetSpans(IEnumerable regions, ITextSnapshot originalSnapshot, ITextSnapshot currentSnapshot) - { - var results = regions.Select(r => AsSnapshotSpan(r, originalSnapshot)); - if (originalSnapshot != currentSnapshot) - results = results.Select(s => s.TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive)); - - return results.Select(x => x.Span); - } - - static SnapshotSpan AsSnapshotSpan(CommentRegion region, ITextSnapshot snapshot) - { - var startLine = snapshot.GetLineFromLineNumber(region.StartLine); - var endLine = snapshot.GetLineFromLineNumber(region.EndLine); - return new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End + region.EndOffset); - } - - - class CommentRegion - { - public int StartLine { get; set; } - public int StartOffset { get; set; } - public int EndLine { get; set; } - public int EndOffset { get; set; } - } - } -} diff --git a/SassyStudio.2012/Scss/Taggers/ScssOutliningTagger.cs b/SassyStudio.2012/Scss/Taggers/ScssOutliningTagger.cs deleted file mode 100644 index 440b8fe..0000000 --- a/SassyStudio.2012/Scss/Taggers/ScssOutliningTagger.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Tagging; - -namespace SassyStudio.Scss.Taggers -{ - class ScssOutliningTagger : ITagger - { - const string ellipsis = "..."; //the characters that are displayed when the region is collapsed - readonly ITextBuffer Buffer; - - public ScssOutliningTagger(ITextBuffer buffer) - { - Buffer = buffer; - CurrentSnapshot = buffer.CurrentSnapshot; - CurrentRegions = new List(0); - - Buffer.ChangedLowPriority += OnBufferChanged; - - // run parsing - Task.Run(() => this.ReParse()); - } - - private ITextSnapshot CurrentSnapshot { get; set; } - private IReadOnlyCollection CurrentRegions { get; set; } - - public event EventHandler TagsChanged; - public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) - { - if (spans.Count == 0) yield break; - - var snapshot = CurrentSnapshot; - var regions = CurrentRegions; - - var startLine = spans[0].Start.GetContainingLine().LineNumber; - var endLine = spans[spans.Count - 1].End.GetContainingLine().LineNumber; - - foreach (var region in regions.Where(x => x.StartLine <= endLine && x.EndLine >= startLine)) - { - var span = AsSnapshotSpan(region, snapshot); - var tag = new OutliningRegionTag(false, false, ellipsis, span.GetText()); - - yield return new TagSpan(span, tag); - } - } - - void OnBufferChanged(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(() => ReParse()); - } - - void ReParse() - { - var snapshot = Buffer.CurrentSnapshot; - var regions = GetRegions(snapshot); - - var originalSpans = GetSpans(CurrentRegions, CurrentSnapshot, snapshot); - var currentSpans = GetSpans(regions, snapshot, snapshot); - - // figure out who has changed (added or removed) - var unchanged = originalSpans.Intersect(currentSpans).ToList(); - var added = currentSpans.Except(unchanged); - var removed = originalSpans.Except(unchanged); - - // get normalized view or the range of what has ben added / removed - var changed = new NormalizedSnapshotSpanCollection( - added.Concat(removed).Select(span => new SnapshotSpan(snapshot, span)) - ); - - // update our regions and snapshots - CurrentSnapshot = snapshot; - CurrentRegions = regions; - - var tagsChanged = this.TagsChanged; - if (tagsChanged != null && changed.Count > 0) - { - foreach (var span in changed) - tagsChanged(this, new SnapshotSpanEventArgs(span)); - } - } - - private static IEnumerable GetSpans(IEnumerable regions, ITextSnapshot originalSnapshot, ITextSnapshot currentSnapshot) - { - var results = regions.Select(r => AsSnapshotSpan(r, originalSnapshot)); - if (originalSnapshot != currentSnapshot) - results = results.Select(s => s.TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive)); - - return results.Select(x => x.Span); - } - - static IReadOnlyCollection GetRegions(ITextSnapshot snapshot) - { - List results = new List(); - - Stack regions = new Stack(); - foreach (var line in snapshot.Lines) - { - var text = line.GetText(); - for (int i = 0; i < text.Length; i++) - { - char current = text[i]; - if (current == '{') - { - // start a new region - regions.Push(new Region - { - StartLine = line.LineNumber, - StartOffset = i - }); - } - else if (current == '}') - { - // if we have opening region - if (regions.Count > 0) - { - var region = regions.Pop(); - region.EndLine = line.LineNumber; - - // don't outline if open and close on same line - if (region.StartLine < region.EndLine) - results.Add(region); - } - } - } - } - - // pop off stranded regions until we get to the start - while (regions.Count > 1) - regions.Pop(); - - // if we have an unclosed region, close it with ending line - if (regions.Count > 0) - { - var lastRegion = regions.Pop(); - lastRegion.EndLine = snapshot.Lines.Last().LineNumber; - if (lastRegion.StartLine < lastRegion.EndLine) - results.Add(lastRegion); - } - - return results; - } - - static SnapshotSpan AsSnapshotSpan(Region region, ITextSnapshot snapshot) - { - var startLine = snapshot.GetLineFromLineNumber(region.StartLine); - var endLine = snapshot.GetLineFromLineNumber(region.EndLine); - return new SnapshotSpan(startLine.Start + region.StartOffset, endLine.End); - } - - class Region - { - public int StartLine { get; set; } - public int StartOffset { get; set; } - public int EndLine { get; set; } - } - } -} diff --git a/SassyStudio.2012/Scss/Taggers/ScssOutliningTaggingProvider.cs b/SassyStudio.2012/Scss/Taggers/ScssOutliningTaggingProvider.cs deleted file mode 100644 index 98347b8..0000000 --- a/SassyStudio.2012/Scss/Taggers/ScssOutliningTaggingProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Tagging; -using Microsoft.VisualStudio.Utilities; - -namespace SassyStudio.Scss.Taggers -{ - //[Export(typeof(ITaggerProvider))] - //[TagType(typeof(IOutliningRegionTag))] - //[ContentType(ScssContentTypeDefinition.ScssContentType)] - class ScssOutliningTaggingProvider : ITaggerProvider - { - public ITagger CreateTagger(ITextBuffer buffer) where T : ITag - { - if (buffer != null) - return buffer.Properties.GetOrCreateSingletonProperty(() => new ScssOutliningTagger(buffer)) as ITagger; - - return null; - } - } -} diff --git a/SassyStudio.Compiler/Parsing/MixinReference.cs b/SassyStudio.Compiler/Parsing/MixinReference.cs index 7adffdc..9ce9806 100644 --- a/SassyStudio.Compiler/Parsing/MixinReference.cs +++ b/SassyStudio.Compiler/Parsing/MixinReference.cs @@ -18,6 +18,8 @@ public class MixinReference : ComplexItem public TokenItem Semicolon { get; protected set; } public IReadOnlyCollection Arguments { get { return _Arguments; } } + public override bool IsUnclosed { get { return Semicolon != null || CloseBrace != null; } } + public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (AtRule.IsRule(text, stream, "include"))