@@ -130,22 +130,42 @@ func (m *Manager) ListShims() ([]string, error) {
130130 return shims , nil
131131}
132132
133- // Rehash regenerates all shims by scanning installed versions
134- func (m * Manager ) Rehash () error {
133+ // RehashResult contains the results of a reshim operation
134+ type RehashResult struct {
135+ // ShimsByRuntime maps runtime names to their shim names
136+ ShimsByRuntime map [string ][]string
137+ // TotalShims is the total number of shims created
138+ TotalShims int
139+ }
140+
141+ // RuntimeShimInfo contains shim information for a single runtime
142+ type RuntimeShimInfo struct {
143+ RuntimeName string
144+ Shims []string
145+ }
146+
147+ // RehashCallback is called before processing each runtime
148+ // runtimeName is the internal name, displayName is the user-friendly name
149+ type RehashCallback func (runtimeName , displayName string )
150+
151+ // RehashWithCallback regenerates all shims, calling the callback before each runtime
152+ func (m * Manager ) RehashWithCallback (callback RehashCallback ) (* RehashResult , error ) {
135153 paths := config .DefaultPaths ()
136154 versionsDir := paths .Versions
137155
138156 // Read all runtime directories
139157 entries , err := os .ReadDir (versionsDir )
140158 if err != nil {
141159 if os .IsNotExist (err ) {
142- return fmt .Errorf ("no versions directory found - no runtimes installed yet" )
160+ return nil , fmt .Errorf ("no versions directory found - no runtimes installed yet" )
143161 }
144- return fmt .Errorf ("failed to read versions directory: %w" , err )
162+ return nil , fmt .Errorf ("failed to read versions directory: %w" , err )
145163 }
146164
147165 // Collect shim-to-runtime mappings (shim name -> runtime name)
148166 shimMap := make (ShimMap )
167+ // Also track shims by runtime for reporting
168+ shimsByRuntime := make (map [string ][]string )
149169
150170 for _ , entry := range entries {
151171 if ! entry .IsDir () {
@@ -161,6 +181,29 @@ func (m *Manager) Rehash() error {
161181 continue
162182 }
163183
184+ // Skip if no versions installed
185+ hasVersions := false
186+ for _ , ve := range versionEntries {
187+ if ve .IsDir () {
188+ hasVersions = true
189+ break
190+ }
191+ }
192+ if ! hasVersions {
193+ continue
194+ }
195+
196+ // Get display name from provider
197+ displayName := runtimeName
198+ if provider , err := runtimepkg .Get (runtimeName ); err == nil {
199+ displayName = provider .DisplayName ()
200+ }
201+
202+ // Call the callback before processing this runtime
203+ if callback != nil {
204+ callback (runtimeName , displayName )
205+ }
206+
164207 // For each installed version, scan for executables
165208 for _ , versionEntry := range versionEntries {
166209 if ! versionEntry .IsDir () {
@@ -173,13 +216,15 @@ func (m *Manager) Rehash() error {
173216 coreShims := RuntimeShims (runtimeName )
174217 for _ , shimName := range coreShims {
175218 shimMap [shimName ] = runtimeName
219+ shimsByRuntime [runtimeName ] = appendUnique (shimsByRuntime [runtimeName ], shimName )
176220 }
177221
178222 // Then, scan bin directory for globally installed packages
179223 binDir := filepath .Join (versionDir , "bin" )
180224 if execs , err := findExecutables (binDir ); err == nil {
181225 for _ , exec := range execs {
182226 shimMap [exec ] = runtimeName
227+ shimsByRuntime [runtimeName ] = appendUnique (shimsByRuntime [runtimeName ], exec )
183228 }
184229 }
185230
@@ -189,36 +234,56 @@ func (m *Manager) Rehash() error {
189234 if execs , err := findExecutables (versionDir ); err == nil {
190235 for _ , exec := range execs {
191236 shimMap [exec ] = runtimeName
237+ shimsByRuntime [runtimeName ] = appendUnique (shimsByRuntime [runtimeName ], exec )
192238 }
193239 }
194240 // Check Scripts directory for Python pip packages
195241 scriptsDir := filepath .Join (versionDir , "Scripts" )
196242 if execs , err := findExecutables (scriptsDir ); err == nil {
197243 for _ , exec := range execs {
198244 shimMap [exec ] = runtimeName
245+ shimsByRuntime [runtimeName ] = appendUnique (shimsByRuntime [runtimeName ], exec )
199246 }
200247 }
201248 }
202249 }
203250 }
204251
205252 if len (shimMap ) == 0 {
206- return fmt .Errorf ("no runtimes installed - nothing to reshim" )
253+ return nil , fmt .Errorf ("no runtimes installed - nothing to reshim" )
207254 }
208255
209256 // Save the shim map cache
210257 if err := SaveShimMap (shimMap ); err != nil {
211- return fmt .Errorf ("failed to save shim map cache: %w" , err )
258+ return nil , fmt .Errorf ("failed to save shim map cache: %w" , err )
212259 }
213260
214261 // Create all shims
215262 for shimName := range shimMap {
216263 if err := m .CreateShim (shimName ); err != nil {
217- return err
264+ return nil , err
218265 }
219266 }
220267
221- return nil
268+ return & RehashResult {
269+ ShimsByRuntime : shimsByRuntime ,
270+ TotalShims : len (shimMap ),
271+ }, nil
272+ }
273+
274+ // Rehash regenerates all shims by scanning installed versions (no progress callback)
275+ func (m * Manager ) Rehash () (* RehashResult , error ) {
276+ return m .RehashWithCallback (nil )
277+ }
278+
279+ // appendUnique appends a string to a slice only if it's not already present
280+ func appendUnique (slice []string , s string ) []string {
281+ for _ , existing := range slice {
282+ if existing == s {
283+ return slice
284+ }
285+ }
286+ return append (slice , s )
222287}
223288
224289// copyFile copies a file from src to dst
0 commit comments