Exemple #1
0
            public void OnCharTyped(char @char)
            {
                // format on ':'
                if (@char == RobotsTxtSyntaxFacts.NameValueDelimiter)
                {
                    ITextBuffer buffer = _textView.TextBuffer;

                    SyntaxTree syntaxTree        = buffer.GetSyntaxTree();
                    RobotsTxtDocumentSyntax root = syntaxTree.Root as RobotsTxtDocumentSyntax;

                    // find in syntax tree
                    var caret = _textView.Caret.Position.BufferPosition;
                    RobotsTxtLineSyntax lineSyntax = root.Records
                                                     .SelectMany(r => r.Lines)
                                                     .FirstOrDefault(p => p.DelimiterToken.Span.Span.End == caret);

                    if (lineSyntax != null)
                    {
                        using (ITextUndoTransaction transaction = _undoHistory.CreateTransaction("Automatic Formatting"))
                        {
                            using (ITextEdit edit = buffer.CreateEdit())
                            {
                                // fix indent
                                // find property before
                                RobotsTxtLineSyntax before = lineSyntax.Record.Lines
                                                             .TakeWhile(p => p != lineSyntax)
                                                             .LastOrDefault();

                                // reference point
                                if (before != null)
                                {
                                    SnapshotPoint referencePoint = before.NameToken.Span.Span.Start;

                                    // compare
                                    ITextSnapshotLine referenceLine = referencePoint.GetContainingLine();
                                    ITextSnapshotLine line          = lineSyntax.DelimiterToken.Span.Span.End.GetContainingLine();

                                    SnapshotSpan referenceIndent = new SnapshotSpan(referenceLine.Start, referencePoint);
                                    SnapshotSpan indent          = new SnapshotSpan(line.Start, lineSyntax.NameToken.Span.Span.Start);

                                    if (indent.GetText() != referenceIndent.GetText())
                                    {
                                        edit.Replace(indent, referenceIndent.GetText());
                                    }
                                }

                                // remove white space before ':'
                                if (lineSyntax.NameToken.Span.Span.End != lineSyntax.DelimiterToken.Span.Span.Start)
                                {
                                    edit.Delete(new SnapshotSpan(lineSyntax.NameToken.Span.Span.End, lineSyntax.DelimiterToken.Span.Span.Start));
                                }

                                edit.Apply();
                            }

                            transaction.Complete();
                        }
                    }
                }
            }
Exemple #2
0
        private ITextEdit FixByMoving(RobotsTxtLineSyntax line, RobotsTxtRecordSyntax record)
        {
            ITextBuffer buffer = line.Record.Document.Snapshot.TextBuffer;

            // default insertion point at record start
            SnapshotPoint insertionPoint = record.Span.Start;

            // find last User-agent line
            var last = record.Lines
                       .TakeWhile(l => l.NameToken.Value.Equals("User-agent", StringComparison.InvariantCultureIgnoreCase))
                       .LastOrDefault();

            if (last != null) // override insertion point
            {
                insertionPoint = last.Span.End.GetContainingLine().EndIncludingLineBreak;
            }

            // move line up
            ITextEdit edit = buffer.CreateEdit();

            edit.Insert(
                insertionPoint,
                line.Span.Start.GetContainingLine().GetTextIncludingLineBreak()
                );
            edit.Delete(line.Span.Start.GetContainingLine().ExtentIncludingLineBreak);

            return(edit);
        }
Exemple #3
0
            public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList <ISignature> signatures)
            {
                ITextSnapshot snapshot = _textBuffer.CurrentSnapshot;

                // trigger point
                SnapshotPoint?point = session.GetTriggerPoint(snapshot);

                if (point == null)
                {
                    return;
                }

                // get syntax tree
                SyntaxTree syntaxTree = snapshot.GetSyntaxTree();
                var        root       = syntaxTree.Root as RobotsTxtDocumentSyntax;

                // find line in syntax tree
                ITextSnapshotLine   line       = point.Value.GetContainingLine();
                RobotsTxtLineSyntax lineSyntax = root.Records.SelectMany(r => r.Lines)
                                                 .Where(l => !l.NameToken.IsMissing && !l.DelimiterToken.IsMissing)
                                                 .FirstOrDefault(l => l.Span.IntersectsWith(line.Extent));

                // found
                if (lineSyntax != null)
                {
                    if (lineSyntax.DelimiterToken.Span.Span.End <= point.Value)
                    {
                        // get semantic model
                        ISemanticModel model = syntaxTree.GetSemanticModel();

                        // add signature
                        signatures.Add(new RobotsTxtSignature(model, lineSyntax));
                    }
                }
            }
        private ITextEdit Fix(RobotsTxtLineSyntax line)
        {
            ITextBuffer buffer = line.Record.Document.Snapshot.TextBuffer;

            string value = line.ValueToken.Value;

            // fix
            string newValue = value;

            // example: * -> /
            if (value == "*")
            {
                newValue = "/";
            }

            // example: /folder/* -> /folder/
            else if (value.EndsWith("/*"))
            {
                newValue = value.Remove(value.Length - 1);
            }

            ITextEdit edit = buffer.CreateEdit();

            edit.Replace(
                line.ValueToken.Span.Span,
                newValue
                );

            return(edit);
        }
        public IEnumerable <CodeAction> GetFixes(SnapshotSpan span)
        {
            ITextBuffer             buffer = span.Snapshot.TextBuffer;
            SyntaxTree              syntax = buffer.GetSyntaxTree();
            RobotsTxtDocumentSyntax root   = syntax.Root as RobotsTxtDocumentSyntax;

            // find declaration
            RobotsTxtLineSyntax line = root.Records
                                       .SelectMany(r => r.Lines)
                                       .First(s => s.ValueToken.Span.Span == span);

            string value = line.ValueToken.Value;

            // TODO: Fix multiple occurrences
            if (value.Count(c => c == '*') != 1)
            {
                yield break;
            }

            if (value == "*" || value.EndsWith("/*"))
            {
                yield return(new CodeAction(
                                 $"Change '*' to directory root",
                                 () => Fix(line)
                                 ));
            }
        }
Exemple #6
0
        private ITextEdit Fix(RobotsTxtLineSyntax line)
        {
            ITextBuffer buffer = line.Record.Document.Snapshot.TextBuffer;

            ITextEdit edit = buffer.CreateEdit();

            edit.Insert(line.NameToken.Span.Span.End, RobotsTxtSyntaxFacts.NameValueDelimiter.ToString());

            return(edit);
        }
            public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent, out ITrackingSpan applicableToSpan)
            {
                ITextSnapshot  snapshot     = _buffer.CurrentSnapshot;
                ITrackingPoint triggerPoint = session.GetTriggerPoint(_buffer);
                SnapshotPoint  point        = triggerPoint.GetPoint(snapshot);

                SyntaxTree syntax            = snapshot.GetSyntaxTree();
                RobotsTxtDocumentSyntax root = syntax.Root as RobotsTxtDocumentSyntax;

                applicableToSpan = null;

                // find section
                RobotsTxtLineSyntax line = root.Records
                                           .SelectMany(r => r.Lines)
                                           .FirstOrDefault(s => s.NameToken.Span.Span.Contains(point));

                if (line != null)
                {
                    IClassificationFormatMap formatMap = _classificationFormatMapService.GetClassificationFormatMap(session.TextView);

                    string fieldName = line.NameToken.Value;

                    // get glyph
                    var glyph = _glyphService.GetGlyph(StandardGlyphGroup.GlyphGroupProperty, StandardGlyphItem.GlyphItemPublic);
                    var classificationType = _classificationRegistry.GetClassificationType("RobotsTxt/RecordName");
                    var format             = formatMap.GetTextProperties(classificationType);

                    // construct content
                    ISemanticModel model = syntax.GetSemanticModel();
                    var            field = model.GetFieldSymbol(line);

                    var content = new QuickInfoContent
                    {
                        Glyph     = glyph,
                        Signature = new Run(field.Name)
                        {
                            Foreground = format.ForegroundBrush
                        },
                        Documentation = RobotsTxtDocumentation.GetDocumentation(field),
                    };

                    // add to session
                    quickInfoContent.Add(
                        new ContentPresenter
                    {
                        Content         = content,
                        ContentTemplate = Template,
                    }
                        );
                    applicableToSpan = snapshot.CreateTrackingSpan(line.NameToken.Span.Span, SpanTrackingMode.EdgeInclusive);
                    return;
                }
            }
        private ITextEdit Fix(RobotsTxtLineSyntax line)
        {
            ITextBuffer buffer = line.Record.Document.Snapshot.TextBuffer;

            ITextSnapshotLine textLine = line.Span.Start.GetContainingLine();

            ITextEdit edit = buffer.CreateEdit();

            edit.Delete(textLine.ExtentIncludingLineBreak);

            return(edit);
        }
Exemple #9
0
        private ITextEdit FixBySeparation(RobotsTxtLineSyntax line)
        {
            ITextBuffer buffer = line.Record.Document.Snapshot.TextBuffer;

            ITextEdit edit = buffer.CreateEdit();

            edit.Insert(
                line.Span.Start.GetContainingLine().Start,
                Environment.NewLine
                );

            return(edit);
        }
Exemple #10
0
        public IEnumerable <CodeAction> GetFixes(SnapshotSpan span)
        {
            ITextBuffer             buffer = span.Snapshot.TextBuffer;
            SyntaxTree              syntax = buffer.GetSyntaxTree();
            RobotsTxtDocumentSyntax root   = syntax.Root as RobotsTxtDocumentSyntax;

            // find declaration
            RobotsTxtLineSyntax line = root.Records
                                       .SelectMany(r => r.Lines)
                                       .First(s => s.Span.IntersectsWith(span));

            yield return(new CodeAction(
                             $"Fix syntax error: Insert missing ':'",
                             () => Fix(line)
                             ));
        }
Exemple #11
0
                public RobotsTxtSignature(ISemanticModel model, RobotsTxtLineSyntax lineSyntax)
                {
                    RobotsTxtFieldSymbol field = model.GetFieldSymbol(lineSyntax);

                    // calculate span
                    ITextSnapshotLine line = lineSyntax.Span.Start.GetContainingLine();

                    this.ApplicableToSpan = lineSyntax.Record.Document.Snapshot.CreateTrackingSpan(
                        new SnapshotSpan(
                            lineSyntax.NameToken.Span.Span.Start,
                            lineSyntax.TrailingTrivia.FirstOrDefault(t => t.Span.Span.IntersectsWith(line.Extent))?.Span.Span.Start ?? line.Extent.End
                            ),
                        SpanTrackingMode.EdgeInclusive
                        );

                    // content
                    string content = $"{field.Name}: {ParameterName}";

                    if (field.IsExtension)
                    {
                        content = $"(extension) {content}";
                    }

                    this.Content = content;

                    // parameters
                    this.Parameters = new ReadOnlyCollection <IParameter>(
                        new []
                    {
                        new RobotsTxtParameter(null, new Span(this.Content.LastIndexOf(ParameterName), ParameterName.Length), ParameterName, this)
                    }
                        );
                    this.CurrentParameter = this.Parameters.Single();

                    // documentation
                    this.Documentation = RobotsTxtDocumentation.GetDocumentation(field);
                }
Exemple #12
0
        public IEnumerable <CodeAction> GetFixes(SnapshotSpan span)
        {
            ITextBuffer             buffer = span.Snapshot.TextBuffer;
            SyntaxTree              syntax = buffer.GetSyntaxTree();
            RobotsTxtDocumentSyntax root   = syntax.Root as RobotsTxtDocumentSyntax;

            // find section
            RobotsTxtRecordSyntax record = root.Records
                                           .First(s => s.Span.IntersectsWith(span));

            // find first declaration
            RobotsTxtLineSyntax line = record.Lines
                                       .First(s => s.NameToken.Span.Span == span);

            yield return(new CodeAction(
                             $"Separate records by a blank line",
                             () => FixBySeparation(line)
                             ));

            yield return(new CodeAction(
                             $"Move line to the top of the record",
                             () => FixByMoving(line, record)
                             ));
        }
Exemple #13
0
            public IEnumerable <ITagSpan <ITextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans)
            {
                ITextBuffer buffer = spans.First().Snapshot.TextBuffer;

                // get syntax
                SyntaxTree syntax            = buffer.GetSyntaxTree();
                RobotsTxtDocumentSyntax root = syntax.Root as RobotsTxtDocumentSyntax;

                // get semantics
                ISemanticModel model = syntax.GetSemanticModel();

                SnapshotPoint caret = _view.Caret.Position.BufferPosition;

                // find line
                RobotsTxtLineSyntax line = root.Records
                                           .SelectMany(r => r.Lines)
                                           .FirstOrDefault(s => s.NameToken.Span.Span.ContainsOrEndsWith(caret));

                // show references
                if (line != null)
                {
                    ISymbol field = model.GetFieldSymbol(line);

                    // find references
                    return
                        (from r in root.Records
                         from l in r.Lines
                         where !l.NameToken.IsMissing
                         let f = model.GetFieldSymbol(l)
                                 where f.Equals(field)
                                 select new TagSpan <ITextMarkerTag>(l.NameToken.Span.Span, Tag)
                        );
                }

                return(Enumerable.Empty <TagSpan <ITextMarkerTag> >());
            }
Exemple #14
0
 public static RobotsTxtFieldSymbol GetFieldSymbol(this ISemanticModel model, RobotsTxtLineSyntax line)
 {
     return(new RobotsTxtFieldSymbol(line.NameToken.Value));
 }
            public void AugmentCompletionSession(ICompletionSession session, IList <CompletionSet> completionSets)
            {
                if (_disposed)
                {
                    return;
                }

                // get snapshot
                ITextSnapshot snapshot     = _buffer.CurrentSnapshot;
                var           triggerPoint = session.GetTriggerPoint(snapshot);

                if (triggerPoint == null)
                {
                    return;
                }

                // get or compute syntax tree
                SyntaxTree syntaxTree        = snapshot.GetSyntaxTree();
                RobotsTxtDocumentSyntax root = syntaxTree.Root as RobotsTxtDocumentSyntax;

                // find line
                var lineSyntax = root.Records
                                 .SelectMany(r => r.Lines)
                                 .FirstOrDefault(l => l.Span.ContainsOrEndsWith(triggerPoint.Value));

                if (lineSyntax != null)
                {
                    // complete existing field
                    if (lineSyntax.NameToken.Span.Span.ContainsOrEndsWith(triggerPoint.Value))
                    {
                        IList <Completion> completions = new List <Completion>();

                        // applicable to
                        ITrackingSpan applicableTo = snapshot.CreateTrackingSpan(lineSyntax.NameToken.Span.Span, SpanTrackingMode.EdgeInclusive);

                        // find lines before
                        var before = lineSyntax.Record.Lines
                                     .TakeWhile(l => l != lineSyntax)
                                     .ToList();

                        // compute completions
                        AugmentCompletionsBasedOnLinesBefore(before, completions);

                        completionSets.Add(
                            new CompletionSet("All", "All", applicableTo, completions, Enumerable.Empty <Completion>())
                            );
                    }
                }

                // blank line
                else
                {
                    ITextSnapshotLine line = triggerPoint.Value.GetContainingLine();

                    // check whether the trigger point is in comment
                    int commentIndex = line.GetText().IndexOf(RobotsTxtSyntaxFacts.Comment);
                    if (commentIndex != -1)
                    {
                        if (commentIndex < (triggerPoint.Value - line.Start))
                        {
                            return;
                        }
                    }

                    IList <Completion> completions = new List <Completion>();

                    // find last line before
                    RobotsTxtLineSyntax lineBefore = root.Records
                                                     .SelectMany(r => r.Lines)
                                                     .TakeWhile(l => l.Span.End < triggerPoint.Value)
                                                     .LastOrDefault();

                    // no line before
                    if (lineBefore == null)
                    {
                        completions.Add(ToCompletion("User-agent"));
                    }

                    // there is a line before
                    else
                    {
                        // same record
                        if (lineBefore.Span.Start.GetContainingLine().LineNumber ==
                            triggerPoint.Value.GetContainingLine().LineNumber - 1)
                        {
                            // find lines before
                            var before = lineBefore.Record.Lines
                                         .TakeWhile(l => l != lineSyntax)
                                         .ToList();

                            // compute completions
                            AugmentCompletionsBasedOnLinesBefore(before, completions);
                        }

                        // new record
                        else
                        {
                            completions.Add(ToCompletion("User-agent"));
                        }
                    }

                    var applicableTo = snapshot.CreateTrackingSpan(new SnapshotSpan(triggerPoint.Value, triggerPoint.Value), SpanTrackingMode.EdgeInclusive);

                    completionSets.Add(
                        new CompletionSet("All", "All", applicableTo, completions, Enumerable.Empty <Completion>())
                        );
                }
            }