Skip to content

Commit 4287fc1

Browse files
work
1 parent 9ba8d1e commit 4287fc1

File tree

2 files changed

+62
-55
lines changed

2 files changed

+62
-55
lines changed

src/Bicep.LangServer.UnitTests/Completions/ModuleReferenceCompletionProviderTests.cs

+8
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ public async Task GetFilteredCompletions_WithInvalidTextInCompletionContext_Retu
211211
[DataRow("module test 'br/public:app/dapr-containerapp:1.0.1|'")]
212212
[DataRow("module test |'br/public:app/dapr-containerapp:1.0.1'")]
213213
[DataRow("module test 'br/public:app/dapr-containerapp:1.0.1'|")]
214+
[DataRow("module test 'br:mcr.microsoft.com/bicep/app/dapr-containerapp:1.0.1|")]
215+
[DataRow("module test 'br:mcr.microsoft.com/bicep/app/dapr-containerapp:1.0.1|'")]
216+
[DataRow("module test |'br:mcr.microsoft.com/bicep/app/dapr-containerapp:1.0.1'")]
217+
[DataRow("module test 'br:mcr.microsoft.com/bicep/app/dapr-containerapp:1.0.1'|")]
218+
[DataRow("module test 'br:contoso.com/app/dapr-containerapp:1.0.1|")]
219+
[DataRow("module test 'br:contoso.com/app/dapr-containerapp:1.0.1|'")]
220+
[DataRow("module test |'br:contoso.com/app/dapr-containerapp:1.0.1'")]
221+
[DataRow("module test 'br:contoso.com/app/dapr-containerapp:1.0.1'|")]
214222
public async Task GetFilteredCompletions_WithInvalidCompletionContext_ReturnsEmptyList(string inputWithCursors)
215223
{
216224
var publicRegistryModuleMetadataProvider = StrictMock.Of<IPublicRegistryModuleMetadataProvider>();

src/Bicep.LangServer/Completions/ModuleReferenceCompletionProvider.cs

+54-55
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,16 @@ private enum ModuleCompletionPriority
4040
}
4141

4242
// Direct reference to a full registry login server URI via br:<registry>
43-
private static readonly Regex ModuleWithFullPath = new(@"^br:(?<registry>(.*?))/", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
43+
private static readonly Regex ModulePrefixWithFullPath = new(@"^br:(?<registry>(.*?))/", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
4444

4545
// Aliased reference to a registry via br/alias:path
46-
private static readonly Regex ModuleWithAlias = new(@"^br/(.*):(?<filePath>(.*?)):", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
46+
private static readonly Regex ModulePrefixWithAlias = new(@"^br/(.*):(?<filePath>(.*?)):", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
4747

4848
// Direct reference to the MCR (public) registry via br:mcr.microsoft.com/bicep/path
49-
private static readonly Regex PublicModuleWithFullPath = new($"^br:{PublicMCRRegistry}/bicep/(?<filePath>(.*?)):'?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); //asdfg needed?
49+
private static readonly Regex PublicModuleWithFullPathAndVersionSeparator = new($"^br:{PublicMCRRegistry}/bicep/(?<filePath>(.*?)):'?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
5050

5151
// Aliased reference to the MCR (public) registry via br/public:
52-
private static readonly Regex PublicModuleWithAlias = new(@"^br/public:(?<filePath>(.*?)):'?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
52+
private static readonly Regex PublicModuleWithAliasAndVersionSeparator = new(@"^br/public:(?<filePath>(.*?)):'?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
5353

5454
private const string PublicMCRRegistry = LanguageConstants.BicepPublicMcrRegistry; // "mcr.microsoft.com"
5555

@@ -83,14 +83,14 @@ public async Task<IEnumerable<CompletionItem>> GetFilteredCompletions(Uri source
8383
{
8484
var trimmedReplacementText = replacementText.Trim('\'');
8585

86-
var replacementsAfterSingleQuote =
86+
var replacementsRequiringStartingQuote =
8787
GetOciModulePathCompletions(context, trimmedReplacementText, sourceFileUri)
88-
.Concat(GetMCRModuleRegistryVersionCompletions(context, trimmedReplacementText, sourceFileUri))
88+
.Concat(GetPublicModuleVersionCompletions(context, trimmedReplacementText, sourceFileUri))
8989
.Concat(await GetAllRegistryNameAndAliasCompletions(context, trimmedReplacementText, sourceFileUri, cancellationToken));
9090

9191
completions = [
9292
..completions,
93-
..replacementsAfterSingleQuote,
93+
..replacementsRequiringStartingQuote,
9494
];
9595
}
9696

@@ -180,7 +180,7 @@ void AddCompletionItem(string schemePrefix, string? alias, string detailLabel, M
180180
/// <summary>
181181
/// True if is an OCI module reference (i.e., it starts with br: or br/)
182182
/// </summary>
183-
private bool IsOciArtifactRegistryReference(string trimmedText) //asdfg rename
183+
private bool IsOciArtifactRegistryReference(string trimmedText)
184184
{
185185
if (trimmedText.StartsWith("br/") || trimmedText.StartsWith("br:"))
186186
{
@@ -196,7 +196,7 @@ private bool IsOciArtifactRegistryReference(string trimmedText) //asdfg rename
196196
// br:mcr.microsoft/bicep/module/name:<CURSOR>
197197
//
198198
// etc
199-
private IEnumerable<CompletionItem> GetMCRModuleRegistryVersionCompletions(BicepCompletionContext context, string trimmedText, Uri sourceFileUri)
199+
private IEnumerable<CompletionItem> GetPublicModuleVersionCompletions(BicepCompletionContext context, string trimmedText, Uri sourceFileUri)
200200
{
201201
if (!IsOciArtifactRegistryReference(trimmedText))
202202
{
@@ -205,19 +205,19 @@ private IEnumerable<CompletionItem> GetMCRModuleRegistryVersionCompletions(Bicep
205205

206206
string? modulePath;
207207

208-
if (PublicModuleWithAlias.IsMatch(trimmedText))
208+
if (PublicModuleWithAliasAndVersionSeparator.IsMatch(trimmedText))
209209
{
210-
var matches = PublicModuleWithAlias.Matches(trimmedText);
210+
var matches = PublicModuleWithAliasAndVersionSeparator.Matches(trimmedText);
211211
modulePath = matches[0].Groups["filePath"].Value;
212212
}
213-
else if (PublicModuleWithFullPath.IsMatch(trimmedText))
213+
else if (PublicModuleWithFullPathAndVersionSeparator.IsMatch(trimmedText))
214214
{
215-
var matches = PublicModuleWithFullPath.Matches(trimmedText);
215+
var matches = PublicModuleWithFullPathAndVersionSeparator.Matches(trimmedText);
216216
modulePath = matches[0].Groups["filePath"].Value;
217217
}
218218
else
219219
{
220-
modulePath = GetNonPublicMCRFilePathForVersionCompletion(trimmedText, sourceFileUri);
220+
modulePath = GetAliasedMCRFilePath(trimmedText, sourceFileUri);
221221
}
222222

223223
if (modulePath is null)
@@ -248,56 +248,56 @@ private IEnumerable<CompletionItem> GetMCRModuleRegistryVersionCompletions(Bicep
248248
}
249249

250250
return completions;
251-
}
252251

253-
// Handles scenario where the user has configured an alias for MCR in bicepconfig.json.
254-
private string? GetNonPublicMCRFilePathForVersionCompletion(string trimmedText, Uri sourceFileUri)
255-
{
256-
foreach (var kvp in GetModuleAliases(sourceFileUri))
252+
// Handles scenario where the user has configured an alias for MCR in bicepconfig.json.
253+
string? GetAliasedMCRFilePath(string trimmedText, Uri sourceFileUri)
257254
{
258-
if (kvp.Value.Registry is string registry &&
259-
registry.Equals(PublicMCRRegistry, StringComparison.Ordinal))
255+
foreach (var kvp in GetModuleAliases(sourceFileUri))
260256
{
261-
var aliasFromBicepConfig = $"br/{kvp.Key}:";
262-
263-
if (trimmedText.StartsWith(aliasFromBicepConfig, StringComparison.Ordinal))
257+
if (kvp.Value.Registry is string registry &&
258+
registry.Equals(PublicMCRRegistry, StringComparison.Ordinal))
264259
{
265-
var matches = ModuleWithAlias.Matches(trimmedText);
260+
var aliasFromBicepConfig = $"br/{kvp.Key}:";
266261

267-
if (!matches.Any())
262+
if (trimmedText.StartsWith(aliasFromBicepConfig, StringComparison.Ordinal))
268263
{
269-
continue;
270-
}
264+
var matches = ModulePrefixWithAlias.Matches(trimmedText);
271265

272-
string filePath = matches[0].Groups["filePath"].Value;
266+
if (!matches.Any())
267+
{
268+
continue;
269+
}
273270

274-
if (filePath is null)
275-
{
276-
continue;
277-
}
271+
string filePath = matches[0].Groups["filePath"].Value;
278272

279-
var modulePath = kvp.Value.ModulePath;
273+
if (filePath is null)
274+
{
275+
continue;
276+
}
280277

281-
if (modulePath is not null)
282-
{
283-
if (modulePath.StartsWith("bicep/"))
278+
var modulePath = kvp.Value.ModulePath;
279+
280+
if (modulePath is not null)
284281
{
285-
modulePath = modulePath.Substring("bicep/".Length);
286-
return $"{modulePath}/{filePath}";
282+
if (modulePath.StartsWith("bicep/"))
283+
{
284+
modulePath = modulePath.Substring("bicep/".Length);
285+
return $"{modulePath}/{filePath}";
286+
}
287287
}
288-
}
289-
else
290-
{
291-
if (filePath.StartsWith("bicep/"))
288+
else
292289
{
293-
return filePath.Substring("bicep/".Length);
290+
if (filePath.StartsWith("bicep/"))
291+
{
292+
return filePath.Substring("bicep/".Length);
293+
}
294294
}
295295
}
296296
}
297297
}
298-
}
299298

300-
return null;
299+
return null;
300+
}
301301
}
302302

303303
private ImmutableSortedDictionary<string, OciArtifactModuleAlias> GetModuleAliases(Uri sourceFileUri)
@@ -316,14 +316,14 @@ private IEnumerable<CompletionItem> GetOciModulePathCompletions(BicepCompletionC
316316

317317
return [
318318
.. GetPublicModuleCompletions(trimmedText, context),
319-
.. GetACRPartialPathCompletionsFromModuleAliases(trimmedText, context, sourceFileUri),
320-
.. GetMCRPathCompletionFromBicepConfig(trimmedText, context, sourceFileUri),
319+
.. GetPartialPrivatePathCompletionsFromAliases(trimmedText, context, sourceFileUri),
320+
.. GetPublicPathCompletionFromAliases(trimmedText, context, sourceFileUri),
321321
];
322322
}
323323

324324

325325
// Handles path completions for case where user has specified an alias in bicepconfig.json with registry set to "mcr.microsoft.com".
326-
private IEnumerable<CompletionItem> GetMCRPathCompletionFromBicepConfig(string trimmedText, BicepCompletionContext context, Uri sourceFileUri)
326+
private IEnumerable<CompletionItem> GetPublicPathCompletionFromAliases(string trimmedText, BicepCompletionContext context, Uri sourceFileUri)
327327
{
328328
List<CompletionItem> completions = new();
329329

@@ -336,7 +336,7 @@ private IEnumerable<CompletionItem> GetMCRPathCompletionFromBicepConfig(string t
336336
{
337337
if (kvp.Value.Registry is string registry)
338338
{
339-
// We currently don't support path completion for ACR, but we'll go ahead and log telemetry to track usage.
339+
// We currently don't support path completion for private modules, but we'll go ahead and log telemetry to track usage.
340340
if (!registry.Equals(PublicMCRRegistry, StringComparison.Ordinal) &&
341341
trimmedText.Equals($"br/{kvp.Key}:"))
342342
{
@@ -457,7 +457,7 @@ private bool IsPrivateRegistryReference(string text, [NotNullWhen(true)] out str
457457
{
458458
registry = null;
459459

460-
var matches = ModuleWithFullPath.Matches(text);
460+
var matches = ModulePrefixWithFullPath.Matches(text);
461461
if (!matches.Any())
462462
{
463463
return false;
@@ -484,7 +484,7 @@ private bool IsPrivateRegistryReference(string text, [NotNullWhen(true)] out str
484484
// br:privateacr.azurecr.io/<CURSOR>
485485
// =>
486486
// br:privateacr.azurecr.io/bicep/app:<CURSOR>
487-
private IEnumerable<CompletionItem> GetACRPartialPathCompletionsFromModuleAliases(string trimmedText, BicepCompletionContext context, Uri sourceFileUri)
487+
private IEnumerable<CompletionItem> GetPartialPrivatePathCompletionsFromAliases(string trimmedText, BicepCompletionContext context, Uri sourceFileUri)
488488
{
489489
List<CompletionItem> completions = new();
490490

@@ -607,15 +607,14 @@ private async Task<IEnumerable<CompletionItem>> GetAllRegistryNameAndAliasComple
607607

608608
completions.Add(mcrCompletionItem);
609609

610-
IEnumerable<CompletionItem> acrCompletions = await GetACRModuleRegistriesCompletions(trimmedText, context, sourceFileUri, cancellationToken);
611-
completions.AddRange(acrCompletions);
610+
completions.AddRange(await GetPrivateModuleCompletions(trimmedText, context, sourceFileUri, cancellationToken));
612611
}
613612

614613
return completions;
615614
}
616615

617616
// Handles registry name completions for private modules possibly available in ACR registries
618-
private async Task<IEnumerable<CompletionItem>> GetACRModuleRegistriesCompletions(string trimmedText, BicepCompletionContext context, Uri sourceFileUri, CancellationToken cancellationToken)
617+
private async Task<IEnumerable<CompletionItem>> GetPrivateModuleCompletions(string trimmedText, BicepCompletionContext context, Uri sourceFileUri, CancellationToken cancellationToken)
619618
{
620619
if (settingsProvider.GetSetting(LangServerConstants.GetAllAzureContainerRegistriesForCompletionsSetting))
621620
{

0 commit comments

Comments
 (0)