11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System ;
45using System . Collections . Generic ;
56using System . ComponentModel . Composition ;
67using System . Diagnostics . CodeAnalysis ;
910using System . Threading . Tasks ;
1011using System . Windows ;
1112using System . Windows . Data ;
12- using System . Windows . Media ;
1313using Microsoft . VisualStudio . Imaging ;
1414using Microsoft . VisualStudio . Imaging . Interop ;
1515using Microsoft . VisualStudio . PlatformUI ;
1919using Microsoft . Web . LibraryManager . Vsix . Shared ;
2020using Microsoft . WebTools . Languages . Json . Editor . Completion ;
2121using Microsoft . WebTools . Languages . Json . Parser . Nodes ;
22+ using Microsoft . WebTools . Languages . Shared . Parser ;
2223using Microsoft . WebTools . Languages . Shared . Parser . Nodes ;
2324
2425namespace Microsoft . Web . LibraryManager . Vsix . Json . Completion
@@ -45,10 +46,20 @@ protected override IEnumerable<JsonCompletionEntry> GetEntries(JsonCompletionCon
4546 {
4647 MemberNode member = context . ContextNode . FindType < MemberNode > ( ) ;
4748
49+ // We can show completions for "files". This could be libraries/[n]/files or
50+ // libraries/[n]/fileMappings/[m]/files.
4851 if ( member == null || member . UnquotedNameText != "files" )
4952 yield break ;
5053
51- var parent = member . Parent as ObjectNode ;
54+ // If the current member is "files", then it is either:
55+ // - a library "files" property
56+ // - a fileMapping "files" property
57+ MemberNode possibleFileMappingsNode = member . Parent . FindType < MemberNode > ( ) ;
58+ bool isFileMapping = possibleFileMappingsNode ? . UnquotedNameText == "fileMappings" ;
59+
60+ ObjectNode parent = isFileMapping
61+ ? possibleFileMappingsNode . Parent as ObjectNode
62+ : member . Parent as ObjectNode ;
5263
5364 if ( ! JsonHelpers . TryGetInstallationState ( parent , out ILibraryInstallationState state ) )
5465 yield break ;
@@ -67,18 +78,23 @@ protected override IEnumerable<JsonCompletionEntry> GetEntries(JsonCompletionCon
6778 FrameworkElement presenter = GetPresenter ( context ) ;
6879 IEnumerable < string > usedFiles = GetUsedFiles ( context ) ;
6980
81+ string rootPathPrefix = isFileMapping ? GetRootValue ( member ) : string . Empty ;
82+ static string GetRootValue ( MemberNode fileMappingNode )
83+ {
84+ FindFileMappingRootVisitor visitor = new FindFileMappingRootVisitor ( ) ;
85+ fileMappingNode . Parent ? . Accept ( visitor ) ;
86+ return visitor . FoundNode ? . UnquotedValueText ?? string . Empty ;
87+ }
88+
7089 if ( task . IsCompleted )
7190 {
7291 if ( ! ( task . Result is ILibrary library ) )
7392 yield break ;
7493
75- foreach ( string file in library . Files . Keys )
94+ IEnumerable < JsonCompletionEntry > completions = GetFileCompletions ( context , usedFiles , library , rootPathPrefix ) ;
95+ foreach ( JsonCompletionEntry item in completions )
7696 {
77- if ( ! usedFiles . Contains ( file ) )
78- {
79- ImageMoniker glyph = WpfUtil . GetImageMonikerForFile ( file ) ;
80- yield return new SimpleCompletionEntry ( file , glyph , context . Session ) ;
81- }
97+ yield return item ;
8298 }
8399 }
84100 else
@@ -94,23 +110,40 @@ protected override IEnumerable<JsonCompletionEntry> GetEntries(JsonCompletionCon
94110
95111 if ( ! context . Session . IsDismissed )
96112 {
97- var results = new List < JsonCompletionEntry > ( ) ;
98-
99- foreach ( string file in library . Files . Keys )
100- {
101- if ( ! usedFiles . Contains ( file ) )
102- {
103- ImageMoniker glyph = WpfUtil . GetImageMonikerForFile ( file ) ;
104- results . Add ( new SimpleCompletionEntry ( file , glyph , context . Session ) ) ;
105- }
106- }
107-
108- UpdateListEntriesSync ( context , results ) ;
113+ IEnumerable < JsonCompletionEntry > completions = GetFileCompletions ( context , usedFiles , library , rootPathPrefix ) ;
114+
115+ UpdateListEntriesSync ( context , completions ) ;
109116 }
110117 } , TaskScheduler . Default ) ;
111118 }
112119 }
113120
121+ private static IEnumerable < JsonCompletionEntry > GetFileCompletions ( JsonCompletionContext context , IEnumerable < string > usedFiles , ILibrary library , string root )
122+ {
123+ static bool alwaysInclude ( string s ) => true ;
124+ bool includeIfUnderRoot ( string s ) => FileHelpers . IsUnderRootDirectory ( s , root ) ;
125+
126+ Func < string , bool > filter = string . IsNullOrEmpty ( root )
127+ ? alwaysInclude
128+ : includeIfUnderRoot ;
129+
130+ bool rootHasTrailingSlash = string . IsNullOrEmpty ( root ) || root . EndsWith ( "/" ) || root . EndsWith ( "\\ " ) ;
131+ int nameOffset = rootHasTrailingSlash ? root . Length : root . Length + 1 ;
132+
133+ foreach ( string file in library . Files . Keys )
134+ {
135+ if ( filter ( file ) )
136+ {
137+ string fileSubPath = file . Substring ( nameOffset ) ;
138+ if ( ! usedFiles . Contains ( fileSubPath ) )
139+ {
140+ ImageMoniker glyph = WpfUtil . GetImageMonikerForFile ( file ) ;
141+ yield return new SimpleCompletionEntry ( fileSubPath , glyph , context . Session ) ;
142+ }
143+ }
144+ }
145+ }
146+
114147 private static IEnumerable < string > GetUsedFiles ( JsonCompletionContext context )
115148 {
116149 ArrayNode array = context . ContextNode . FindType < ArrayNode > ( ) ;
@@ -139,5 +172,31 @@ private FrameworkElement GetPresenter(JsonCompletionContext context)
139172
140173 return presenter ;
141174 }
175+
176+ private class FindFileMappingRootVisitor : INodeVisitor
177+ {
178+ public MemberNode FoundNode { get ; private set ; }
179+
180+ public VisitNodeResult Visit ( Node node )
181+ {
182+ if ( node is ObjectNode )
183+ {
184+ return VisitNodeResult . Continue ;
185+ }
186+ // we only look at the object and it's members, this is not a recursive search
187+ if ( node is not MemberNode mn )
188+ {
189+ return VisitNodeResult . SkipChildren ;
190+ }
191+
192+ if ( mn . UnquotedNameText == ManifestConstants . Root )
193+ {
194+ FoundNode = mn ;
195+ return VisitNodeResult . Cancel ;
196+ }
197+
198+ return VisitNodeResult . SkipChildren ;
199+ }
200+ }
142201 }
143202}
0 commit comments