public void SimpleList_FindItemAtPosition(string input, int position, string expectedItemValue) { SimpleList list = MSBuildExpression.ParseSimpleList(input); DumpList(list, input); SimpleListItem actualItem = list.FindItemAt(position); Assert.NotNull(actualItem); Assert.Equal(expectedItemValue, actualItem.Value); string actualInput = input.Substring( startIndex: actualItem.AbsoluteStart, length: actualItem.AbsoluteEnd - actualItem.AbsoluteStart ); Assert.Equal(expectedItemValue, actualInput); }
/// <summary> /// Provide completions for the specified location. /// </summary> /// <param name="location"> /// The <see cref="XmlLocation"/> where completions are requested. /// </param> /// <param name="projectDocument"> /// The <see cref="ProjectDocument"/> that contains the <paramref name="location"/>. /// </param> /// <param name="cancellationToken"> /// A <see cref="CancellationToken"/> that can be used to cancel the operation. /// </param> /// <returns> /// A <see cref="Task{TResult}"/> that resolves either a <see cref="CompletionList"/>s, or <c>null</c> if no completions are provided. /// </returns> public override async Task <CompletionList> ProvideCompletions(XmlLocation location, ProjectDocument projectDocument, CancellationToken cancellationToken = default(CancellationToken)) { if (location == null) { throw new ArgumentNullException(nameof(location)); } if (projectDocument == null) { throw new ArgumentNullException(nameof(projectDocument)); } Log.Verbose("Evaluate completions for {XmlLocation:l}", location); List <CompletionItem> completions = new List <CompletionItem>(); using (await projectDocument.Lock.ReaderLockAsync()) { XSAttribute attribute; if (!location.CanCompleteAttributeValue(out attribute, onElementWithPath: WellKnownElementPaths.Target) || !SupportedAttributeNames.Contains(attribute.Name)) { Log.Verbose("Not offering any completions for {XmlLocation:l} (not the value of a supported attribute on a 'Target' element).", location); return(null); } Range targetRange = attribute.ValueRange; HashSet <string> excludeTargetNames = new HashSet <string>(); // Handle potentially composite (i.e. "Value1;Value2;Value3") values, where it's legal to have them. if (attribute.Name != "Name" && attribute.Value.IndexOf(';') != -1) { int startPosition = projectDocument.XmlPositions.GetAbsolutePosition(attribute.ValueRange.Start); int relativePosition = location.AbsolutePosition - startPosition; SimpleList list = MSBuildExpression.ParseSimpleList(attribute.Value); SimpleListItem itemAtPosition = list.FindItemAt(relativePosition); if (itemAtPosition == null) { return(null); } Log.Verbose("Completions will replace item {ItemValue} spanning [{ItemStartPosition}..{ItemEndPosition}) in MSBuild simple list expression {ListExpression}.", itemAtPosition.Value, itemAtPosition.AbsoluteStart, itemAtPosition.AbsoluteEnd, attribute.Value ); targetRange = projectDocument.XmlPositions.GetRange( absoluteStartPosition: startPosition + itemAtPosition.AbsoluteStart, absoluteEndPosition: startPosition + itemAtPosition.AbsoluteEnd ); } completions.AddRange( GetCompletionItems(projectDocument, targetRange, excludeTargetNames) ); } if (completions.Count == 0) { return(null); // No completions provided. } Log.Verbose("Offering {CompletionCount} completion(s) for {XmlLocation:l}", completions.Count, location); return(new CompletionList(completions, isIncomplete: false // Consider this list to be exhaustive )); }