Catalogue resolver + first-launch bundle installer sheet - #3
Merged
Conversation
Bumps Bundle Support pinned SHA in MandatoryBundles.h to the merge commit of textmatelives/bundle-support.tmbundle#1 (1663f664), which adds Support/DefaultBundles.plist, Support/AvailableBundles.plist, Support/BundleFileTypeIndex.plist, and Support/build_filetype_index.rb to the bundle. The app no longer carries those three plists or the generator script. New + (NSString*)pathForCatalogueResource: on BundleRegistry resolves a basename (DefaultBundles.plist / AvailableBundles.plist / BundleFileTypeIndex.plist) to an on-disk path. It prefers the managed install at ~/Library/Application Support/TextMate/Managed/Bundles/ Bundle Support.tmbundle/Support/<file>.plist, falling back to the embedded copy under <App>/Contents/SharedSupport/Bundles/ Bundle Support.tmbundle/Support/<file>.plist for first launch and offline. Returns nil if neither exists. Callsites switched: BundleRegistry -seedShippedDefaults, -seedAvailableBundles, -fileTypeIndex; BundlesManager -shippedDefaultsByUUID. The initForTestingWithSpecs:fileTypeIndexPath: seam still takes an explicit path, so existing unit tests need no other changes. Embedded Bundle Support copy refreshed via bin/fetch_embedded_bundles.sh at the new SHA. The fetch script now also scrubs .github/ (CI metadata, no runtime use) and Support/shared/bin/CocoaDialog.app/ (Intel-only, blocks notarization — removed in commit 297d39d but the tarball re-extracts it on every SHA bump). Catalogue + extension updates now ship via the existing 3h bundle auto-update path rather than a notarized app release.
Picks up textmatelives/bundle-support.tmbundle#2 (the description backfill for default-tier bundles — 40/40 entries now carry description fields pulled from each bundle's own info.plist and normalized HTML→plain to match the available-tier format already in place). - MandatoryBundles.h: pin 1663f664 → 8ca9ddb. - Applications/TextMate/support/Bundles/Bundle Support.tmbundle/: re-fetched at the new SHA via bin/fetch_embedded_bundles.sh. Brings in the populated Support/DefaultBundles.plist and the new Support/backfill_descriptions.rb helper. No code change. With the resolver introduced earlier in this branch, the app loads catalogue descriptions either from the managed install or from this embedded copy at cold start.
NSBackgroundActivityScheduler is the only entry point that drives default-tier bundle installation, and it doesn't fire at t=0 — it waits at least its 3-hour interval and then only when the system feels idle. On a fresh install that meant default bundles (Python, Ruby, Git, Rave, …) wouldn't appear for hours, even though they're listed in DefaultBundles.plist and registered in Bundles.plist. This commit adds a modeless floating window that fires once on first launch (gated by kUserDefaultsDidPromptForDefaultBundlesKey), lists every uninstalled default-tier bundle (filtered by TMBundleOriginShipped + !installedSHA + !in BundlesToNeverSuggest), pre-checks them, and lets the user kick off a batch install via -[BundlesManager installSpecs:]. Window stays non-modal on purpose: the install path is async and NSURLSession delegates run on the main NSOperationQueue, which a runModalForWindow: session would block — exactly the deadlock the prototype hit. NSFloatingWindowLevel + activateIgnoringOtherApps: gives it the "prominent" feel without the deadlock. Keys: ⏎ activates Install Selected; ⎋ activates Skip. Space toggles the focused row's checkbox via a tiny NSTableView subclass. Skip records every candidate UUID into kUserDefaultsBundlesToNeverSuggestKey so the on-demand per-extension prompt (SelectGrammarViewController) doesn't ambush the user later. Install Selected records unchecked rows the same way. Either button flips kUserDefaultsDidPromptForDefaultBundlesKey so we never re-prompt. Progress: NSProgress.completedUnitCount via KVO drives a determinate bar + "Installed N of M…" label. Tested with full ~/Library/Application Support/TextMate + ~/Library/Caches/com.macromates.TextMate + prefs scrub: sheet appears, 40 default-tier bundles listed (incl. promoted Rave), install completes, registry and managed/Bundles directory populate correctly, on-demand prompt still fires for .yml etc. when their bundle is unchecked.
dayglojesus
force-pushed
the
fix-bundle-fileindex
branch
from
May 23, 2026 01:56
b856e06 to
0932d14
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands the textmate-side half of the bundle-catalogue refactor and adds a first-launch UX for getting the default-tier bundles onto a fresh install. Three commits:
Bundle Support.tmbundle— companion to textmatelives/bundle-support.tmbundle#1. Stops shippingDefaultBundles.plist,AvailableBundles.plist, andBundleFileTypeIndex.plistas app resources; replaces them with a runtime resolver that prefers the managed install at~/Library/Application Support/TextMate/Managed/Bundles/Bundle Support.tmbundle/Support/<file>and falls back to the embedded copy under<App>/Contents/SharedSupport/Bundles/Bundle Support.tmbundle/Support/<file>. Catalogue + index updates ride the existing 3h bundle auto-update path instead of requiring a notarized app release.8ca9ddb— picks up textmatelives/bundle-support.tmbundle#2 (the description backfill: 40/40 default-tier entries now carry descriptions normalized from each bundle's owninfo.plist). Re-fetches the embedded copy at the new SHA.Why the first-launch sheet
BundlesManager.initschedules default-tier auto-installs viaNSBackgroundActivitySchedulerwith a 3-hour interval. The scheduler is opportunistic — it doesn't fire att=0; it waits at least the interval, and then only when the system feels idle. So a freshly-installed TextMate didn't show Python, Ruby, Git, etc. for hours, even though they were already registered inBundles.plist. (Pre-existing behaviour, surfaced by the catalogue refactor when we tested cold-start.)The sheet:
DidPromptForDefaultBundlesuser default.TMBundleOriginShippedbundle (filtered by!installedSHAand!in BundlesToNeverSuggest), pre-checked, with category and description columns.[BundlesManager installSpecs:]and shows a determinate progress bar driven byNSProgress.completedUnitCountvia KVO.BundlesToNeverSuggestso the on-demand per-extension prompt (SelectGrammarViewController) won't ambush the user later. Install Selected does the same for any unchecked rows.NSTableViewsubclass).NSFloatingWindowLevel.runModalForWindow:was a no-go — it blocks the mainNSOperationQueuethat theBundleArchiveTaskURLSession delegates run on (BundleFetcher.mm:78), and the install would never complete.Code surface
New
Applications/TextMate/src/FirstLaunchBundleInstaller.{h,mm}— the window controller, candidate filter, table data source, install kickoff.Modified
Frameworks/BundlesManager/src/{BundleRegistry,BundlesManager}.{h,mm}— resolver+[BundleRegistry pathForCatalogueResource:], callsites switched inseedShippedDefaults/seedAvailableBundles/fileTypeIndex/shippedDefaultsByUUID, newkUserDefaultsDidPromptForDefaultBundlesKey.Frameworks/BundlesManager/src/MandatoryBundles.h— Bundle Support pin7c779d06→8ca9ddb.Applications/TextMate/src/AppController.mm—[FirstLaunchBundleInstaller promptIfNeeded]fromapplicationDidFinishLaunching:.bin/fetch_embedded_bundles.sh— post-extract scrub of.github/(CI metadata, no runtime use) andSupport/shared/bin/CocoaDialog.app/(Intel-only, blocks notarization — already removed in 297d39d but the tarball re-extracted it on every SHA bump).Frameworks/BundlesManager/tests/t_filetype_lookup.mm— comment update (test seam unchanged; usesinitForTestingWithSpecs:fileTypeIndexPath:).Deleted
Applications/TextMate/resources/DefaultBundles.plistApplications/TextMate/resources/AvailableBundles.plistApplications/TextMate/resources/BundleFileTypeIndex.plistbin/build_filetype_index.rbEmbedded bundle refresh
Applications/TextMate/support/Bundles/Bundle Support.tmbundle/re-fetched at8ca9ddb. Includes populatedSupport/DefaultBundles.plist, the regeneratedBundleFileTypeIndex.plist, and the newSupport/backfill_descriptions.rb.Test plan
ninja BundlesManager/test— 10/10 pass.ninja document/test— 9/9 pass.ninja TextMate— clean full build, signed.<App>/Contents/Resources/confirmed clean of the 3 catalogue plists.<App>/Contents/SharedSupport/Bundles/Bundle Support.tmbundle/Support/confirmed carrying the 3 plists + generator + backfill script.~/Library/Application Support/TextMate+ caches + prefs, launch built app):.ymlopen triggers on-demand install prompt for YAML when it was unchecked at first launch.Out of scope
Applications/TextMate/resources/DefaultBundles.tbz.bl+ the derivedDefaultBundles.tbz— legacy installer payload, no remaining references. Cleanup deferred.bin/generate_available_bundles.rb— not audited as part of this PR.