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(); } } } }
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); }
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) )); } }
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); }
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); }
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 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); }
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> >()); }
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>()) ); } }