diff --git a/src/LanguageServer.Common/Utilities/TextPositions.cs b/src/LanguageServer.Common/Utilities/TextPositions.cs index 24d81b4..c395d46 100644 --- a/src/LanguageServer.Common/Utilities/TextPositions.cs +++ b/src/LanguageServer.Common/Utilities/TextPositions.cs @@ -16,6 +16,11 @@ public sealed class TextPositions /// readonly int[] _lineStartPositions; + /// + /// The total length of the text. + /// + readonly int _textLength; + /// /// Create a new for the specified text. /// @@ -28,6 +33,7 @@ public TextPositions(string text) throw new ArgumentNullException(nameof(text)); _lineStartPositions = CalculateLineStartPositions(text); + _textLength = text.Length; } /// @@ -177,6 +183,28 @@ public Position MoveLeft(Position position, int byCharCount) return GetPosition(absolutePosition); } + /// + /// Move the specified position closer to the end of the document by the specified number of characters. + /// + /// + /// The position. + /// + /// + /// The number of characters. + /// + /// + /// The updated position. If would take the position past the end of the document, this becomes (1,1). + /// + public Position MoveRight(Position position, int byCharCount) + { + int absolutePosition = GetAbsolutePosition(position); + absolutePosition += byCharCount; + if (absolutePosition >= _textLength) + absolutePosition = _textLength - 1; + + return GetPosition(absolutePosition); + } + /// /// Extend the specified range closer to the start of the document by the specified number of characters. /// @@ -196,6 +224,25 @@ public Range ExtendLeft(Range range, int byCharCount) ); } + /// + /// Extend the specified range closer to the end of the document by the specified number of characters. + /// + /// + /// The range. + /// + /// + /// The number of characters. + /// + /// + /// The updated range. If would take the range end past the end of the document, this becomes (1,1). + /// + public Range ExtendRight(Range range, int byCharCount) + { + return range.WithEnd( + MoveRight(range.End, byCharCount) + ); + } + /// /// Calculate the start position for each line in the text. /// diff --git a/src/LanguageServer.Engine/CompletionProviders/CompletionProvider.cs b/src/LanguageServer.Engine/CompletionProviders/CompletionProvider.cs index 7240202..c4e4187 100644 --- a/src/LanguageServer.Engine/CompletionProviders/CompletionProvider.cs +++ b/src/LanguageServer.Engine/CompletionProviders/CompletionProvider.cs @@ -93,12 +93,9 @@ protected virtual bool HandleTriggerCharacters(string triggerCharacters, Project if (projectDocument == null) throw new ArgumentNullException(nameof(projectDocument)); - // Replace any characters that were typed to trigger the completion. - if (triggerCharacters != null) + if (!String.IsNullOrEmpty(triggerCharacters)) { - targetRange = projectDocument.XmlPositions.ExtendLeft(targetRange, byCharCount: triggerCharacters.Length); - - Log.Verbose("Completion was triggered by typing one or more characters; target range will be extended by {TriggerCharacterCount} characters toward start of document (now: {TargetRange}).", triggerCharacters.Length, targetRange); + // NOTE: VSCode / LSP no longer require the selection to be extended when providing completions triggered by typing trigger characters, but you can still perform any other special handling here (if required). return true; } diff --git a/src/LanguageServer.Engine/CompletionProviders/PropertyElementCompletionProvider.cs b/src/LanguageServer.Engine/CompletionProviders/PropertyElementCompletionProvider.cs index 74cc69a..1b9c220 100644 --- a/src/LanguageServer.Engine/CompletionProviders/PropertyElementCompletionProvider.cs +++ b/src/LanguageServer.Engine/CompletionProviders/PropertyElementCompletionProvider.cs @@ -123,7 +123,7 @@ public override async Task ProvideCompletionsAsync(XmlLocation l /// public IEnumerable GetCompletionItems(ProjectDocument projectDocument, Range replaceRange) { - LspModels.Range replaceRangeLsp = replaceRange.ToLsp(); + LspModels.Range completionRange = replaceRange.ToLsp(); HashSet offeredPropertyNames = new HashSet(); @@ -136,7 +136,7 @@ public IEnumerable GetCompletionItems(ProjectDocument projectDoc var defaultValues = MSBuildSchemaHelp.DefaultsForProperty(wellKnownPropertyName); - yield return PropertyCompletionItem(wellKnownPropertyName, replaceRangeLsp, + yield return PropertyCompletionItem(wellKnownPropertyName, completionRange, description: MSBuildSchemaHelp.ForProperty(wellKnownPropertyName), defaultValues: defaultValues ); @@ -160,7 +160,7 @@ public IEnumerable GetCompletionItems(ProjectDocument projectDoc if (!offeredPropertyNames.Add(propertyName)) continue; - yield return PropertyCompletionItem(propertyName, replaceRangeLsp, otherPropertyPriority, + yield return PropertyCompletionItem(propertyName, completionRange, 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." ); } @@ -172,7 +172,7 @@ public IEnumerable GetCompletionItems(ProjectDocument projectDoc /// /// The MSBuild property name. /// - /// + /// /// The range of text that will be replaced by the completion. /// /// @@ -189,7 +189,7 @@ public IEnumerable GetCompletionItems(ProjectDocument projectDoc /// /// The . /// - CompletionItem PropertyCompletionItem(string propertyName, LspModels.Range replaceRange, int? priority = null, string description = null, IReadOnlyList defaultValues = null) + CompletionItem PropertyCompletionItem(string propertyName, LspModels.Range completionRange, int? priority = null, string description = null, IReadOnlyList defaultValues = null) { return new CompletionItem { @@ -201,7 +201,7 @@ CompletionItem PropertyCompletionItem(string propertyName, LspModels.Range repla TextEdit = new TextEdit { NewText = GetCompletionText(propertyName, defaultValues), - Range = replaceRange + Range = completionRange }, InsertTextFormat = InsertTextFormat.Snippet };