* Fixed some typos in the `preferences:low-level-put-preferences' doc

(used `put-preference' not the plural form).

* Added `preferences:low-level-get-preference' that is set by default
  to the `get-preference'.  (Together with the previous one it is
  possible to setup things so preferences are kept in a hash table
  instead of on disk.)

* The `preferences:get' function will try to read a (marshalled) value
  from the preferences if there is no value set, and the `marshalled'
  hash table is gone (it was used only for initial values of
  preferences).

  This means that the preference file is not consulted until the
  preference value is needed, which makes reading the file more lazy.
  More importantly, if some user application sets the
  `preferences:low-level-get-preference' hook, then the newly
  installed hook will be used to read the initial values.  This is
  important since just registering a preference (via
  `preferences:set-default') would already read the preference to the
  `marshalled' hash table -- and many such preferences are registered
  at various module top-levels, so this would happen before the user
  code had any chance of changing the low-level get function.

  The only visible effect of this change outside of this module is
  that preferences are read more lazily from the file.  For example,
  if you start DrScheme and then remove the preference file and then
  search, you will not see your saved search string because.  (Before
  this change, the saved search string would have been read on
  startup, so its value was read before you removed the file.)

* Delayed reading of the old-preferences until needed for similar
  reasons.

* Reformatted some of the documentation strings.

svn: r14716

original commit: 17d64755a266693666db7ad2977dd4ed238b7b1a
This commit is contained in:
Eli Barzilay 2009-05-05 05:09:21 +00:00
parent e3dda16aa3
commit 36add1d173

View File

@ -38,12 +38,18 @@ the state transitions / contracts are:
(define exn:make-unknown-preference make-exn:unknown-preference) (define exn:make-unknown-preference make-exn:unknown-preference)
(define exn:struct:unknown-preference struct:exn:unknown-preference) (define exn:struct:unknown-preference struct:exn:unknown-preference)
(define preferences:low-level-put-preferences (make-parameter put-preferences))
(define preferences:low-level-get-preference (make-parameter get-preference))
(define old-preferences-symbol 'plt:framework-prefs) (define old-preferences-symbol 'plt:framework-prefs)
(define old-preferences (make-hasheq)) ;; reading is delayed, in case the low-level parameter is changed
(let ([old-prefs (get-preference old-preferences-symbol (λ () '()))]) (define old-preferences #f)
(for-each (define (init-old-preferences)
(λ (line) (hash-set! old-preferences (car line) (cadr line))) (unless old-preferences
old-prefs)) (set! old-preferences (make-hasheq))
(for ([line (in-list ((preferences:low-level-get-preference)
old-preferences-symbol (λ () '())))])
(hash-set! old-preferences (car line) (cadr line)))))
(define (add-pref-prefix p) (string->symbol (format "plt:framework-pref:~a" p))) (define (add-pref-prefix p) (string->symbol (format "plt:framework-pref:~a" p)))
@ -51,12 +57,6 @@ the state transitions / contracts are:
;; the current values of the preferences ;; the current values of the preferences
(define preferences (make-hasheq)) (define preferences (make-hasheq))
;; marshalled : hash-table[sym -o> any]
;; the values of the preferences, as read in from the disk
;; each symbol will only be mapped in one of the preferences
;; hash-table and this hash-table, but not both.
(define marshalled (make-hasheq))
;; marshall-unmarshall : sym -o> un/marshall ;; marshall-unmarshall : sym -o> un/marshall
(define marshall-unmarshall (make-hasheq)) (define marshall-unmarshall (make-hasheq))
@ -93,18 +93,24 @@ the state transitions / contracts are:
(cond (cond
[(pref-default-set? p) [(pref-default-set? p)
;; unmarshall, if required (unless (hash-has-key? preferences p)
(when (hash-has-key? marshalled p) ;; first time reading this, check the file, unmarshall if required
;; if `preferences' is already bound, that means the unmarshalled value isn't useful. (let/ec k
(unless (hash-has-key? preferences p) ;; if there is no preference saved, we just don't do anything.
(hash-set! preferences p (unmarshall-pref p (hash-ref marshalled p)))) ;; the code below notices this case.
(hash-remove! marshalled p)) (let ([marshalled ((preferences:low-level-get-preference)
(add-pref-prefix p) (λ () (k (void))))])
(hash-set! preferences p (unmarshall-pref p marshalled)))))
;; initialize old-preferences if needed
(init-old-preferences)
;; if there is no value in the preferences table, but there is one ;; if there is no value in the preferences table, but there is one
;; in the old version preferences file, take that: ;; in the old version preferences file, take that:
(unless (hash-has-key? preferences p) (unless (hash-has-key? preferences p)
(when (hash-has-key? old-preferences p) (when (hash-has-key? old-preferences p)
(hash-set! preferences p (unmarshall-pref p (hash-ref old-preferences p))))) (hash-set! preferences p
(unmarshall-pref p (hash-ref old-preferences p)))))
;; clear the pref from the old table (just in case it was taking space -- we don't need it anymore) ;; clear the pref from the old table (just in case it was taking space -- we don't need it anymore)
(when (hash-has-key? old-preferences p) (when (hash-has-key? old-preferences p)
@ -155,8 +161,6 @@ the state transitions / contracts are:
values)) values))
(void)) (void))
(define preferences:low-level-put-preferences (make-parameter put-preferences))
(define (raise-unknown-preference-error sym fmt . args) (define (raise-unknown-preference-error sym fmt . args)
(raise (exn:make-unknown-preference (raise (exn:make-unknown-preference
(string-append (format "~a: " sym) (apply format fmt args)) (string-append (format "~a: " sym) (apply format fmt args))
@ -243,12 +247,7 @@ the state transitions / contracts are:
(unless default-okay? (unless default-okay?
(error 'set-default "~s: checker (~s) returns ~s for ~s, expected #t~n" (error 'set-default "~s: checker (~s) returns ~s for ~s, expected #t~n"
p checker default-okay? default-value)) p checker default-okay? default-value))
(hash-set! defaults p (make-default default-value checker)) (hash-set! defaults p (make-default default-value checker)))]
(let/ec k
(let ([m (get-preference (add-pref-prefix p) (λ () (k (void))))])
;; if there is no preference saved, we just don't do anything.
;; `get' notices this case.
(hash-set! marshalled p m))))]
[(not (pref-can-init? p)) [(not (pref-can-init? p))
(error 'preferences:set-default (error 'preferences:set-default
"tried to call set-default for preference ~e but it cannot be configured any more" "tried to call set-default for preference ~e but it cannot be configured any more"
@ -350,83 +349,77 @@ the state transitions / contracts are:
((p f) ((p f)
((weak? #f))) ((weak? #f)))
@{This function adds a callback which is called with a symbol naming a @{This function adds a callback which is called with a symbol naming a
preference and its value, when the preference changes. preference and its value, when the preference changes.
@scheme[preferences:add-callback] returns a thunk, which when @scheme[preferences:add-callback] returns a thunk, which when
invoked, removes the callback from this preference. invoked, removes the callback from this preference.
If @scheme[weak?] is true, the preferences system will only hold on to If @scheme[weak?] is true, the preferences system will only hold on to
the callback weakly. the callback weakly.
The callbacks will be called in the order in which they were added. The callbacks will be called in the order in which they were added.
If you are adding a callback for a preference that requires If you are adding a callback for a preference that requires
marshalling and unmarshalling, you must set the marshalling and marshalling and unmarshalling, you must set the marshalling and
unmarshalling functions by calling unmarshalling functions by calling
@scheme[preferences:set-un/marshall] before adding a callback. @scheme[preferences:set-un/marshall] before adding a callback.
This function raises This function raises
@index['("exn:unknown-preference")]{@scheme[exn:unknown-preference]} @index['("exn:unknown-preference")]{@scheme[exn:unknown-preference]}
@scheme[exn:unknown-preference] @scheme[exn:unknown-preference]
if the preference has not been set.}) if the preference has not been set.})
(proc-doc/names (proc-doc/names
preferences:set-default preferences:set-default
(symbol? any/c (any/c . -> . any) . -> . void?) (symbol? any/c (any/c . -> . any) . -> . void?)
(symbol value test) (symbol value test)
@{This function must be called every time your application starts up, before any call to @{This function must be called every time your application starts up, before
@scheme[preferences:get] or any call to @scheme[preferences:get] or @scheme[preferences:set]
@scheme[preferences:set] (for any given preference).
(for any given preference).
If you use @scheme[preferences:set-un/marshall],
If you use you must call this function before calling it.
@scheme[preferences:set-un/marshall],
you must call this function before calling it. This sets the default value of the preference @scheme[symbol] to
@scheme[value]. If the user has chosen a different setting,
This sets the default value of the preference @scheme[symbol] to the user's setting will take precedence over the default value.
@scheme[value]. If the user has chosen a different setting,
the user's setting The last argument, @scheme[test] is used as a safeguard. That function is
will take precedence over the default value. called to determine if a preference read in from a file is a valid
preference. If @scheme[test] returns @scheme[#t], then the preference is
The last argument, @scheme[test] is used as a safeguard. That function is treated as valid. If @scheme[test] returns @scheme[#f] then the default is
called to determine if a preference read in from a file is a valid used.})
preference. If @scheme[test] returns @scheme[#t], then the preference is
treated as valid. If @scheme[test] returns @scheme[#f] then the default is
used.})
(proc-doc/names (proc-doc/names
preferences:set-un/marshall preferences:set-un/marshall
(symbol? (any/c . -> . printable/c) (printable/c . -> . any/c) . -> . void?) (symbol? (any/c . -> . printable/c) (printable/c . -> . any/c) . -> . void?)
(symbol marshall unmarshall) (symbol marshall unmarshall)
@{@scheme[preference:set-un/marshall] is used to specify marshalling and @{@scheme[preference:set-un/marshall] is used to specify marshalling and
unmarshalling functions for the preference unmarshalling functions for the preference
@scheme[symbol]. @scheme[marshall] will be called when the users saves their @scheme[symbol]. @scheme[marshall] will be called when the users saves their
preferences to turn the preference value for @scheme[symbol] into a preferences to turn the preference value for @scheme[symbol] into a
printable value. @scheme[unmarshall] will be called when the user's printable value. @scheme[unmarshall] will be called when the user's
preferences are read from the file to transform the printable value preferences are read from the file to transform the printable value
into its internal representation. If @scheme[preference:set-un/marshall] into its internal representation. If @scheme[preference:set-un/marshall]
is never called for a particular preference, the values of that is never called for a particular preference, the values of that
preference are assumed to be printable. preference are assumed to be printable.
If the unmarshalling function returns a value that does not meet the If the unmarshalling function returns a value that does not meet the
guard passed to guard passed to @scheme[preferences:set-default]
@scheme[preferences:set-default] for this preference, the default value is used.
for this preference, the default value is used.
The @scheme[marshall] function might be called with any value returned
The @scheme[marshall] function might be called with any value returned from @scheme[read] and it must not raise an error
from @scheme[read] and it must not raise an error (although it can return arbitrary results if it gets bad input). This might
(although it can return arbitrary results if it gets bad input). This might happen when the preferences file becomes corrupted, or is edited
happen when the preferences file becomes corrupted, or is edited by hand.
by hand.
@scheme[preference:set-un/marshall] must be called before calling
@scheme[preference:set-un/marshall] must be called before calling @scheme[preferences:get],@scheme[preferences:set].})
@scheme[preferences:get],
@scheme[preferences:set].})
(proc-doc/names (proc-doc/names
preferences:restore-defaults preferences:restore-defaults
(-> void?) (-> void?)
() ()
@{@scheme[(preferences:restore-defaults)] @{@scheme[(preferences:restore-defaults)] restores the users' configuration
restores the users's configuration to the to the default preferences.})
default preferences.})
(proc-doc/names (proc-doc/names
exn:make-unknown-preference exn:make-unknown-preference
@ -442,28 +435,33 @@ the state transitions / contracts are:
(parameter-doc (parameter-doc
preferences:low-level-put-preferences preferences:low-level-put-preferences
(parameter/c (-> (listof symbol?) (listof any/c) any)) (parameter/c ((listof symbol?) (listof any/c) . -> . any))
put-preference put-preferences
@{This parameter's value @{This parameter's value is called to save preference the preferences file.
is called to save preference the preferences. Its interface should Its interface should be just like mzlib's @scheme[put-preferences].})
be just like mzlib's @scheme[put-preference].})
(parameter-doc
preferences:low-level-get-preference
(parameter/c (->* [symbol?] [(-> any)] any))
get-preference
@{This parameter's value is called to get a preference from the preferences
file. Its interface should be just like mzlib's @scheme[get-preference].})
(proc-doc/names (proc-doc/names
preferences:snapshot? preferences:snapshot?
(-> any/c boolean?) (-> any/c boolean?)
(arg) (arg)
@{Determines if its argument is a preferences snapshot. @{Determines if its argument is a preferences snapshot.
See also See also @scheme[preferences:get-prefs-snapshot] and
@scheme[preferences:get-prefs-snapshot] and @scheme[preferences:restore-prefs-snapshot].})
@scheme[preferences:restore-prefs-snapshot].})
(proc-doc/names (proc-doc/names
preferences:restore-prefs-snapshot preferences:restore-prefs-snapshot
(-> preferences:snapshot? void?) (-> preferences:snapshot? void?)
(snapshot) (snapshot)
@{Restores the preferences saved in @scheme[snapshot]. @{Restores the preferences saved in @scheme[snapshot].
See also @scheme[preferences:get-prefs-snapshot].}) See also @scheme[preferences:get-prefs-snapshot].})
(proc-doc/names (proc-doc/names
preferences:get-prefs-snapshot preferences:get-prefs-snapshot