Skip to content

Commit

Permalink
Replace opening "<" in element completions
Browse files Browse the repository at this point in the history
Slightly hacky mechanism for handling behavioural changes in the VSCode extension or LSP API where reported position no longer includes character that was typed to trigger completion (it's possible that this extension is not reporting some newly-defined capability or setting to VSCode that would enable it to see the previous behaviour but it's hard to tell given how often things seem to change).

NOTE: This set of changes is not exhaustive - it's just a record of the types of changes that need to be made more extensively.

tintoy/msbuild-project-tools-vscode#67
  • Loading branch information
tintoy committed Jun 30, 2020
1 parent 856a529 commit acf3678
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
41 changes: 41 additions & 0 deletions src/LanguageServer.Common/Utilities/TextPositions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,47 @@ public int GetDistance(Position position1, Position position2)
return GetAbsolutePosition(position2) - GetAbsolutePosition(position1);
}

/// <summary>
/// Move the specified position closer to the start of the document by the specified number of characters.
/// </summary>
/// <param name="position">
/// The position.
/// </param>
/// <param name="byCharCount">
/// The number of characters.
/// </param>
/// <returns>
/// The updated position. If <paramref name="byCharCount"/> would take the position past the start of the document, this becomes (1,1).
/// </returns>
public Position MoveLeft(Position position, int byCharCount)
{
int absolutePosition = GetAbsolutePosition(position);
absolutePosition -= byCharCount;
if (absolutePosition < 0)
absolutePosition = 0;

return GetPosition(absolutePosition);
}

/// <summary>
/// Extend the specified range closer to the start of the document by the specified number of characters.
/// </summary>
/// <param name="range">
/// The range.
/// </param>
/// <param name="byCharCount">
/// The number of characters.
/// </param>
/// <returns>
/// The updated range. If <paramref name="byCharCount"/> would take the range start past the start of the document, this becomes (1,1).
/// </returns>
public Range ExtendLeft(Range range, int byCharCount)
{
return range.WithStart(
MoveLeft(range.Start, byCharCount)
);
}

/// <summary>
/// Calculate the start position for each line in the text.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ public ItemElementCompletion(ILogger logger)
{
replaceRange = location.Position.ToEmptyRange();

// Handle replacement of existing "<" if one was typed.
if (projectDocument.IsMSBuildProjectCached)
{
// Project XML is currently invalid; assume it's because they've typed a "<" character and attempt to compensate.
replaceRange = projectDocument.XmlPositions.ExtendLeft(replaceRange, byCharCount: 1);
}

Log.Verbose("Offering completions to create element @ {ReplaceRange:l}",
replaceRange
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,19 @@ public PackageReferenceCompletion(ILogger logger)
}
else if (location.CanCompleteElement(out XSElement replaceElement, parentPath: WellKnownElementPaths.ItemGroup))
{
Range replaceRange;

if (replaceElement != null)
{
replaceRange = replaceElement.Range;

// Handle replacement of existing "<" if one was typed.
if (projectDocument.IsMSBuildProjectCached)
{
// Project XML is currently invalid; assume it's because they've typed a "<" character and attempt to compensate.
replaceRange = projectDocument.XmlPositions.ExtendLeft(replaceRange, byCharCount: 1);
}

Log.Verbose("Offering completions to replace child element @ {ReplaceRange} of {ElementName} @ {Position:l}",
replaceElement.Range,
"ItemGroup",
Expand All @@ -108,13 +119,15 @@ public PackageReferenceCompletion(ILogger logger)
}
else
{
replaceRange = location.Position.ToEmptyRange();

Log.Verbose("Offering completions for new child element of {ElementName} @ {Position:l}",
"ItemGroup",
location.Position
replaceRange
);
}

List<CompletionItem> elementCompletions = HandlePackageReferenceElementCompletion(location, projectDocument, replaceElement);
List<CompletionItem> elementCompletions = HandlePackageReferenceElementCompletion(location, projectDocument, replaceRange);
if (elementCompletions != null)
completions.AddRange(elementCompletions);
}
Expand Down Expand Up @@ -216,22 +229,20 @@ async Task<List<CompletionItem>> HandlePackageReferenceAttributeCompletion(Proje
/// <param name="projectDocument">
/// The current project document.
/// </param>
/// <param name="replaceElement">
/// The element (if any) that will be replaced by the completion.
/// <param name="replaceRange">
/// The range of text that will be replaced by the completion.
/// </param>
/// <returns>
/// The completion list or <c>null</c> if no completions are provided.
/// </returns>
List<CompletionItem> HandlePackageReferenceElementCompletion(XmlLocation location, ProjectDocument projectDocument, XSElement replaceElement)
List<CompletionItem> HandlePackageReferenceElementCompletion(XmlLocation location, ProjectDocument projectDocument, Range replaceRange)
{
if (projectDocument == null)
throw new ArgumentNullException(nameof(projectDocument));

if (location == null)
throw new ArgumentNullException(nameof(location));

Range replaceRange = replaceElement?.Range ?? location.Position.ToEmptyRange();

return new List<CompletionItem>
{
new CompletionItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ public PropertyElementCompletion(ILogger logger)
{
replaceRange = location.Position.ToEmptyRange();

// Handle replacement of existing "<" if one was typed.
if (projectDocument.IsMSBuildProjectCached)
{
// Project XML is currently invalid; assume it's because they've typed a "<" character and attempt to compensate.
replaceRange = projectDocument.XmlPositions.ExtendLeft(replaceRange, byCharCount: 1);
}

Log.Verbose("Offering completions to create element @ {ReplaceRange:l}",
replaceRange
);
Expand Down

0 comments on commit acf3678

Please sign in to comment.