public async Task Handle_FilterDiagnostics_CSharpWarning() { // Arrange var documentPath = "C:/path/to/document.cshtml"; var codeDocument = CreateCodeDocumentWithCSharpProjection( "<p>@DateTime.Now</p>", "var __o = DateTime.Now", new[] { new SourceMapping( new SourceSpan(4, 12), new SourceSpan(10, 12)) }); var documentResolver = CreateDocumentResolver(documentPath, codeDocument); var diagnosticsEndpoint = new RazorDiagnosticsEndpoint(Dispatcher, documentResolver, DocumentVersionCache, MappingService, LoggerFactory); var request = new RazorDiagnosticsParams() { Kind = RazorLanguageKind.CSharp, Diagnostics = new[] { new Diagnostic() { Range = new Range(new Position(0, 10), new Position(0, 22)), Code = RazorDiagnosticsEndpoint.DiagnosticsToIgnore.First(), Severity = DiagnosticSeverity.Warning } }, RazorDocumentUri = new Uri(documentPath), }; var expectedRange = new Range(new Position(0, 4), new Position(0, 16)); // Act var response = await Task.Run(() => diagnosticsEndpoint.Handle(request, default)); // Assert Assert.Empty(response.Diagnostics); Assert.Equal(1337, response.HostDocumentVersion); }
/// <summary> /// Get comment completions. /// </summary> /// <param name="replaceRange"> /// The range of text to be replaced by the completions. /// </param> /// <returns> /// A sequence of <see cref="CompletionItem"/>s. /// </returns> public IEnumerable <CompletionItem> GetCompletionItems(Range replaceRange) { if (replaceRange == null) { throw new ArgumentNullException(nameof(replaceRange)); } LspModels.Range completionRange = replaceRange.ToLsp(); // <!-- --> yield return(new CompletionItem { Label = "<!-- -->", Detail = "Comment", Documentation = "XML comment", SortText = Priority + "<!-- -->", TextEdit = new TextEdit { NewText = "<!-- $0 -->", Range = completionRange }, InsertTextFormat = InsertTextFormat.Snippet }); }
public override bool TryMapToProjectedDocumentRange(RazorCodeDocument codeDocument, Range originalRange, out Range projectedRange) { if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (originalRange is null) { throw new ArgumentNullException(nameof(originalRange)); } projectedRange = default; if ((originalRange.End.Line < originalRange.Start.Line) || (originalRange.End.Line == originalRange.Start.Line && originalRange.End.Character < originalRange.Start.Character)) { Debug.Fail($"DefaultRazorDocumentMappingService:TryMapToProjectedDocumentRange original range end < start '{originalRange}'"); return(false); } var sourceText = codeDocument.GetSourceText(); var range = originalRange; var startIndex = range.Start.GetAbsoluteIndex(sourceText); if (!TryMapToProjectedDocumentPosition(codeDocument, startIndex, out var projectedStart, out var _)) { return(false); } var endIndex = range.End.GetAbsoluteIndex(sourceText); if (!TryMapToProjectedDocumentPosition(codeDocument, endIndex, out var projectedEnd, out var _)) { return(false); } // Ensures a valid range is returned. // As we're doing two seperate TryMapToProjectedDocumentPosition calls, // it's possible the projectedStart and projectedEnd positions are in completely // different places in the document, including the possibility that the // projectedEnd position occurs before the projectedStart position. // We explicitly disallow such ranges where the end < start. if ((projectedEnd.Line < projectedStart.Line) || (projectedEnd.Line == projectedStart.Line && projectedEnd.Character < projectedStart.Character)) { return(false); } projectedRange = new Range( projectedStart, projectedEnd); return(true); }
private bool TryMapFromProjectedDocumentRangeStrict(RazorCodeDocument codeDocument, Range projectedRange, out Range originalRange) { originalRange = default; var csharpSourceText = SourceText.From(codeDocument.GetCSharpDocument().GeneratedCode); var range = projectedRange; var startIndex = range.Start.GetAbsoluteIndex(csharpSourceText); if (!TryMapFromProjectedDocumentPosition(codeDocument, startIndex, out var hostDocumentStart, out _)) { return(false); } var endIndex = range.End.GetAbsoluteIndex(csharpSourceText); if (!TryMapFromProjectedDocumentPosition(codeDocument, endIndex, out var hostDocumentEnd, out _)) { return(false); } originalRange = new Range( hostDocumentStart, hostDocumentEnd); return(true); }
public override bool TryMapFromProjectedDocumentRange(RazorCodeDocument codeDocument, Range projectedRange, out Range originalRange) => TryMapFromProjectedDocumentRange(codeDocument, projectedRange, MappingBehavior.Strict, out originalRange);
private string AssertSemanticTokens(string txt, IEnumerable <int> expectedData, bool isRazor, out RazorSemanticTokensInfoService outService, RazorSemanticTokensInfoService service = null, OmniSharpRange location = null) { // Arrange if (service is null) { service = GetDefaultRazorSemanticTokenInfoService(); } outService = service; RazorCodeDocument codeDocument; if (isRazor) { codeDocument = CreateRazorDocument(txt, DefaultTagHelpers); } else { codeDocument = CreateCodeDocument(txt, DefaultTagHelpers); } // Act var tokens = service.GetSemanticTokens(codeDocument, location); // Assert Assert.Equal(expectedData, tokens.Data); return(tokens.ResultId); }
public override bool TryMapFromProjectedDocumentRange(RazorCodeDocument codeDocument, Range projectedRange, out Range originalRange) { if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (projectedRange is null) { throw new ArgumentNullException(nameof(projectedRange)); } originalRange = default; var csharpSourceText = SourceText.From(codeDocument.GetCSharpDocument().GeneratedCode); var range = projectedRange; var startIndex = range.Start.GetAbsoluteIndex(csharpSourceText); if (!TryMapFromProjectedDocumentPosition(codeDocument, startIndex, out var hostDocumentStart, out var _)) { return(false); } var endIndex = range.End.GetAbsoluteIndex(csharpSourceText); if (!TryMapFromProjectedDocumentPosition(codeDocument, endIndex, out var hostDocumentEnd, out var _)) { return(false); } originalRange = new Range( hostDocumentStart, hostDocumentEnd); return(true); }
private HoverModel ElementInfoToHover(IEnumerable <TagHelperDescriptor> descriptors, RangeModel range, ClientCapabilities clientCapabilities) { var descriptionInfos = descriptors.Select(descriptor => BoundElementDescriptionInfo.From(descriptor)) .ToList() .AsReadOnly(); var elementDescriptionInfo = new AggregateBoundElementDescription(descriptionInfos); var isVSClient = clientCapabilities is PlatformAgnosticClientCapabilities platformAgnosticClientCapabilities && platformAgnosticClientCapabilities.SupportsVisualStudioExtensions; if (isVSClient && _vsLspTagHelperTooltipFactory.TryCreateTooltip(elementDescriptionInfo, out ContainerElement classifiedTextElement)) { var vsHover = new OmniSharpVSHover { Contents = new MarkedStringsOrMarkupContent(), Range = range, RawContent = classifiedTextElement, }; return(vsHover); } else { var hoverContentFormat = GetHoverContentFormat(clientCapabilities); if (!_lspTagHelperTooltipFactory.TryCreateTooltip(elementDescriptionInfo, hoverContentFormat, out var vsMarkupContent)) { return(null); } Enum.TryParse(vsMarkupContent.Kind.Value, out MarkupKind markupKind); var markupContent = new MarkupContent() { Value = vsMarkupContent.Value, Kind = markupKind, }; var hover = new HoverModel { Contents = new MarkedStringsOrMarkupContent(markupContent), Range = range }; return(hover); } }
public static void ShiftLineNumber(this Range range, int amount) { range.Start.ShiftLineNumber(amount); range.End.ShiftLineNumber(amount); }
public static Range Offset(this Range range, int character = 0, int line = 0) { return(range.OffsetStart(character, line).OffsetEnd(character, line)); }
public static Range OffsetEnd(this Range range, int character = 0, int line = 0) { return(new Range(range.Start, new Position(range.End.Line + line, range.End.Character + character))); }
/// <summary> /// Create a <see cref="CompletionItem"/> for the specified MSBuild task element. /// </summary> /// <param name="taskName"> /// The MSBuild task name. /// </param> /// <param name="taskMetadata"> /// The MSBuild task's metadata. /// </param> /// <param name="replaceRange"> /// The range of text that will be replaced by the completion. /// </param> /// <returns> /// The <see cref="CompletionItem"/>. /// </returns> CompletionItem TaskElementCompletionItem(string taskName, MSBuildTaskMetadata taskMetadata, LspModels.Range replaceRange) { MSBuildTaskParameterMetadata[] requiredParameters = taskMetadata.Parameters.Where(parameter => parameter.IsRequired).ToArray(); string requiredAttributes = String.Join(" ", requiredParameters.Select( (parameter, index) => $"{parameter.Name}=\"${index + 1}\"" )); string attributePadding = (requiredAttributes.Length > 0) ? " " : String.Empty; string restOfElement = " />$0"; if (taskMetadata.Parameters.Any(parameter => parameter.IsOutput)) { // Create Outputs sub-element if there are any output parameters. restOfElement = $">\n\t${requiredParameters.Length + 1}\n</{taskName}>$0"; } return(new CompletionItem { Label = $"<{taskName}>", Detail = "Task", Documentation = MSBuildSchemaHelp.ForTask(taskName), SortText = $"{Priority:0000}<{taskName}>", TextEdit = new TextEdit { NewText = $"<{taskName}{attributePadding}{requiredAttributes}{restOfElement}", Range = replaceRange }, InsertTextFormat = InsertTextFormat.Snippet }); }
public static CompletionItem WithSnippetEdit(this CompletionItem item, Range range, string snippet) { AssertNoInsertText(item); SetTextEditInternal(item, range, InsertTextFormat.Snippet, snippet); return(item); }
public static CompletionItem WithPlainTextEdit(this CompletionItem item, Range range, string text) { AssertNoInsertText(item); SetTextEditInternal(item, range, InsertTextFormat.PlainText, text); return(item); }
public async Task CanSendPesterLegacyCodeLensRequestAsync() { // Make sure LegacyCodeLens is enabled because we'll need it in this test. PsesLanguageClient.Workspace.DidChangeConfiguration( new DidChangeConfigurationParams { Settings = JObject.Parse(@" { ""powershell"": { ""pester"": { ""useLegacyCodeLens"": true } } } ") }); string filePath = NewTestFile(@" Describe 'DescribeName' { Context 'ContextName' { It 'ItName' { 1 | Should - Be 1 } } } ", isPester: true); CodeLensContainer codeLenses = await PsesLanguageClient .SendRequest <CodeLensParams>( "textDocument/codeLens", new CodeLensParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(filePath) } }) .Returning <CodeLensContainer>(CancellationToken.None).ConfigureAwait(false); Assert.Collection(codeLenses, codeLens1 => { Range range = codeLens1.Range; Assert.Equal(1, range.Start.Line); Assert.Equal(0, range.Start.Character); Assert.Equal(7, range.End.Line); Assert.Equal(1, range.End.Character); Assert.Equal("Run tests", codeLens1.Command.Title); }, codeLens2 => { Range range = codeLens2.Range; Assert.Equal(1, range.Start.Line); Assert.Equal(0, range.Start.Character); Assert.Equal(7, range.End.Line); Assert.Equal(1, range.End.Character); Assert.Equal("Debug tests", codeLens2.Command.Title); }); }
/// <summary> /// Push a token onto the builder /// </summary> /// <remarks>Avoid creating the range just to call this method</remarks> /// <param name="range">The range, cannot span multiple lines</param> /// <param name="tokenType"></param> /// <param name="tokenModifiers"></param> public void Push(Range range, SemanticTokenType?tokenType, IEnumerable <SemanticTokenModifier> tokenModifiers) => Push( range, _legend.GetTokenTypeIdentity(tokenType), _legend.GetTokenModifiersIdentity(tokenModifiers) );
/// <summary> /// Push a token onto the builder /// </summary> /// <remarks>Avoid creating the range just to call this method</remarks> /// <param name="range">The range, cannot span multiple lines</param> /// <param name="tokenType"></param> /// <param name="tokenModifiers"></param> public void Push(Range range, string tokenType, params string[] tokenModifiers) => Push( range, _legend.GetTokenTypeIdentity(tokenType), _legend.GetTokenModifiersIdentity(tokenModifiers) );
public static Range Clone(this Range range) { return(From(range.Start.Line, range.Start.Character, range.End.Line, range.End.Character)); }
/// <summary> /// Get property element completions. /// </summary> /// <param name="projectDocument"> /// The <see cref="ProjectDocument"/> for which completions will be offered. /// </param> /// <param name="replaceRange"> /// The range of text to be replaced by the completions. /// </param> /// <returns> /// A sequence of <see cref="CompletionItem"/>s. /// </returns> public IEnumerable <CompletionItem> GetCompletionItems(ProjectDocument projectDocument, Range replaceRange) { if (replaceRange == null) { throw new ArgumentNullException(nameof(replaceRange)); } LspModels.Range replaceRangeLsp = replaceRange.ToLsp(); HashSet <string> offeredPropertyNames = new HashSet <string>(); // Special-case properties // Output type yield return(new CompletionItem { Label = "<OutputType>", Detail = "Property", Kind = CompletionItemKind.Property, Documentation = MSBuildSchemaHelp.ForProperty("OutputType"), SortText = Priority + "<OutputType>", TextEdit = new TextEdit { NewText = "<OutputType>${1|Library,Exe|}</OutputType>", Range = replaceRangeLsp }, InsertTextFormat = InsertTextFormat.Snippet }); offeredPropertyNames.Add("OutputType"); // Target framework yield return(new CompletionItem { Label = "<TargetFramework>", Detail = "Property", Kind = CompletionItemKind.Property, Documentation = MSBuildSchemaHelp.ForProperty("TargetFramework"), SortText = Priority + "<TargetFramework>", TextEdit = new TextEdit { NewText = "<TargetFramework>${1|netstandard1.0,netstandard1.1,netstandard1.2,netstandard1.3,netstandard1.4,netstandard1.5,netstandard1.6,netstandard2.0,netcoreapp1.0,netcoreapp1.1,netcoreapp2.0,net4,net451,net452,net46,net461,net462,net47|}</TargetFramework>", Range = replaceRangeLsp }, InsertTextFormat = InsertTextFormat.Snippet }); offeredPropertyNames.Add("TargetFramework"); // Well-known (but standard-format) properties. foreach (string wellKnownPropertyName in MSBuildSchemaHelp.WellKnownPropertyNames) { if (!offeredPropertyNames.Add(wellKnownPropertyName)) { continue; } var propertyDefaults = MSBuildSchemaHelp.DefaultsForProperty(wellKnownPropertyName); yield return(PropertyCompletionItem(wellKnownPropertyName, replaceRangeLsp, description: MSBuildSchemaHelp.ForProperty(wellKnownPropertyName), defaultValue: propertyDefaults.defaultValue, defaultValues: propertyDefaults.defaultValues )); } if (!projectDocument.HasMSBuildProject) { yield break; // Without a valid MSBuild project (even a cached one will do), we can't inspect existing MSBuild properties. } if (!projectDocument.Workspace.Configuration.Language.CompletionsFromProject.Contains(CompletionSource.Property)) { yield break; } int otherPropertyPriority = Priority + 10; string[] otherPropertyNames = projectDocument.MSBuildProject.Properties .Select(property => property.Name) .Where(propertyName => !propertyName.StartsWith("_")) // Ignore private properties. .ToArray(); foreach (string propertyName in otherPropertyNames) { if (!offeredPropertyNames.Add(propertyName)) { continue; } yield return(PropertyCompletionItem(propertyName, replaceRangeLsp, otherPropertyPriority, description: $"I don't know anything about the '{propertyName}' property, but it's defined in this project (or a project that it imports); you can override its value by specifying it here." )); } }
public static FormattingContext Create( DocumentUri uri, DocumentSnapshot originalSnapshot, RazorCodeDocument codeDocument, FormattingOptions options, Range range = null, bool isFormatOnType = false) { if (uri is null) { throw new ArgumentNullException(nameof(uri)); } if (originalSnapshot is null) { throw new ArgumentNullException(nameof(originalSnapshot)); } if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } var text = codeDocument.GetSourceText(); range ??= TextSpan.FromBounds(0, text.Length).AsRange(text); var result = new FormattingContext() { Uri = uri, OriginalSnapshot = originalSnapshot, CodeDocument = codeDocument, Range = range, Options = options, IsFormatOnType = isFormatOnType }; var sourceText = codeDocument.GetSourceText(); var syntaxTree = codeDocument.GetSyntaxTree(); var formattingSpans = syntaxTree.GetFormattingSpans(); var indentations = new Dictionary <int, IndentationContext>(); var previousIndentationLevel = 0; for (var i = 0; i < sourceText.Lines.Count; i++) { // Get first non-whitespace character position var nonWsPos = sourceText.Lines[i].GetFirstNonWhitespacePosition(); var existingIndentation = (nonWsPos ?? sourceText.Lines[i].End) - sourceText.Lines[i].Start; var emptyOrWhitespaceLine = false; if (nonWsPos == null) { emptyOrWhitespaceLine = true; nonWsPos = sourceText.Lines[i].Start; } // position now contains the first non-whitespace character or 0. Get the corresponding FormattingSpan. if (TryGetFormattingSpan(nonWsPos.Value, formattingSpans, out var span)) { indentations[i] = new IndentationContext { Line = i, RazorIndentationLevel = span.RazorIndentationLevel, HtmlIndentationLevel = span.HtmlIndentationLevel, RelativeIndentationLevel = span.IndentationLevel - previousIndentationLevel, ExistingIndentation = existingIndentation, FirstSpan = span, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; previousIndentationLevel = span.IndentationLevel; } else { // Couldn't find a corresponding FormattingSpan. Happens if it is a 0 length line. // Let's create a 0 length span to represent this and default it to HTML. var placeholderSpan = new FormattingSpan( new Language.Syntax.TextSpan(nonWsPos.Value, 0), new Language.Syntax.TextSpan(nonWsPos.Value, 0), FormattingSpanKind.Markup, FormattingBlockKind.Markup, razorIndentationLevel: 0, htmlIndentationLevel: 0, isInClassBody: false); indentations[i] = new IndentationContext { Line = i, RazorIndentationLevel = 0, HtmlIndentationLevel = 0, RelativeIndentationLevel = previousIndentationLevel, ExistingIndentation = existingIndentation, FirstSpan = placeholderSpan, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; } } result.Indentations = indentations; return(result); }
public override bool TryMapToProjectedDocumentRange(RazorCodeDocument codeDocument, Range originalRange, out Range projectedRange) { if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (originalRange is null) { throw new ArgumentNullException(nameof(originalRange)); } projectedRange = default; var sourceText = codeDocument.GetSourceText(); var range = originalRange; var startIndex = range.Start.GetAbsoluteIndex(sourceText); if (!TryMapToProjectedDocumentPosition(codeDocument, startIndex, out var projectedStart, out var _)) { return(false); } var endIndex = range.End.GetAbsoluteIndex(sourceText); if (!TryMapToProjectedDocumentPosition(codeDocument, endIndex, out var projectedEnd, out var _)) { return(false); } projectedRange = new Range( projectedStart, projectedEnd); return(true); }
// We can't get C# responses without significant amounts of extra work, so let's just shim it for now, any non-Null result is fine. internal override Task <IReadOnlyList <SemanticRange> > GetCSharpSemanticRangesAsync(RazorCodeDocument codeDocument, TextDocumentIdentifier textDocumentIdentifier, Range range, long?documentVersion, CancellationToken cancellationToken) { return(Task.FromResult((IReadOnlyList <SemanticRange>) new List <SemanticRange>())); }
private static DefaultRazorDocumentMappingService CreateDocumentMappingService(Range projectedRange = null) { projectedRange ??= new Range(new Position(5, 2), new Position(5, 2)); var documentMappingService = Mock.Of <DefaultRazorDocumentMappingService>( d => d.TryMapToProjectedDocumentRange(It.IsAny <RazorCodeDocument>(), It.IsAny <Range>(), out projectedRange) == true ); return(documentMappingService); }
/// <summary> /// Get all completion items for target names. /// </summary> /// <param name="projectDocument"> /// The <see cref="ProjectDocument"/> for which completions will be offered. /// </param> /// <param name="replaceRange"> /// The range of text to be replaced by the completions. /// </param> /// <param name="excludeTargetNames"> /// The names of targets (if any) to exclude from the completion list. /// </param> /// <returns> /// A sequence of <see cref="CompletionItem"/>s. /// </returns> public IEnumerable <CompletionItem> GetCompletionItems(ProjectDocument projectDocument, Range replaceRange, HashSet <string> excludeTargetNames) { if (replaceRange == null) { throw new ArgumentNullException(nameof(replaceRange)); } HashSet <string> offeredTargetNames = new HashSet <string>(excludeTargetNames); LspModels.Range replaceRangeLsp = replaceRange.ToLsp(); // Well-known targets. foreach (string targetName in WellKnownTargets.Keys) { if (!offeredTargetNames.Add(targetName)) { continue; } yield return(TargetNameCompletionItem(targetName, replaceRangeLsp, description: WellKnownTargets[targetName] )); } // All other (public) targets defined in the project. if (!projectDocument.HasMSBuildProject) { yield break; // Without a valid MSBuild project (even a cached one will do), we can't inspect existing MSBuild targets. } if (!projectDocument.Workspace.Configuration.Language.CompletionsFromProject.Contains(CompletionSource.Target)) { yield break; } int otherTargetPriority = Priority + 10; ProjectTargetInstance[] otherTargets = projectDocument.MSBuildProject.Targets.Values .Where( target => !target.Name.StartsWith("_") // Ignore private targets. ) .OrderBy(target => target.Name) .ToArray(); foreach (ProjectTargetInstance otherTarget in otherTargets) { if (!offeredTargetNames.Add(otherTarget.Name)) { continue; } // We can't really tell them much else about the target if it's not one of the well-known ones. string targetDescription = String.Format("Originally declared in {0} (line {1}, column {2})", Path.GetFileName(otherTarget.Location.File), otherTarget.Location.Line, otherTarget.Location.Column ); yield return(TargetNameCompletionItem(otherTarget.Name, replaceRangeLsp, otherTargetPriority, targetDescription)); } }
public override bool TryMapFromProjectedDocumentRange(RazorCodeDocument codeDocument, Range projectedRange, MappingBehavior mappingBehavior, out Range originalRange) { if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (projectedRange is null) { throw new ArgumentNullException(nameof(projectedRange)); } if (mappingBehavior == MappingBehavior.Strict) { return(TryMapFromProjectedDocumentRangeStrict(codeDocument, projectedRange, out originalRange)); } else if (mappingBehavior == MappingBehavior.Inclusive) { return(TryMapFromProjectedDocumentRangeInclusive(codeDocument, projectedRange, out originalRange)); } else { throw new InvalidOperationException("Unknown mapping behavior"); } }
/// <summary> /// Get top-level element completions. /// </summary> /// <param name="replaceRange"> /// The range of text to be replaced by the completions. /// </param> /// <returns> /// A sequence of <see cref="CompletionItem"/>s. /// </returns> public IEnumerable <CompletionItem> GetCompletionItems(Range replaceRange) { if (replaceRange == null) { throw new ArgumentNullException(nameof(replaceRange)); } LspModels.Range completionRange = replaceRange.ToLsp(); // <PropertyGroup> // $0 // </PropertyGroup> yield return(new CompletionItem { Label = "<PropertyGroup>", Detail = "Element", Documentation = MSBuildSchemaHelp.ForElement("PropertyGroup"), SortText = Priority + "<PropertyGroup>", TextEdit = new TextEdit { NewText = "<PropertyGroup>\n\t$0\n</PropertyGroup>", Range = completionRange }, InsertTextFormat = InsertTextFormat.Snippet }); // <ItemGroup> // $0 // </ItemGroup> yield return(new CompletionItem { Label = "<ItemGroup>", Detail = "Element", Documentation = MSBuildSchemaHelp.ForElement("ItemGroup"), SortText = Priority + "<ItemGroup>", TextEdit = new TextEdit { NewText = "<ItemGroup>\n\t$0\n</ItemGroup>", Range = completionRange }, InsertTextFormat = InsertTextFormat.Snippet }); // <Target Name="TargetName"> // $0 // </Target> yield return(new CompletionItem { Label = "<Target>", Detail = "Element", Documentation = MSBuildSchemaHelp.ForElement("Target"), SortText = Priority + "<Target>", TextEdit = new TextEdit { NewText = "<Target Name=\"${1:TargetName}\">\n\t$0\n</Target>", Range = completionRange }, InsertTextFormat = InsertTextFormat.Snippet }); // <Import Project="ProjectFile" /> yield return(new CompletionItem { Label = "<Import>", Detail = "Element", Documentation = MSBuildSchemaHelp.ForElement("Import"), SortText = Priority + "<Import>", TextEdit = new TextEdit { NewText = "<Import Project=\"${1:ProjectFile}\" />$0", Range = completionRange }, InsertTextFormat = InsertTextFormat.Snippet }); }
private bool TryMapFromProjectedDocumentRangeInclusive(RazorCodeDocument codeDocument, Range projectedRange, out Range originalRange) { originalRange = default; var csharpDoc = codeDocument.GetCSharpDocument(); var csharpSourceText = SourceText.From(csharpDoc.GeneratedCode); var projectedRangeAsSpan = projectedRange.AsTextSpan(csharpSourceText); var range = projectedRange; var startIndex = projectedRangeAsSpan.Start; var startMappedDirectly = TryMapFromProjectedDocumentPosition(codeDocument, startIndex, out var hostDocumentStart, out _); var endIndex = projectedRangeAsSpan.End; var endMappedDirectly = TryMapFromProjectedDocumentPosition(codeDocument, endIndex, out var hostDocumentEnd, out _); if (startMappedDirectly && endMappedDirectly) { // We strictly mapped the start/end of the projected range. originalRange = new Range(hostDocumentStart, hostDocumentEnd); return(true); } List <SourceMapping> candidateMappings; if (startMappedDirectly) { // Start of projected range intersects with a mapping candidateMappings = csharpDoc.SourceMappings.Where(mapping => IntersectsWith(startIndex, mapping.GeneratedSpan)).ToList(); } else if (endMappedDirectly) { // End of projected range intersects with a mapping candidateMappings = csharpDoc.SourceMappings.Where(mapping => IntersectsWith(endIndex, mapping.GeneratedSpan)).ToList(); } else { // Our range does not intersect with any mapping; we should see if it overlaps generated locations candidateMappings = csharpDoc.SourceMappings.Where(mapping => Overlaps(projectedRangeAsSpan, mapping.GeneratedSpan)).ToList(); } if (candidateMappings.Count == 1) { // We're intersecting or overlapping a single mapping, lets choose that. var mapping = candidateMappings[0]; originalRange = ConvertMapping(codeDocument.Source, mapping); return(true); } else { // More then 1 or exactly 0 intersecting/overlapping mappings return(false); } bool Overlaps(TextSpan projectedRangeAsSpan, SourceSpan span) { var overlapStart = Math.Max(projectedRangeAsSpan.Start, span.AbsoluteIndex); var overlapEnd = Math.Min(projectedRangeAsSpan.End, span.AbsoluteIndex + span.Length); return(overlapStart < overlapEnd); } bool IntersectsWith(int position, SourceSpan span) { return(unchecked ((uint)(position - span.AbsoluteIndex) <= (uint)span.Length)); }
/// <summary> /// Push a token onto the builder /// </summary> /// <remarks>Avoid creating the range just to call this method</remarks> /// <param name="range">The range, cannot span multiple lines</param> /// <param name="tokenType"></param> /// <param name="tokenModifiers"></param> public void Push(Range range, string tokenType, IEnumerable <string> tokenModifiers) => Push( range, _legend.GetTokenTypeIdentity(tokenType), _legend.GetTokenModifiersIdentity(tokenModifiers) );
public async Task CanSendPesterCodeLensRequest() { // Make sure Pester legacy CodeLens is disabled because we'll need it in this test. LanguageClient.Workspace.DidChangeConfiguration(JObject.Parse(@" { ""powershell"": { ""pester"": { ""useLegacyCodeLens"": false } } } ")); string filePath = NewTestFile(@" Describe 'DescribeName' { Context 'ContextName' { It 'ItName' { 1 | Should - Be 1 } } } ", isPester: true); CodeLensContainer codeLenses = await LanguageClient.SendRequest <CodeLensContainer>( "textDocument/codeLens", new CodeLensParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(filePath) } }); Assert.Collection(codeLenses, codeLens => { Range range = codeLens.Range; Assert.Equal(1, range.Start.Line); Assert.Equal(0, range.Start.Character); Assert.Equal(7, range.End.Line); Assert.Equal(1, range.End.Character); Assert.Equal("Run tests", codeLens.Command.Title); }, codeLens => { Range range = codeLens.Range; Assert.Equal(1, range.Start.Line); Assert.Equal(0, range.Start.Character); Assert.Equal(7, range.End.Line); Assert.Equal(1, range.End.Character); Assert.Equal("Debug tests", codeLens.Command.Title); }, codeLens => { Range range = codeLens.Range; Assert.Equal(2, range.Start.Line); Assert.Equal(4, range.Start.Character); Assert.Equal(6, range.End.Line); Assert.Equal(5, range.End.Character); Assert.Equal("Run tests", codeLens.Command.Title); }, codeLens => { Range range = codeLens.Range; Assert.Equal(2, range.Start.Line); Assert.Equal(4, range.Start.Character); Assert.Equal(6, range.End.Line); Assert.Equal(5, range.End.Character); Assert.Equal("Debug tests", codeLens.Command.Title); }, codeLens => { Range range = codeLens.Range; Assert.Equal(3, range.Start.Line); Assert.Equal(8, range.Start.Character); Assert.Equal(5, range.End.Line); Assert.Equal(9, range.End.Character); Assert.Equal("Run test", codeLens.Command.Title); }, codeLens => { Range range = codeLens.Range; Assert.Equal(3, range.Start.Line); Assert.Equal(8, range.Start.Character); Assert.Equal(5, range.End.Line); Assert.Equal(9, range.End.Character); Assert.Equal("Debug test", codeLens.Command.Title); }); }
/// <summary> /// Push a token onto the builder /// </summary> /// <remarks>Avoid creating the range just to call this method</remarks> /// <param name="range">The range, cannot span multiple lines</param> /// <param name="tokenType"></param> /// <param name="tokenModifiers"></param> public void Push(Range range, SemanticTokenType?tokenType, params SemanticTokenModifier[] tokenModifiers) => Push( range, _legend.GetTokenTypeIdentity(tokenType), _legend.GetTokenModifiersIdentity(tokenModifiers) );