Example #1
0
        //=====================================================================

        /// <inheritdoc />
        public IEnumerable <ITagSpan <NaturalTextTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (classifier == null || spans == null || spans.Count == 0)
            {
                yield break;
            }

            ITextSnapshot snapshot = spans[0].Snapshot;

            foreach (var snapshotSpan in spans)
            {
                Debug.Assert(snapshotSpan.Snapshot.TextBuffer == buffer);

                foreach (ClassificationSpan classificationSpan in classifier.GetClassificationSpans(snapshotSpan))
                {
                    string name = classificationSpan.ClassificationType.Classification.ToLowerInvariant();

                    switch (name)
                    {
                    case "md_bold":         // Markers only, these contain nothing that can be spell checked
                    case "md_header":
                    case "md_html":
                    case "md_italic":
                    case "md_quote":
                    case "keyword":
                        break;

                    default:
                        // "md_code" will most likely contain a fair number of false reports but the
                        // classification can be excluded if necessary through the configuration or
                        // specific unwanted words through the Ignore Spelling directive.
                        classificationCache.Add(name);

                        if (!ignoredClassifications.Contains(name))
                        {
                            yield return(new TagSpan <NaturalTextTag>(classificationSpan.Span, new NaturalTextTag()));
                        }
                        break;
                    }
                }
            }
        }
Example #2
0
        //=====================================================================

        /// <inheritdoc />
        public IEnumerable <ITagSpan <NaturalTextTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            bool   preprocessorKeywordSeen = false, delimiterSeen = false;
            string elementName = null, attributeName = null, text;
            int    pos;

            if (classifier == null || spans == null || spans.Count == 0)
            {
                yield break;
            }

            ITextSnapshot snapshot = spans[0].Snapshot;

            foreach (var snapshotSpan in spans)
            {
                Debug.Assert(snapshotSpan.Snapshot.TextBuffer == buffer);

                foreach (ClassificationSpan classificationSpan in classifier.GetClassificationSpans(snapshotSpan))
                {
                    string name = classificationSpan.ClassificationType.Classification.ToLowerInvariant(),
                                            originalName = name;

                    // Do some conversion to make things simpler below
                    switch (name)
                    {
                    case "sql string":
                        // Skip the leading Unicode indicator if present
                        var span = classificationSpan.Span;

                        if (span.Length > 2 && span.GetText()[0] == 'N')
                        {
                            span = new SnapshotSpan(span.Snapshot, span.Start + 1, span.Length - 1);
                        }

                        classificationCache.Add(name);

                        if (!ignoredClassifications.Contains(name))
                        {
                            yield return(new TagSpan <NaturalTextTag>(span, new NaturalTextTag()));
                        }
                        continue;

                    case "vb xml doc attribute":
                        name = "attribute value";
                        break;

                    // VS2015 is much more specific in classifying XML doc comment parts
                    case "xml doc comment - delimiter":
                        name = "xml delimiter";
                        break;

                    case "xml doc comment - name":
                        name = "xml name";
                        break;

                    case "xml doc comment - attribute name":
                        name = "xml attribute";
                        break;

                    case "xml doc comment - attribute value":
                        name = "attribute value";
                        break;

                    case "xml doc comment - text":
                        break;

                    default:
                        if (name == "identifier" || name.StartsWith("xml doc comment - ", StringComparison.Ordinal))
                        {
                            continue;
                        }
                        break;
                    }

                    // As long as the opening and closing XML tags appear on the same line as the content, we
                    // can skip spell checking of unwanted elements.
                    if (name == "xml delimiter" || name == "xaml delimiter" || name == "vb xml doc tag" ||
                        name.StartsWith("vb xml delimiter", StringComparison.Ordinal))
                    {
                        text = classificationSpan.Span.GetText();

                        if (text.IndexOf('/') != -1)
                        {
                            elementName   = null;
                            delimiterSeen = false;
                        }
                        else
                        if (text.IndexOf('<') != -1)
                        {
                            delimiterSeen = true;
                        }

                        if (name == "vb xml doc tag" && delimiterSeen)
                        {
                            if (text.Length > 1 && text[0] == '<')
                            {
                                pos = text.IndexOf(' ');

                                if (pos != -1)
                                {
                                    elementName = text.Substring(1, pos - 1);
                                }
                                else
                                {
                                    elementName = text.Substring(1, text.Length - 2);
                                }
                            }

                            if (text.Length > 1 && text[text.Length - 1] == '=')
                            {
                                pos = text.IndexOf(' ');

                                if (pos != -1)
                                {
                                    attributeName = text.Substring(pos + 1, text.Length - pos - 2);
                                }
                                else
                                {
                                    attributeName = text.Substring(0, text.Length - 1);
                                }
                            }
                        }
                    }

                    if (delimiterSeen && (name == "xml name" || name == "xaml name" ||
                                          name.StartsWith("vb xml name", StringComparison.Ordinal)))
                    {
                        elementName = classificationSpan.Span.GetText().Trim();

                        // Ignore any namespace prefix
                        if (elementName.IndexOf(':') != -1)
                        {
                            elementName = elementName.Substring(elementName.IndexOf(':') + 1);
                        }
                    }

                    // As long as the attribute value appears on the same line as the attribute name, we can
                    // spell check attribute values if wanted.
                    if (name.EndsWith(" attribute", StringComparison.Ordinal) || name.Contains("attribute name"))
                    {
                        // XAML attribute names may include leading and trailing white space
                        attributeName = classificationSpan.Span.GetText().Trim();

                        // Ignore any namespace prefix
                        if (attributeName.IndexOf(':') != -1)
                        {
                            attributeName = attributeName.Substring(attributeName.IndexOf(':') + 1);
                        }
                    }

                    if ((name.Contains("comment") || name.Contains("string") || name.Contains("xml text") ||
                         name.Contains("xaml text") || name.Contains("attribute value")) &&
                        !name.Contains("xml doc tag"))
                    {
                        // If it's not a wanted attribute name, don't spell check its value
                        if (attributeName != null && name.Contains("attribute value") &&
                            !spellCheckedXmlAttributes.Contains(attributeName))
                        {
                            attributeName = null;
                            continue;
                        }

                        attributeName = null;

                        // If it's an unwanted element, don't spell check its XML text
                        if (elementName != null && !name.Contains("attribute value") && ignoredXmlElements.Contains(elementName))
                        {
                            continue;
                        }

                        // Include files in C/C++ are tagged as a string but we don't want to spell check them
                        if (preprocessorKeywordSeen && name == "string" &&
                            classificationSpan.Span.Snapshot.ContentType.IsOfType("C/C++"))
                        {
                            continue;
                        }

                        preprocessorKeywordSeen = false;

                        // Track and ignore classifications by original name to allow the user to be more
                        // selective if necessary.
                        classificationCache.Add(originalName);

                        if (ignoredClassifications.Contains(originalName))
                        {
                            continue;
                        }

                        yield return(new TagSpan <NaturalTextTag>(classificationSpan.Span, new NaturalTextTag()));
                    }
                    else
                    if (name == "preprocessor keyword")
                    {
                        preprocessorKeywordSeen = true;
                    }
                }
            }
        }
Example #3
0
        //=====================================================================

        /// <inheritdoc />
        public IEnumerable <ITagSpan <NaturalTextTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            List <SnapshotSpan> ignoredSpans = new List <SnapshotSpan>();
            string text;
            int    start, end;

            if (classifier == null || spans == null || spans.Count == 0)
            {
                yield break;
            }

            ITextSnapshot snapshot = spans[0].Snapshot;

            foreach (var snapshotSpan in spans)
            {
                Debug.Assert(snapshotSpan.Snapshot.TextBuffer == buffer);

                ignoredSpans.Clear();

                // The classifier for this one doesn't return natural language spans so we'll get those below.
                // First, get a list of stuff we can handle directly and/or ignore below.
                foreach (ClassificationSpan classificationSpan in classifier.GetClassificationSpans(snapshotSpan))
                {
                    string name = classificationSpan.ClassificationType.Classification.ToLowerInvariant();

                    switch (name)
                    {
                    case "markdown monospace":          // Typically code keywords, etc.
                    case "keyword":                     // RDoc stuff
                    case "number":
                    case "punctuation":
                    case "rd braces":
                        ignoredSpans.Add(classificationSpan.Span);
                        break;

                    case "markdown italic text":
                        // Italics may be denoted with underscores so we'll need to trim them off of the
                        // span or it will not spell check the text if the "treat underscore as separator"
                        // option is turned off.
                        text  = classificationSpan.Span.GetText();
                        start = 0;

                        while (start < text.Length && text[start] == '_')
                        {
                            start++;
                        }

                        end = text.Length - 1;

                        while (end > start && text[end] == '_')
                        {
                            end--;
                        }

                        end++;

                        if (end - start > 1)
                        {
                            SnapshotSpan s = new SnapshotSpan(classificationSpan.Span.Start + start, end - start);
                            ignoredSpans.Add(s);

                            classificationCache.Add(name);

                            if (!ignoredClassifications.Contains(name))
                            {
                                yield return(new TagSpan <NaturalTextTag>(s, new NaturalTextTag()));
                            }
                        }
                        break;

                    default:
                        classificationCache.Add(name);

                        if (ignoredClassifications.Contains(name))
                        {
                            ignoredSpans.Add(classificationSpan.Span);
                        }
                        break;
                    }
                }

                // Now return the spans we didn't ignore or handle above
                start = snapshotSpan.Start;

                foreach (var ignored in ignoredSpans.OrderBy(s => s.Start))
                {
                    if (ignored.Start > start)
                    {
                        yield return(new TagSpan <NaturalTextTag>(new SnapshotSpan(snapshotSpan.Snapshot, start,
                                                                                   ignored.Start.Position - start), new NaturalTextTag()));
                    }

                    start = ignored.Start + ignored.Length;
                }

                if (start < snapshotSpan.End)
                {
                    yield return(new TagSpan <NaturalTextTag>(new SnapshotSpan(snapshotSpan.Snapshot, start,
                                                                               snapshotSpan.End.Position - start), new NaturalTextTag()));
                }
            }
        }