@@ -144,14 +144,28 @@ export class LspClientManager {
144144 }
145145
146146 async getExtensionsForFile ( metadata : FileMetadata ) : Promise < Extension [ ] > {
147- const { uri, languageId, languageName, view, file, rootUri } = metadata ;
147+ const {
148+ uri : originalUri ,
149+ languageId,
150+ languageName,
151+ view,
152+ file,
153+ rootUri,
154+ } = metadata ;
148155
149156 const effectiveLang = safeString ( languageId ?? languageName ) . toLowerCase ( ) ;
150157 if ( ! effectiveLang ) return [ ] ;
151158
152159 const servers = serverRegistry . getServersForLanguage ( effectiveLang ) ;
153160 if ( ! servers . length ) return [ ] ;
154161
162+ // Normalize the document URI for LSP (convert content:// to file://)
163+ const normalizedUri = normalizeDocumentUri ( originalUri ) ;
164+ if ( ! normalizedUri ) {
165+ console . warn ( `Cannot normalize document URI for LSP: ${ originalUri } ` ) ;
166+ return [ ] ;
167+ }
168+
155169 const lspExtensions : Extension [ ] = [ ] ;
156170 const diagnosticsUiExtension = this . options . diagnosticsUiExtension ;
157171
@@ -162,28 +176,31 @@ export class LspClientManager {
162176 const resolved = server . resolveLanguageId ( {
163177 languageId : effectiveLang ,
164178 languageName,
165- uri,
179+ uri : normalizedUri ,
166180 file,
167181 } ) ;
168182 if ( resolved ) targetLanguageId = safeString ( resolved ) ;
169183 } catch ( error ) {
170184 console . warn (
171- `LSP server ${ server . id } failed to resolve language id for ${ uri } ` ,
185+ `LSP server ${ server . id } failed to resolve language id for ${ normalizedUri } ` ,
172186 error ,
173187 ) ;
174188 }
175189 }
176190
177191 try {
178192 const clientState = await this . #ensureClient( server , {
179- uri,
193+ uri : normalizedUri ,
180194 file,
181195 view,
182196 languageId : targetLanguageId ,
183197 rootUri,
184198 } ) ;
185- const plugin = clientState . client . plugin ( uri , targetLanguageId ) ;
186- clientState . attach ( uri , view as EditorView ) ;
199+ const plugin = clientState . client . plugin (
200+ normalizedUri ,
201+ targetLanguageId ,
202+ ) ;
203+ clientState . attach ( normalizedUri , view as EditorView ) ;
187204 lspExtensions . push ( plugin ) ;
188205 } catch ( error ) {
189206 const lspError = error as LSPError ;
@@ -211,16 +228,25 @@ export class LspClientManager {
211228 metadata : FileMetadata ,
212229 options : FormattingOptions = { } ,
213230 ) : Promise < boolean > {
214- const { uri, languageId, languageName, view, file } = metadata ;
231+ const { uri : originalUri , languageId, languageName, view, file } = metadata ;
215232 const effectiveLang = safeString ( languageId ?? languageName ) . toLowerCase ( ) ;
216233 if ( ! effectiveLang || ! view ) return false ;
234+
235+ const normalizedUri = normalizeDocumentUri ( originalUri ) ;
236+ if ( ! normalizedUri ) {
237+ console . warn (
238+ `Cannot normalize document URI for formatting: ${ originalUri } ` ,
239+ ) ;
240+ return false ;
241+ }
242+
217243 const servers = serverRegistry . getServersForLanguage ( effectiveLang ) ;
218244 if ( ! servers . length ) return false ;
219245
220246 for ( const server of servers ) {
221247 try {
222248 const context : RootUriContext = {
223- uri,
249+ uri : normalizedUri ,
224250 languageId : effectiveLang ,
225251 view,
226252 file,
@@ -229,15 +255,15 @@ export class LspClientManager {
229255 const state = await this . #ensureClient( server , context ) ;
230256 const capabilities = state . client . serverCapabilities ;
231257 if ( ! capabilities ?. documentFormattingProvider ) continue ;
232- state . attach ( uri , view ) ;
258+ state . attach ( normalizedUri , view ) ;
233259 const plugin = LSPPlugin . get ( view ) ;
234260 if ( ! plugin ) continue ;
235261 plugin . client . sync ( ) ;
236262 const edits = await state . client . request <
237263 { textDocument : { uri : string } ; options : FormattingOptions } ,
238264 TextEdit [ ] | null
239265 > ( "textDocument/formatting" , {
240- textDocument : { uri } ,
266+ textDocument : { uri : normalizedUri } ,
241267 options : buildFormattingOptions ( view , options ) ,
242268 } ) ;
243269 if ( ! edits || ! edits . length ) {
@@ -900,6 +926,30 @@ function normalizeRootUriForServer(
900926 return { normalizedRootUri : rootUri , originalRootUri : rootUri } ;
901927}
902928
929+ function normalizeDocumentUri ( uri : string | null | undefined ) : string | null {
930+ if ( ! uri || typeof uri !== "string" ) return null ;
931+
932+ const schemeMatch = / ^ ( [ a - z A - Z ] [ \w + \- . ] * ) : / . exec ( uri ) ;
933+ const scheme = schemeMatch ? schemeMatch [ 1 ] . toLowerCase ( ) : null ;
934+
935+ // Already a file:// URI or untitled use as-is
936+ if ( scheme === "file" || scheme === "untitled" ) {
937+ return uri ;
938+ }
939+
940+ // Convert content:// URIs to file:// URIs
941+ if ( scheme === "content" ) {
942+ const fileUri = contentUriToFileUri ( uri ) ;
943+ if ( fileUri ) {
944+ return fileUri ;
945+ }
946+ return null ;
947+ }
948+
949+ // Unknown scheme
950+ return uri ;
951+ }
952+
903953function contentUriToFileUri ( uri : string ) : string | null {
904954 try {
905955 const parsed = Uri . parse ( uri ) as ParsedUri | null ;
@@ -912,7 +962,7 @@ function contentUriToFileUri(uri: string): string | null {
912962 }
913963
914964 const providerMatch =
915- / ^ c o n t e n t : \/ \/ c o m \. ( (? ! [: <> " / \\ | ? * ] ) .* ) \ \ .d o c u m e n t s \/ / . exec (
965+ / ^ c o n t e n t : \/ \/ c o m \. ( (? ! [: <> " / \\ | ? * ] ) .* ? ) \. d o c u m e n t s \/ / . exec (
916966 rootUri ?? "" ,
917967 ) ;
918968 const providerId = providerMatch ? providerMatch [ 1 ] : null ;
0 commit comments