22// Licensed under the MIT License.
33
44using System ;
5+ using System . Collections . Generic ;
56using System . IO ;
67using System . Linq ;
78using System . Threading . Tasks ;
1617using Newtonsoft . Json . Linq ;
1718using OmniSharp . Extensions . JsonRpc ;
1819using OmniSharp . Extensions . LanguageServer . Protocol . General ;
20+ using OmniSharp . Extensions . LanguageServer . Protocol . Models ;
1921using OmniSharp . Extensions . LanguageServer . Protocol . Server ;
2022using OmniSharp . Extensions . LanguageServer . Server ;
2123
@@ -138,12 +140,13 @@ public async Task StartAsync()
138140 languageServer . Services . GetService < ILogger < HostLoggerAdapter > > ( )
139141 ) ) ;
140142
141- // Set the workspace path from the parameters.
143+ // Set the workspace path from the parameters. The collection may be
144+ // absent (the field is optional in LSP), uninitialized, or contain
145+ // entries without a URI, so we treat any of those as "no folders yet"
146+ // rather than dereferencing a null and throwing.
142147 WorkspaceService workspaceService = languageServer . Services . GetService < WorkspaceService > ( ) ;
143- if ( initializeParams . WorkspaceFolders is not null )
144- {
145- workspaceService . WorkspaceFolders . AddRange ( initializeParams . WorkspaceFolders ) ;
146- }
148+ workspaceService . WorkspaceFolders . AddRange (
149+ GetValidWorkspaceFolders ( initializeParams . WorkspaceFolders ) ) ;
147150
148151 // Parse initialization options.
149152 JObject initializationOptions = initializeParams . InitializationOptions as JObject ;
@@ -161,7 +164,7 @@ public async Task StartAsync()
161164 // First check the setting, then use the first workspace folder,
162165 // finally fall back to CWD.
163166 InitialWorkingDirectory = initializationOptions ? . GetValue ( "initialWorkingDirectory" ) ? . Value < string > ( )
164- ?? workspaceService . WorkspaceFolders . FirstOrDefault ( ) ? . Uri . GetFileSystemPath ( )
167+ ?? workspaceService . WorkspaceFolders . FirstOrDefault ( ) ? . Uri ? . GetFileSystemPath ( )
165168 ?? Directory . GetCurrentDirectory ( ) ,
166169 // If a shell integration script path is provided, that implies the feature is enabled.
167170 ShellIntegrationScript = initializationOptions ? . GetValue ( "shellIntegrationScript" ) ? . Value < string > ( )
@@ -180,6 +183,21 @@ public async Task StartAsync()
180183 _serverStart . SetResult ( true ) ;
181184 }
182185
186+ /// <summary>
187+ /// Filters the workspace folders provided on <c>initialize</c> down to the usable ones.
188+ /// </summary>
189+ /// <remarks>
190+ /// The <c>workspaceFolders</c> field is optional in LSP, so the collection may be absent or
191+ /// uninitialized, and individual folders may be sent without a URI. Any of those are treated
192+ /// as "no folder" so that downstream code (which dereferences <see cref="WorkspaceFolder.Uri" />)
193+ /// does not throw a <see cref="NullReferenceException" />.
194+ /// </remarks>
195+ /// <param name="workspaceFolders">The workspace folders from the initialize parameters.</param>
196+ /// <returns>The folders that have a non-null URI, or an empty sequence.</returns>
197+ internal static IEnumerable < WorkspaceFolder > GetValidWorkspaceFolders ( IEnumerable < WorkspaceFolder > workspaceFolders )
198+ => workspaceFolders ? . Where ( static folder => folder ? . Uri is not null )
199+ ?? Enumerable . Empty < WorkspaceFolder > ( ) ;
200+
183201 /// <summary>
184202 /// Get a task that completes when the server is shut down.
185203 /// </summary>
0 commit comments