<commit_before>﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Threading;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
using NSass;
using SassyStudio.Compiler;
using SassyStudio.Compiler.Parsing;
using SassyStudio.Integration.Compass;
using SassyStudio.Integration.LibSass;
using SassyStudio.Integration.SassGem;
using SassyStudio.Options;
using Yahoo.Yui.Compressor;

namespace SassyStudio.Editor
{
    [Export(typeof(IWpfTextViewCreationListener))]
    [ContentType(ScssContentTypeDefinition.ScssContentType)]
    [TextViewRole(PredefinedTextViewRoles.Document)]
    class GenerateCssOnSave : IWpfTextViewCreationListener
    {
        static readonly Encoding UTF8_ENCODING = new UTF8Encoding(true);
        readonly Lazy<ScssOptions> _Options = new Lazy<ScssOptions>(() => SassyStudioPackage.Instance.Options.Scss, true);

        private ScssOptions Options { get { return _Options.Value; } }

        readonly IRootLevelDocumentCache DocumentCache;

        [ImportingConstructor]
        public GenerateCssOnSave(IRootLevelDocumentCache documentCache)
        {
            DocumentCache = documentCache;
        }

        public void TextViewCreated(IWpfTextView textView)
        {
            ITextDocument document;
            if (textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
            {
                document.FileActionOccurred += OnFileActionOccurred;
            }
            else
            {
                if (Options.IsDebugLoggingEnabled)
                    Logger.Log("Eh? Couldn't find text document. Can't handle saving documents now.");
            }
        }

        private void OnFileActionOccurred(object sender, TextDocumentFileActionEventArgs e)
        {
            if (e.FileActionType == FileActionTypes.ContentSavedToDisk)
            {
                if (Options.IsDebugLoggingEnabled)
                    Logger.Log("Detected file saved: " + e.FilePath);

                if (!Options.GenerateCssOnSave) return;

                var filename = Path.GetFileName(e.FilePath);

                // ignore anything that isn't .scss and not a root document
                if (!filename.EndsWith(".scss", StringComparison.OrdinalIgnoreCase))
                    return;

                if (filename.StartsWith("_"))
                {
                    if (Options.IsDebugLoggingEnabled)
                        Logger.Log("Compiling all files referencing include file: " + filename);

                    Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => GenerateAllReferencing(e.Time, e.FilePath)), DispatcherPriority.Background);
                }
                else
                {
                    if (Options.IsDebugLoggingEnabled)
                        Logger.Log("Compiling: " + filename);

                    Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => GenerateCss(e.Time, e.FilePath)), DispatcherPriority.Background);
                }
            }
        }

        private void GenerateAllReferencing(DateTime time, string path)
        {
            var source = new FileInfo(path);
            var documents = DocumentCache.Documents;

            var visited = new HashSet<ISassDocument>();
            foreach (var document in documents)
            {
                if (IsReferenced(source, document, visited))
                    GenerateCss(time, document.Source.FullName);
            }
        }

        private bool IsReferenced(FileInfo source, ISassDocument document, HashSet<ISassDocument> visited)
        {
            var comparer = StringComparer.CurrentCultureIgnoreCase;
            foreach (var import in document.Stylesheet.Children.OfType<SassImportDirective>().SelectMany(x => x.Files).Where(x => x.Document != null))
            {
                if (comparer.Equals(import.Document.Source.FullName, source.FullName))
                    return true;

                if (!visited.Add(import.Document))
                    continue;

                if (IsReferenced(source, import.Document, visited))
                    return true;
            }

            return false;
        }

        private void GenerateCss(DateTime time, string path)
        {
            if (Options.IsDebugLoggingEnabled)
                Logger.Log("Beginning compile: " + path);
<commit_msg>unique set per visited root<commit_after>﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Threading;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
using NSass;
using SassyStudio.Compiler;
using SassyStudio.Compiler.Parsing;
using SassyStudio.Integration.Compass;
using SassyStudio.Integration.LibSass;
using SassyStudio.Integration.SassGem;
using SassyStudio.Options;
using Yahoo.Yui.Compressor;

namespace SassyStudio.Editor
{
    [Export(typeof(IWpfTextViewCreationListener))]
    [ContentType(ScssContentTypeDefinition.ScssContentType)]
    [TextViewRole(PredefinedTextViewRoles.Document)]
    class GenerateCssOnSave : IWpfTextViewCreationListener
    {
        static readonly Encoding UTF8_ENCODING = new UTF8Encoding(true);
        readonly Lazy<ScssOptions> _Options = new Lazy<ScssOptions>(() => SassyStudioPackage.Instance.Options.Scss, true);

        private ScssOptions Options { get { return _Options.Value; } }

        readonly IRootLevelDocumentCache DocumentCache;

        [ImportingConstructor]
        public GenerateCssOnSave(IRootLevelDocumentCache documentCache)
        {
            DocumentCache = documentCache;
        }

        public void TextViewCreated(IWpfTextView textView)
        {
            ITextDocument document;
            if (textView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
            {
                document.FileActionOccurred += OnFileActionOccurred;
            }
            else
            {
                if (Options.IsDebugLoggingEnabled)
                    Logger.Log("Eh? Couldn't find text document. Can't handle saving documents now.");
            }
        }

        private void OnFileActionOccurred(object sender, TextDocumentFileActionEventArgs e)
        {
            if (e.FileActionType == FileActionTypes.ContentSavedToDisk)
            {
                if (Options.IsDebugLoggingEnabled)
                    Logger.Log("Detected file saved: " + e.FilePath);

                if (!Options.GenerateCssOnSave) return;

                var filename = Path.GetFileName(e.FilePath);

                // ignore anything that isn't .scss and not a root document
                if (!filename.EndsWith(".scss", StringComparison.OrdinalIgnoreCase))
                    return;

                if (filename.StartsWith("_"))
                {
                    if (Options.IsDebugLoggingEnabled)
                        Logger.Log("Compiling all files referencing include file: " + filename);

                    Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => GenerateAllReferencing(e.Time, e.FilePath)), DispatcherPriority.Background);
                }
                else
                {
                    if (Options.IsDebugLoggingEnabled)
                        Logger.Log("Compiling: " + filename);

                    Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => GenerateCss(e.Time, e.FilePath)), DispatcherPriority.Background);
                }
            }
        }

        private void GenerateAllReferencing(DateTime time, string path)
        {
            var source = new FileInfo(path);
            var documents = DocumentCache.Documents;

            foreach (var document in documents)
            {
                if (IsReferenced(source, document, new HashSet<ISassDocument>()))
                    GenerateCss(time, document.Source.FullName);
            }
        }

        private bool IsReferenced(FileInfo source, ISassDocument document, HashSet<ISassDocument> visited)
        {
            var comparer = StringComparer.CurrentCultureIgnoreCase;
            foreach (var import in document.Stylesheet.Children.OfType<SassImportDirective>().SelectMany(x => x.Files).Where(x => x.Document != null))
            {
                if (comparer.Equals(import.Document.Source.FullName, source.FullName))
                    return true;

                if (!visited.Add(import.Document))
                    continue;

                if (IsReferenced(source, import.Document, visited))
                    return true;
            }

            return false;
        }

        private void GenerateCss(DateTime time, string path)
        {
            if (Options.IsDebugLoggingEnabled)
                Logger.Log("Beginning compile: " + path);

{'fraction_non_alphanumeric': 0.08299661461177242, 'fraction_numerical': 0.00043682428743038114, 'mean_word_length': 2.2009786787836423, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1680440', 'n_tokens_mistral': 2377, 'n_tokens_neox': 2214, 'n_words': 473}