/////////////////////////////////////////////////////////////////////////////////////////////////////
        // NON-PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Rescan the document and look for instances of the word 'Actipro' to mark with squiggle tags.
        /// </summary>
        private void RefreshSquiggleTags()
        {
            // Get the tagger that was created by the language and has been persisted in the document's properties
            //   while the language is active on the document
            CustomSquiggleTagger tagger = null;

            if (editor.Document.Properties.TryGetValue(typeof(CustomSquiggleTagger), out tagger))
            {
                using (var batch = tagger.CreateBatch()) {
                    // Clear existing tags
                    tagger.Clear();

                    // In this example we are going to construct the full snapshot text string... this is not generally a good
                    //   idea for a production application since doing so for a large document in the UI thread can negatively affect performance...
                    //   But this example shows how any text range results (such as those from an external error scan) can be used to generate squiggle tags
                    var snapshot     = editor.ActiveView.CurrentSnapshot;
                    var snapshotText = snapshot.GetText(LineTerminator.Newline);

                    // Look for regex pattern matches
                    var matches = Regex.Matches(snapshotText, @"\bActipro\b", RegexOptions.IgnoreCase);
                    for (var matchIndex = 0; matchIndex < matches.Count; matchIndex++)
                    {
                        var match = matches[matchIndex];

                        // Create a version range for the match
                        var snapshotRange = new TextSnapshotRange(snapshot, TextRange.FromSpan(match.Index, match.Length));
                        var versionRange  = snapshotRange.ToVersionRange(TextRangeTrackingModes.DeleteWhenZeroLength);

                        // Create a tag, and include a quick info tip if specified
                        var tag = new SquiggleTag();
                        tag.ClassificationType = ClassificationTypes.Warning;                          // This classification type is mapped in the tagger to a Green color
                        tag.ContentProvider    = new PlainTextContentProvider(String.Format("Instance number {0}", matchIndex + 1));

                        // Add the tag to the tagger
                        tagger.Add(new TagVersionRange <ISquiggleTag>(versionRange, tag));
                    }
                }
            }
        }
Exemple #2
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Returns the tag ranges that intersect with the specified normalized snapshot ranges.
        /// </summary>
        /// <param name="snapshotRanges">The collection of normalized snapshot ranges.</param>
        /// <param name="parameter">An optional parameter that provides contextual information about the tag request.</param>
        /// <returns>The tag ranges that intersect with the specified normalized snapshot ranges.</returns>
        public override IEnumerable <TagSnapshotRange <IClassificationTag> > GetTags(NormalizedTextSnapshotRangeCollection snapshotRanges, object parameter)
        {
            // Loop through the requested snapshot ranges...
            foreach (TextSnapshotRange snapshotRange in snapshotRanges)
            {
                // If the snapshot range is not zero-length...
                if (!snapshotRange.IsZeroLength)
                {
                    IEnumerable <TagSnapshotRange <ITokenTag> > tokenTagRanges = tokenTagAggregator.GetTags(snapshotRange);
                    if (tokenTagRanges != null)
                    {
                        foreach (TagSnapshotRange <ITokenTag> tokenTagRange in tokenTagRanges)
                        {
                            if (tokenTagRange.Tag.Token != null)
                            {
                                switch (tokenTagRange.Tag.Token.Key)
                                {
                                case "XmlCommentText": {
                                    if (highlightDocumentationComments)
                                    {
                                        // Get the text of the token
                                        string text = tokenTagRange.SnapshotRange.Text;

                                        // Look for the text "Actipro"
                                        int index = text.IndexOf("Actipro");
                                        while (index != -1)
                                        {
                                            // Add a highlighted range
                                            yield return(new TagSnapshotRange <IClassificationTag>(
                                                             new TextSnapshotRange(snapshotRange.Snapshot, TextRange.FromSpan(tokenTagRange.SnapshotRange.StartOffset + index, 7)),
                                                             new ClassificationTag(ClassificationTypes.SyntaxError)
                                                             ));

                                            // Look for another match
                                            index = text.IndexOf("Actipro", index + 7);
                                        }
                                    }
                                    break;
                                }

                                case "Identifier": {
                                    if (highlightIdentifiers)
                                    {
                                        // Get the text of the token
                                        string text = tokenTagRange.SnapshotRange.Text;

                                        // If the text is "Actipro"...
                                        if (text == "Actipro")
                                        {
                                            // Add a highlighted range
                                            yield return(new TagSnapshotRange <IClassificationTag>(
                                                             new TextSnapshotRange(snapshotRange.Snapshot, tokenTagRange.SnapshotRange.TextRange),
                                                             new ClassificationTag(ClassificationTypes.SyntaxError)
                                                             ));
                                        }
                                    }
                                    break;
                                }
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #3
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Performs a parsing operation using the parameters specified in the supplied <see cref="IParseRequest"/>
        /// and returns the resulting parse data.
        /// </summary>
        /// <param name="request">The <see cref="IParseRequest"/> that contains data about the requested parsing operation.</param>
        /// <returns>An <see cref="IParseData"/> that is the result of the parsing operation.</returns>
        /// <remarks>
        /// A <see cref="IParseRequestDispatcher"/> typically calls this method when a queued parse request is ready to be processed.
        /// </remarks>
        public override IParseData Parse(IParseRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // Create parse data
            ParentParseData parseData = new ParentParseData();

            parseData.Snapshot = request.Snapshot;

            // Initialize generated text
            StringBuilder generatedText = new StringBuilder();

            generatedText.Append("using System;\n");
            generatedText.Append("using System.Collections.Generic;\n\n");
            generatedText.Append("using System.Linq;\n\n");
            generatedText.Append("[EditorBrowsable(EditorBrowsableState.Never)]\n");
            generatedText.Append("class __Generated {\n");
            generatedText.Append("\t[EditorBrowsable(EditorBrowsableState.Never)]\n");
            generatedText.Append("\tvoid __WriteOutput() {\n");

            ITextSnapshotReader sourceReader = request.Snapshot.GetReader(0);
            int  lastDelimiterOffset         = 0;
            bool lastDelimiterWasStart       = false;

            while (!sourceReader.IsAtSnapshotEnd)
            {
                IToken token = sourceReader.ReadToken();
                if (token != null)
                {
                    switch (token.Id)
                    {
                    case ParentTokenId.ChildCodeBlockStart:
                    case ParentTokenId.ChildOutputBlockStart:
                        if (token.StartOffset - lastDelimiterOffset > 0)
                        {
                            // Append generated text
                            string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, token.StartOffset), LineTerminator.Newline);
                            generatedText.Append("\t\tResponse.Write(@\"");
                            generatedText.Append(text.Replace("\"", "\"\""));
                            generatedText.Append("\");\n");
                        }

                        // Store the last delimiter offset
                        lastDelimiterOffset   = token.EndOffset;
                        lastDelimiterWasStart = true;
                        break;

                    case ParentTokenId.ChildCodeBlockEnd:
                        if ((lastDelimiterWasStart) && (token.StartOffset - lastDelimiterOffset > 0))
                        {
                            // Get the text between the delimiters
                            string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, token.StartOffset), LineTerminator.Newline);
                            generatedText.Append("\t\t");

                            // Add a mapping
                            parseData.TextRangeMappings.Add(Tuple.Create(new TextRange(lastDelimiterOffset, token.StartOffset), TextRange.FromSpan(generatedText.Length, text.Length)));

                            // Append the text directly
                            generatedText.Append(text);
                            generatedText.Append("\n");
                        }

                        // Store the last delimiter offset
                        lastDelimiterOffset   = token.EndOffset;
                        lastDelimiterWasStart = false;
                        break;

                    case ParentTokenId.ChildOutputBlockEnd:
                        if ((lastDelimiterWasStart) && (token.StartOffset - lastDelimiterOffset > 0))
                        {
                            // Get the text between the delimiters and append a Response.Write
                            string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, token.StartOffset), LineTerminator.Newline);
                            generatedText.Append("\t\tResponse.Write(");

                            // Add a mapping
                            parseData.TextRangeMappings.Add(Tuple.Create(new TextRange(lastDelimiterOffset, token.StartOffset), TextRange.FromSpan(generatedText.Length, text.Length)));

                            // Append the text directly
                            generatedText.Append(text);
                            generatedText.Append(");\n");
                        }

                        // Store the last delimiter offset
                        lastDelimiterOffset   = token.EndOffset;
                        lastDelimiterWasStart = false;
                        break;
                    }
                }
            }

            if (lastDelimiterOffset < sourceReader.Snapshot.Length)
            {
                // Append generated text
                string text = sourceReader.Snapshot.GetSubstring(new TextRange(lastDelimiterOffset, sourceReader.Snapshot.Length), LineTerminator.Newline);
                generatedText.Append("\t\tResponse.Write(@\"");
                generatedText.Append(text.Replace("\"", "\"\""));
                generatedText.Append("\");\n");
            }

            // Store the generated text
            generatedText.Append("\t}\n");
            generatedText.Append("}\n");

            // Get parse data for the translated code
            CodeDocument generatedDocument = new CodeDocument();

            generatedDocument.Language = childLanguage;
            generatedDocument.SetText(generatedText.ToString());

            // Get a reader
            ITextBufferReader generatedReader = generatedDocument.CurrentSnapshot.GetReader(0).BufferReader;

            // Create a request
            ParseRequest generatedRequest = new ParseRequest(Guid.NewGuid().ToString(), generatedReader, childParser, generatedDocument);

            generatedRequest.Snapshot = generatedDocument.CurrentSnapshot;

            // Parse
            generatedDocument.ParseData  = childParser.Parse(generatedRequest);
            parseData.GeneratedParseData = generatedDocument.ParseData as ILLParseData;

            return(parseData);
        }
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Returns the tag ranges that intersect with the specified normalized snapshot ranges.
        /// </summary>
        /// <param name="snapshotRanges">The collection of normalized snapshot ranges.</param>
        /// <param name="parameter">An optional parameter that provides contextual information about the tag request.</param>
        /// <returns>The tag ranges that intersect with the specified normalized snapshot ranges.</returns>
        public override IEnumerable <TagSnapshotRange <IClassificationTag> > GetTags(NormalizedTextSnapshotRangeCollection snapshotRanges, object parameter)
        {
            // Get a regex of the current word
            var search = new Regex(Regex.Escape(HighlightedString), RegexOptions.Singleline | RegexOptions.IgnoreCase);

            // Loop through the requested snapshot ranges...
            foreach (TextSnapshotRange snapshotRange in snapshotRanges)
            {
                // If the snapshot range is not zero-length...
                if (!snapshotRange.IsZeroLength)
                {
                    // Look for current word matches
                    foreach (Match match in search.Matches(snapshotRange.Text))
                    {
                        // Add a highlighted range
                        yield return(new TagSnapshotRange <IClassificationTag>(
                                         new TextSnapshotRange(snapshotRange.Snapshot, TextRange.FromSpan(snapshotRange.StartOffset + match.Index, match.Length)),
                                         new ClassificationTag(wordHighlightClassificationType)
                                         ));
                    }
                }
            }
        }