public IEnumerable <ITagSpan <IOutliningRegionTag> > GetTags(NormalizedSnapshotSpanCollection spans) { ITextBuffer buffer = spans.First().Snapshot.TextBuffer; SyntaxTree syntax = buffer.GetSyntaxTree(); RobotsTxtDocumentSyntax root = syntax.Root as RobotsTxtDocumentSyntax; return (from record in root.Records where record.Lines.Count() >= 2 where spans.IntersectsWith(record.Span) let first = record.Lines.First() where first.NameToken.Value.Equals("User-agent", StringComparison.InvariantCultureIgnoreCase) let last = record.Lines.Last() let collapsibleSpan = new SnapshotSpan( first.Span.End, (last.TrailingTrivia.LastOrDefault() ?? last.ValueToken).Span.Span.End ) select new TagSpan <IOutliningRegionTag>( collapsibleSpan, new OutliningRegionTag( collapsedForm: "...", collapsedHintForm: collapsibleSpan.GetText().Trim() ) ) ); }
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(); } } } }
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) )); } }
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; } }
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) )); }
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) )); }
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> >()); }
private void OnBufferChanged(object sender, TextContentChangedEventArgs e) { if (e.After != _buffer.CurrentSnapshot) { return; } SnapshotSpan?changedSpan = null; // examine old version SyntaxTree oldSyntaxTree = e.Before.GetSyntaxTree(); RobotsTxtDocumentSyntax oldRoot = oldSyntaxTree.Root as RobotsTxtDocumentSyntax; // find affected sections IReadOnlyCollection <RobotsTxtRecordSyntax> oldChangedRecords = ( from change in e.Changes from record in oldRoot.Records where record.Span.IntersectsWith(change.OldSpan) orderby record.Span.Start select record ).ToList(); if (oldChangedRecords.Any()) { // compute changed span changedSpan = new SnapshotSpan( oldChangedRecords.First().Span.Start, oldChangedRecords.Last().Span.End ); // translate to new version changedSpan = changedSpan.Value.TranslateTo(e.After, SpanTrackingMode.EdgeInclusive); } // examine current version SyntaxTree syntaxTree = e.After.GetSyntaxTree(); RobotsTxtDocumentSyntax root = syntaxTree.Root as RobotsTxtDocumentSyntax; // find affected sections IReadOnlyCollection <RobotsTxtRecordSyntax> changedRecords = ( from change in e.Changes from record in root.Records where record.Span.IntersectsWith(change.NewSpan) orderby record.Span.Start select record ).ToList(); if (changedRecords.Any()) { // compute changed span SnapshotSpan newChangedSpan = new SnapshotSpan( changedRecords.First().Span.Start, changedRecords.Last().Span.End ); changedSpan = changedSpan == null ? newChangedSpan : new SnapshotSpan( changedSpan.Value.Start <newChangedSpan.Start?changedSpan.Value.Start : newChangedSpan.Start, changedSpan.Value.End> newChangedSpan.End ? changedSpan.Value.End : newChangedSpan.End ) ; } // notify if any change affects outlining if (changedSpan != null) { this.TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(changedSpan.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>()) ); } }