#lang racket/unit (require racket/class racket/contract racket/list "sig.rkt" "../preferences.rkt" mred/mred-sig) (import mred^ [prefix preferences: framework:preferences^] [prefix exit: framework:exit^] [prefix group: framework:group^] [prefix handler: framework:handler^] [prefix editor: framework:editor^] [prefix color-prefs: framework:color-prefs^] [prefix racket: framework:racket^] [prefix early-init: framework:early-init^] [prefix color: framework:color^]) (export framework:main^) (init-depend framework:preferences^ framework:exit^ framework:editor^ framework:color-prefs^ framework:racket^ framework:early-init^) (preferences:low-level-get-preference preferences:get-preference/gui) (preferences:low-level-put-preferences preferences:put-preferences/gui) (application-preferences-handler (λ () (preferences:show-dialog))) (preferences:set-default 'framework:color-scheme 'classic symbol?) (preferences:set-default 'framework:column-guide-width '(#f 102) (list/c boolean? (and/c exact-integer? (>=/c 2)))) (preferences:set-default 'framework:aspell-dict #f (λ (x) (or (not x) (string? x)))) (preferences:set-default 'framework:line-spacing-add-gap? (not (eq? (system-type) 'windows)) boolean?) ;; used to time how long it takes to set a preference; the value is not actually used. (preferences:set-default 'drracket:prefs-debug #f (λ (x) #t)) ;; 'framework:spell-check-on? is only for people who had set ;; prefs in old versions; it isn't used except to provide the ;; default values for the newer prefs: 'framework:spell-check-strings? ;; and 'framework:spell-check-text? (preferences:set-default 'framework:spell-check-on? #f boolean?) (preferences:set-default 'framework:spell-check-strings? (preferences:get 'framework:spell-check-on?) boolean?) (preferences:set-default 'framework:spell-check-text? (preferences:get 'framework:spell-check-on?) boolean?) (preferences:set-default 'framework:always-use-platform-specific-linefeed-convention #f boolean?) (preferences:set-default 'framework:overwrite-mode-keybindings #f boolean?) (preferences:set-default 'framework:ask-about-paste-normalization #t boolean?) (preferences:set-default 'framework:do-paste-normalization #t boolean?) (preferences:set-default 'framework:replace-visible? #f boolean?) (preferences:set-default 'framework:anchored-search #f boolean?) (let ([search/replace-string-predicate (λ (l) (and (list? l) (andmap (λ (x) (or (string? x) (is-a? x snip%))) l)))]) (preferences:set-default 'framework:search-string '() search/replace-string-predicate) (preferences:set-default 'framework:replace-string '() search/replace-string-predicate)) ;; marshalling for this one will just lose information. Too bad. (preferences:set-un/marshall 'framework:search-string (λ (l) (map (λ (x) (if (is-a? x snip%) (send x get-text 0 (send x get-count)) x)) l)) values) (preferences:set-default 'framework:paren-color-scheme 'basic-grey symbol?) (define cond/offset-defaults '(("case-lambda" 0) ("match-lambda" 0) ("match-lambda*" 0) ("cond" 0) ("field" 0) ("provide/contract" 0) ("match" 1) ("new" 1) ("case" 1) ("datum-case" 1) ("match" 1) ("match*" 1) ("syntax-rules" 1) ("syntax-case" 2) ("syntax-case*" 3) ("kernel-syntax-case" 2) ("kernel-syntax-case*" 3))) (preferences:set-default 'framework:square-bracket:cond/offset cond/offset-defaults (listof (list/c string? exact-nonnegative-integer?))) (preferences:set-un/marshall 'framework:square-bracket:cond/offset (λ (val) (define deletions (for/list ([line (in-list cond/offset-defaults)] #:unless (ormap (λ (val-line) (equal? (car line) (car val-line))) val)) (list-ref line 0))) (define additions/changes (for/list ([line (in-list val)] #:when (not (member line cond/offset-defaults))) line)) (list additions/changes deletions)) (λ (marsh) (cond [((listof (list/c string? exact-nonnegative-integer?)) marsh) ;; old style prefs: don't try to find any deletions, as they are ;; probably caused by a stale defaults setting (define ht (make-hash (map (λ (x) (cons (list-ref x 0) (list-ref x 1))) cond/offset-defaults))) (for ([line (in-list marsh)]) (hash-set! ht (list-ref line 0) (list-ref line 1))) (hash-map ht list)] [((list/c (listof (list/c string? exact-nonnegative-integer?)) (listof string?)) marsh) ;; new style-pref (define additions/changes (list-ref marsh 0)) (define deletions (list-ref marsh 1)) (define ht (make-hash (map (λ (x) (cons (list-ref x 0) (list-ref x 1))) cond/offset-defaults))) (for ([del (in-list deletions)]) (hash-remove! ht del)) (for/list ([line (in-list additions/changes)]) (hash-set! ht (list-ref line 0) (list-ref line 1))) (hash-map ht list)]))) (define (set-square-bracket-nonum-pref pref-sym defaults) (preferences:set-default pref-sym defaults (listof string?)) (preferences:set-un/marshall pref-sym (λ (val) (define additions '()) (define deletions '()) (for ([itm (in-list val)]) (unless (member itm defaults) (set! additions (cons itm additions)))) (for ([def (in-list defaults)]) (unless (member def val) (set! deletions (cons def deletions)))) (list additions deletions)) (λ (marshed) (cond [((listof string?) marshed) ;; this is the old preference; in this case ;; we ignore any deletions while unmarshalling ;; as those are likely caused by a defaults ;; set that got bigger (remove-duplicates (append marshed defaults))] [((list/c (listof string?) (listof string?)) marshed) (define additions (list-ref marshed 0)) (define deletions (list-ref marshed 1)) (append additions (remove* deletions defaults))])))) (set-square-bracket-nonum-pref 'framework:square-bracket:local '("local")) (define all-fors (let () (define base-fors '(for for/list for/hash for/hasheq for/hasheqv for/and for/or for/lists for/first for/last for/vector for/flvector for/sum for/product for/set)) (define untyped-fors (append base-fors (map (λ (x) (string->symbol (regexp-replace #rx"^for" (symbol->string x) "for*"))) base-fors))) (define all-fors (append untyped-fors (map (λ (x) (string->symbol (string-append (symbol->string x) ":"))) untyped-fors))) all-fors)) (define for/folds '("for/fold" "for/fold:" "for*/fold" "for*/fold:")) (set-square-bracket-nonum-pref 'framework:square-bracket:letrec (append (map symbol->string all-fors) for/folds '("let" "let*" "let-values" "let*-values" "let-syntax" "let-struct" "let-syntaxes" "match-let" "match-let*" "match-letrec" "letrec" "letrec-syntaxes" "letrec-syntaxes+values" "letrec-values" "parameterize" "parameterize*" "with-syntax" "with-handlers"))) (set-square-bracket-nonum-pref 'framework:square-bracket:for/fold for/folds) (preferences:set-default 'framework:white-on-black? #f boolean?) (preferences:set-default 'framework:case-sensitive-search? #f boolean?) (color-prefs:add-color-scheme-entry 'framework:basic-canvas-background "white" "black") (preferences:set-default 'framework:special-meta-key #f boolean?) (preferences:add-callback 'framework:special-meta-key (λ (p v) (map-command-as-meta-key v))) (map-command-as-meta-key (preferences:get 'framework:special-meta-key)) (preferences:set-default 'framework:fraction-snip-style 'mixed (λ (x) (memq x '(mixed improper decimal)))) (preferences:set-default 'framework:standard-style-list:font-name (cond [(equal? (system-type) 'macosx) (define preferred-font "Menlo") (define fl (get-face-list)) (if (member preferred-font fl) preferred-font (get-family-builtin-face 'modern))] [else (get-family-builtin-face 'modern)]) string?) (preferences:set-default 'framework:standard-style-list:font-size (vector (hash) (let* ([txt (make-object text%)] [stl (send txt get-style-list)] [bcs (send stl basic-style)]) (send bcs get-size))) (vector/c ;; font sizes for specific monitor configurations (hash/c ;; a particular monitor configuration: the widths and heights (non-empty-listof (list/c exact-nonnegative-integer? exact-nonnegative-integer?)) ;; the font size for that configuration (integer-in 0 255) #:flat? #t) ;; default font size, when none of the configs above apply (integer-in 0 255) #:flat? #t)) (preferences:set-un/marshall 'framework:standard-style-list:font-size values (λ (x) (if (exact-nonnegative-integer? x) ;; coerce old pref settings to new (vector (hash) x) x))) (preferences:set-default 'framework:standard-style-list:smoothing 'default (λ (x) (memq x '(unsmoothed partly-smoothed smoothed default)))) (preferences:set-default 'framework:standard-style-list:weight 'normal (λ (x) (memq x '(normal light bold)))) (editor:set-standard-style-list-pref-callbacks) (let ([gray-level ;; old gray-level 192 (if (eq? (system-type) 'windows) (* 3/4 256) (- (* 7/8 256) 1))]) (define default-color (make-object color% 0 0 0 (- 1. (/ gray-level 255)))) (define w-o-b-default-color (make-object color% 255 255 255 (/ 50 255))) (color-prefs:add-color-scheme-entry 'framework:paren-match-color default-color w-o-b-default-color) ;; when the preference is currently set to the old color, ;; then just update it to the new one (if someone really ;; wants the old default, they can still have a color that is ;; off by one from the old default which should be ok) (define current-color (color-prefs:lookup-in-color-scheme 'framework:paren-match-color)) (cond [(and (= (send current-color red) gray-level) (= (send current-color green) gray-level) (= (send current-color blue) gray-level) (= (send current-color alpha) 1.0)) (color-prefs:set-in-color-scheme 'framework:paren-match-color default-color)] [(and (= (send current-color red) 50) (= (send current-color green) 50) (= (send current-color blue) 50) (= (send current-color alpha) 1.0)) (color-prefs:set-in-color-scheme 'framework:paren-match-color w-o-b-default-color)])) (preferences:set-default 'framework:recently-opened-files/pos null (λ (x) (and (list? x) (andmap (λ (x) (and (list? x) (= 3 (length x)) (path? (car x)) (number? (cadr x)) (number? (caddr x)))) x)))) (preferences:set-un/marshall 'framework:recently-opened-files/pos (λ (l) (map (λ (ele) (cons (path->bytes (car ele)) (cdr ele))) l)) (λ (l) (let/ec k (unless (list? l) (k '())) (map (λ (x) (unless (and (list? x) (= 3 (length x)) (bytes? (car x)) (number? (cadr x)) (number? (caddr x))) (k '())) (cons (bytes->path (car x)) (cdr x))) l)))) (preferences:set-default 'framework:last-directory (find-system-path 'doc-dir) (λ (x) (or (not x) path-string?))) (preferences:set-un/marshall 'framework:last-directory (λ (x) (and (path? x) (path->bytes x))) (λ (x) (and (bytes? x) (bytes->path x)))) (preferences:set-default 'framework:recent-max-count 50 (λ (x) (and (number? x) (x . > . 0) (integer? x)))) (preferences:add-callback 'framework:recent-max-count (λ (p v) (handler:size-recently-opened-files v))) (preferences:set-default 'framework:last-url-string "" string?) (preferences:set-default 'framework:recently-opened-sort-by 'age (λ (x) (or (eq? x 'age) (eq? x 'name)))) (preferences:set-default 'framework:recent-items-window-w 400 number?) (preferences:set-default 'framework:recent-items-window-h 600 number?) (preferences:set-default 'framework:show-delegate? #f boolean?) (preferences:set-default 'framework:windows-mdi #f boolean?) (preferences:set-default 'framework:menu-bindings #t boolean?) (preferences:set-default 'framework:verify-change-format #f boolean?) (preferences:set-default 'framework:auto-set-wrap? #f boolean?) (preferences:set-default 'framework:display-line-numbers #t boolean?) (preferences:set-default 'framework:show-status-line #t boolean?) (preferences:set-default 'framework:col-offsets #f boolean?) (preferences:set-default 'framework:print-output-mode 'standard (λ (x) (or (eq? x 'standard) (eq? x 'postscript) (eq? x 'pdf)))) (preferences:set-default 'framework:highlight-parens #t boolean?) (preferences:set-default 'framework:fixup-parens #t boolean?) (preferences:set-default 'framework:fixup-open-parens #f boolean?) (preferences:set-default 'framework:paren-match #t boolean?) (let ([defaults-ht (make-hasheq)]) (for-each (λ (x) (hash-set! defaults-ht x 'for/fold)) '(for/fold for/fold: for*/fold for*/fold:)) (for-each (λ (x) (hash-set! defaults-ht x 'define)) '(struct local struct: define-struct: define-typed-struct define-struct/exec: define: pdefine: define-type define-predicate match-define)) (for-each (λ (x) (hash-set! defaults-ht x 'begin)) '(case-lambda case-lambda: pcase-lambda: match-lambda match-lambda* syntax-parser cond delay unit compound-unit compound-unit/sig public private override require inherit sequence)) (for-each (λ (x) (hash-set! defaults-ht x 'lambda)) `( cases instantiate super-instantiate syntax/loc quasisyntax/loc datum-case match match* match-let match-let* match-letrec λ lambda let let* letrec recur lambda/kw letrec-values with-syntax with-syntax* with-continuation-mark module module* module+ match match-let match-let* match-letrec let/cc let/ec letcc catch let-syntax letrec-syntax fluid-let-syntax letrec-syntaxes+values let: letrec: let*: let-values: letrec-values: let*-values: let/cc: let/ec: lambda: λ: plambda: opt-lambda: popt-lambda: splicing-let splicing-letrec splicing-let-values splicing-letrec-values splicing-let-syntax splicing-letrec-syntax splicing-let-syntaxes splicing-letrec-syntaxes splicing-letrec-syntaxes+values splicing-local splicing-syntax-parameterize do: kernel-syntax-case syntax-case syntax-case* syntax-rules syntax-id-rules syntax-parse let-signature fluid-let let-struct let-macro let-values let*-values case when unless let-enumerate class class* class-asi class-asi* class*/names class100 class100* class100-asi class100-asi* class100*/names rec make-object mixin define-some do opt-lambda send* with-method define-record catch shared unit/sig unit/lang with-handlers interface parameterize parameterize* call-with-input-file call-with-input-file* with-input-from-file with-input-from-port call-with-output-file with-output-to-file with-output-to-port for-all type-case)) (preferences:set-default 'framework:tabify (list defaults-ht #rx"^begin" #rx"^def" #rx"^for\\*?(/|$)" #f) (list/c (hash/c symbol? (or/c 'for/fold 'define 'begin 'lambda) #:flat? #t) (or/c #f regexp?) (or/c #f regexp?) (or/c #f regexp?) (or/c #f regexp?))) (define old-style-pred? (listof (list/c symbol? symbol?))) (define new-style-pred? (list/c (listof (list/c symbol? symbol?)) ;; additions to defaults (listof (list/c symbol? symbol?)))) ;; deletions (define pref-pred? (or/c (list/c new-style-pred? (or/c regexp? #f) (or/c regexp? #f) (or/c regexp? #f) (or/c regexp? #f)) (list/c (or/c old-style-pred? new-style-pred?) (or/c regexp? #f) (or/c regexp? #f) (or/c regexp? #f)))) (define (ht->addition/deletion-lists ht) (define additions '()) (define deletions '()) (for ([(k v) (in-hash ht)]) (unless (hash-ref defaults-ht k #f) (set! additions (cons (list k v) additions)))) (for ([(k v) (in-hash defaults-ht)]) (unless (hash-ref ht k #f) (set! deletions (cons (list k v) deletions)))) (list additions deletions)) (define (addition/deletion-lists->ht lsts) (define additions (list-ref lsts 0)) (define deletions (list-ref lsts 1)) (define ht (hash-copy defaults-ht)) (for ([pr (in-list deletions)]) (define k (list-ref pr 0)) (define v (list-ref pr 1)) (when (equal? (hash-ref ht k #f) v) (hash-remove! ht k))) (for ([pr (in-list additions)]) (define k (list-ref pr 0)) (define v (list-ref pr 1)) (hash-set! ht k v)) ht) (define (pad-to len lst) (cond [(null? lst) (build-list len (λ (x) #f))] [else (cons (car lst) (pad-to (- len 1) (cdr lst)))])) (preferences:set-un/marshall 'framework:tabify (λ (t) (cons (ht->addition/deletion-lists (list-ref t 0)) (cdr t))) (λ (l) (and (pref-pred? l) (cond [(old-style-pred? (list-ref l 0)) ;; when migrating prefs from the old style, ;; get rid of any apparent deletions, as ;; they are likely unintentional, a result ;; of moving defaults (define h (make-hasheq)) (for-each (λ (x) (apply hash-set! h x)) (list-ref l 0)) (define lsts (ht->addition/deletion-lists h)) (cons (addition/deletion-lists->ht (list (list-ref l 0) '())) (cdr l))] [else (cons (addition/deletion-lists->ht (list-ref l 0)) (pad-to 4 (cdr l)))]))))) (preferences:set-default 'framework:autosave-delay 30 number?) (preferences:set-default 'framework:autosaving-on? #t boolean?) (preferences:set-default 'framework:backup-files? #t boolean?) (preferences:set-default 'framework:verify-exit #t boolean?) (preferences:set-default 'framework:delete-forward? #t boolean?) (preferences:set-default 'framework:show-periods-in-dirlist #f boolean?) (preferences:set-default 'framework:file-dialogs 'std (λ (x) (and (memq x '(common std)) #t))) (for ([line (in-list (racket:get-color-prefs-table))] [white-on-black-line (in-list (racket:get-white-on-black-color-prefs-table))]) (define sym (car line)) (define color (cadr line)) (define white-on-black-color (cadr white-on-black-line)) (color-prefs:add-color-scheme-entry (racket:short-sym->pref-name sym) #:style (racket:short-sym->style-name sym) color white-on-black-color)) (preferences:set-default 'framework:coloring-active #t boolean?) (color-prefs:add-color-scheme-entry 'framework:default-text-color "black" "white") (color-prefs:register-color-scheme-entry-change-callback 'framework:basic-canvas-background (λ (v) (editor:set-default-font-color (color-prefs:lookup-in-color-scheme 'framework:default-text-color) v))) (color-prefs:register-color-scheme-entry-change-callback 'framework:default-text-color (λ (v) (editor:set-default-font-color v (color-prefs:lookup-in-color-scheme 'framework:basic-canvas-background)))) (editor:set-default-font-color (color-prefs:lookup-in-color-scheme 'framework:default-text-color) (color-prefs:lookup-in-color-scheme 'framework:basic-canvas-background)) (color-prefs:add-color-scheme-entry 'framework:misspelled-text-color "black" "white") (color-prefs:set-default/color-scheme 'framework:delegatee-overview-color "light blue" (make-object color% 62 67 155)) (let ([delta (make-object style-delta%)] [style (send (editor:get-standard-style-list) find-named-style color:misspelled-text-color-style-name)]) (if style (send style set-delta delta) (send (editor:get-standard-style-list) new-named-style color:misspelled-text-color-style-name (send (editor:get-standard-style-list) find-or-create-style (send (editor:get-standard-style-list) find-named-style "Standard") delta)))) (let ([update-style-list (λ (v) (define sl (editor:get-standard-style-list)) (define style (send sl find-named-style color:misspelled-text-color-style-name)) (define delta (new style-delta%)) (send style get-delta delta) (send delta set-delta-foreground v) (send style set-delta delta))]) (color-prefs:register-color-scheme-entry-change-callback 'framework:misspelled-text-color (λ (v) (update-style-list v))) (update-style-list (color-prefs:lookup-in-color-scheme 'framework:misspelled-text-color))) ;; groups (preferences:set-default 'framework:exit-when-no-frames #t boolean?) (unless (preferences:get 'framework:exit-when-no-frames) (preferences:set 'framework:exit-when-no-frames #t)) (exit:insert-can?-callback (λ () (send (group:get-the-frame-group) can-close-all?))) (exit:insert-on-callback (λ () (send (group:get-the-frame-group) on-close-all))) ;; reset these -- they are only for the test suite. ;; they do not need to be set across starting up and shutting down ;; the application. ;(preferences:set 'framework:file-dialogs 'std)