Make Preferences standalone in app:utils - #1563
Open
diyaayay wants to merge 8 commits into
Open
Conversation
The bundled defaults are loaded from the classpath, so shipping them inside the app:utils jar lets the standalone Preferences (upcoming) resolve its own defaults without the app being present. All existing readers load the file via getResourceAsStream() and are unaffected.
storage half of app.Preferences: defaults from classpath, load/save, platform-specific keys. throws instead of showing dialogs; init split so the app can insert its own defaults between stages. follows processing#1209.
app keeps fonts/colors, dialogs, and proxy/native-chooser side effects in their original startup order; loading and saving now go through the standalone class, with the settings folder passed in from Base.
replaces the per-call file re-read (platform charset, no defaults) with the standalone class, so the preprocessor resolves preferences from the bundled defaults even without a preferences.txt.
set()/unset() notify registered listeners when a value actually changes; loading stays silent. per the processing#1104 todo list.
covers defaults loading, first-run creation, save/load round trips, the preferences.file override, platform-specific keys, backslash normalization, getInteger fallback, sorted save, the 3.x sketchbook migration, and the change listener contract. adds a package-private reset() for test isolation.
found while smoke-testing the utils jar standalone: the PDE and the unit tests both pre-create the settings folder, but a standalone caller passing a new location would fail on the first save.
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.
Resolves #1104
Splits
processing.app.Preferencesinto a standalone storage class (processing.utils.Preferencesinapp:utils) and an app-side facade, so preferences work in contexts without the PDE: the Gradle plugin, CLI tools, and the preprocessor, as motivated in #1104 and the standalone-CLI discussion in #1522.Changes
processing.utils.Preferences: the storage half of the old class. Bundled defaults from the classpath, reading/writingpreferences.txt, platform-specific keys, and the 3.x sketchbook migration. JDK-only (nocore, no AWT/Swing). Errors are reported by throwingIOExceptionwith the cause chained instead of showing dialogs, so callers decide how to react.processing.app.Preferencesbecomes a facade: keeps fonts/colors,Messagesdialogs, and the proxy/native-chooser side effects in their original startup order, delegating storage to the utils class. No call sites change (~246 acrossappandjava).defaults.txtmoves intoapp:utilsresources: the published utils jar now carries its own defaults and works standalone. All readers (including the ComposePreferencesProvider) load it viagetResourceAsStream, so nothing else changes.Platform.getName(): platform name for preference-key suffixes, mirroringPConstants.platformNames. The four strings are part of the preferences file format, so a small mirror avoids givingapp:utilsacoredependency.addChangeListener/removeChangeListeneron the utils class. Fires only on real changes fromset()/unset(); bulk loading is silent; a throwing listener can't block the change or other listeners. No consumers wired yet. First candidates are PDE components that currently re-read on window close, and possibly converging with the Compose side'sPreferencesEventslater.java:preprocessor'sprocessing.app.Preferencesused to re-readpreferences.txton every call with the platform charset and had no defaults, so a standalone preprocessor could crash ongetInteger("editor.tabs.size")with no prefs file present. It now resolves from the bundled defaults. Happy to split this commit into a follow-up PR if preferred.Design notes
:app(Base/Platform) whilePreferenceswas moving to:app:utils, so each module needed the other. Since then, RefactoringSketchExceptionto be available outside ofapp#1196 createdapp:utilsand Rewrite of theBase.getSettingsFolder()andPlatform.getSettingsFolder()#1335 moved settings-folder resolution intoprocessing.utils.Settings, so the knowledgePreferencesneeds now lives below it and all dependency arrows point one way. This PR adds no new dependencies on top of that: the remaining app couplings are handled by throwing instead of dialogs, and by passing the settings folder in as an argument (loadUserPrefs(File)), withSettings.getFolder()and theprocessing.app.preferences.filesystem property as fallbacks for standalone use.run.window.bgcolor, CJK input-method support) between loading the bundled defaults and the user's file, so init is split intoloadDefaults()/loadUserPrefs(File), withinit(File)composing them for standalone consumers. This keeps the PDE's startup order exactly as onmain.extendsrelationship would let calls through the parent type silently skip the app's error dialogs. The facade delegates explicitly; the cost is fully-qualified names (Java can't alias same-named imports), which was preferred over renaming a class and churning every reference.preferences.txtsurfaces as an exception (the PDE shows the same error dialog as before), and the utils class won't run the sketchbook migration/save over a file it couldn't read.Builds on the direction @AhmedMagedC explored in #1209, thank you for the groundwork! Rebuilt on today's
mainsince that branch predates theapp:utilsmodule: delegation instead of static inheritance, chainedIOExceptions instead of a custom exception, nocoredependency, and defaults bundled in the utils jar.Tests
app:utils(PreferencesTest): default loading, file creation, and backwards compatibility (3.x sketchbook migration, backslash normalization, platform-suffix keys), plus save/load round trips, thepreferences.fileoverride,getIntegerfallback, sorted save, and the listener contract.app:utils,app(incl.PreferencesKtTest, so the Compose provider still finds the moveddefaults.txt), andjava(incl.ParserTeststhrough the preprocessor).Checklist