@@ -7,97 +7,11 @@ use std::sync::Arc;
77use CommonLibrary :: ExtensionManagement :: ExtensionManagementService :: ExtensionManagementService ;
88use serde_json:: { Value , json} ;
99
10- use crate :: { dev_log, RunTime :: ApplicationRunTime :: ApplicationRunTime } ;
11-
12- /// `MarshalledId.Uri` from VS Code's `src/vs/base/common/marshallingIds.ts`.
13- /// VS Code's `transformAndReviveIncomingURIs` walks every property of every
14- /// object returned from the IPC channel and only calls `URI.revive()` on
15- /// nested objects that carry `$mid === 1`. Without this marker the extension
16- /// location surfaces as a plain `UriComponents` bag; downstream
17- /// `resources.joinPath(local.location, …)` then trips on
18- /// `uri.with is not a function` the moment the sidebar tries to build an
19- /// icon URL. Every UriComponents we produce has to carry `$mid: 1`.
20- const MID_URI : u64 = 1 ;
21-
22- /// Reshape an `extensionLocation` field into VS Code's `UriComponents` object
23- /// form. The extension scanner stores it as a raw `file://` URL string; the
24- /// renderer's URI reviver is keyed off the `$mid` marshalling marker and only
25- /// revives objects that carry it, so the emitted shape must always include
26- /// `$mid: 1` alongside the usual `scheme / authority / path / query /
27- /// fragment` fields - otherwise the sidebar silently filters the whole batch
28- /// out (no `$mid` ⇒ no revive ⇒ `.fsPath` / `.with` undefined).
29- fn Normalize_Location_To_UriComponents ( Raw : Option < & Value > ) -> Value {
30- let Base = match Raw {
31- Some ( Value :: Object ( Map ) ) if Map . contains_key ( "scheme" ) => Value :: Object ( Map . clone ( ) ) ,
32- Some ( Value :: String ( Url ) ) => Parse_File_Url_To_UriComponents ( Url ) ,
33- _ => json ! ( {
34- "scheme" : "file" ,
35- "authority" : "" ,
36- "path" : "/extensions/unknown" ,
37- "query" : "" ,
38- "fragment" : "" ,
39- } ) ,
40- } ;
41- Stamp_Mid_Uri ( Base )
42- }
43-
44- /// Attach `$mid: 1` to a `UriComponents` object if it isn't already present.
45- /// Guards against both missing markers (the common case; Mountain built the
46- /// object ourselves) and pre-marked payloads (passthrough from an upstream
47- /// service that already tagged it). Returns the input unchanged for any
48- /// non-object value - callers are expected to have already produced a shape.
49- fn Stamp_Mid_Uri ( Input : Value ) -> Value {
50- match Input {
51- Value :: Object ( mut Map ) => {
52- Map . entry ( "$mid" . to_string ( ) ) . or_insert ( json ! ( MID_URI ) ) ;
53- Value :: Object ( Map )
54- }
55- Other => Other ,
56- }
57- }
58-
59- /// Minimal `file://` URL → `UriComponents` parser. Accepts
60- /// `file:///absolute/path` (authority empty) and preserves the path verbatim.
61- /// Non-`file:` schemes are parsed generically (scheme: path).
62- fn Parse_File_Url_To_UriComponents ( Url : & str ) -> Value {
63- if let Some ( Rest ) = Url . strip_prefix ( "file://" ) {
64- // `file:///Volumes/...` → authority="", path="/Volumes/..."
65- let ( Authority , Path ) = match Rest . find ( '/' ) {
66- Some ( 0 ) => ( "" , Rest ) ,
67- Some ( Index ) => ( & Rest [ ..Index ] , & Rest [ Index ..] ) ,
68- None => ( "" , "" ) ,
69- } ;
70- return json ! ( {
71- "scheme" : "file" ,
72- "authority" : Authority ,
73- "path" : Path ,
74- "query" : "" ,
75- "fragment" : "" ,
76- } ) ;
77- }
78- if let Some ( ( Scheme , PathPart ) ) = Url . split_once ( ':' ) {
79- let Trimmed = PathPart . trim_start_matches ( "//" ) ;
80- let ( Authority , Path ) = match Trimmed . find ( '/' ) {
81- Some ( 0 ) => ( "" , Trimmed ) ,
82- Some ( Index ) => ( & Trimmed [ ..Index ] , & Trimmed [ Index ..] ) ,
83- None => ( "" , Trimmed ) ,
84- } ;
85- return json ! ( {
86- "scheme" : Scheme ,
87- "authority" : Authority ,
88- "path" : Path ,
89- "query" : "" ,
90- "fragment" : "" ,
91- } ) ;
92- }
93- json ! ( {
94- "scheme" : "file" ,
95- "authority" : "" ,
96- "path" : Url ,
97- "query" : "" ,
98- "fragment" : "" ,
99- } )
100- }
10+ use crate :: {
11+ IPC :: UriComponents :: { Normalize as NormalizeUri , StampMidUri } ,
12+ RunTime :: ApplicationRunTime :: ApplicationRunTime ,
13+ dev_log,
14+ } ;
10115
10216/// Return scanned extensions reshaped as VS Code's `ILocalExtension[]`
10317/// so `ExtensionManagementChannelClient.getInstalled` can destructure
@@ -128,7 +42,7 @@ pub async fn handle_extensions_get_installed(runtime:Arc<ApplicationRunTime>) ->
12842 // filtered out. Normalize once, reuse for both the top-level
12943 // `location` and the mirror inside `manifest.extensionLocation` so
13044 // callers that read either field get the same shape.
131- let Location = Normalize_Location_To_UriComponents ( Manifest . get ( "extensionLocation" ) ) ;
45+ let Location = NormalizeUri ( Manifest . get ( "extensionLocation" ) ) ;
13246 let mut Manifest = Manifest ;
13347 if let Value :: Object ( ref mut Map ) = Manifest {
13448 Map . insert ( "extensionLocation" . to_string ( ) , Location . clone ( ) ) ;
0 commit comments