diff --git a/collects/framework/private/frame.rkt b/collects/framework/private/frame.rkt index c3ab42c906..784580895c 100644 --- a/collects/framework/private/frame.rkt +++ b/collects/framework/private/frame.rkt @@ -921,6 +921,7 @@ overwrite-status-changed anchor-status-changed editor-position-changed + use-file-text-mode-changed add-line-number-menu-items)) (define text-info-mixin (mixin (info<%>) (text-info<%>) @@ -1077,12 +1078,24 @@ (define/public (add-line-number-menu-items menu) (void)) + (define/public (use-file-text-mode-changed) + (when (object? file-text-mode-msg) + (define ed (get-info-editor)) + (send file-text-mode-msg-parent change-children + (λ (l) + (if (and (is-a? ed text:info<%>) + (eq? (system-type) 'windows) + (send ed use-file-text-mode)) + (list file-text-mode-msg) + '()))))) + (define/override (update-info) (super update-info) (update-macro-recording-icon) (overwrite-status-changed) (anchor-status-changed) - (editor-position-changed)) + (editor-position-changed) + (use-file-text-mode-changed)) (super-new) (inherit get-info-panel) @@ -1093,14 +1106,25 @@ [stretchable-width #f] [stretchable-height #f] [extra-menu-items (λ (menu) (add-line-number-menu-items menu))])) - (define position-canvas (new position-canvas% [parent position-parent] [init-width "000:00-000:00"])) + (define position-canvas (new position-canvas% + [parent position-parent] + [init-width "000:00-000:00"])) (define/private (change-position-edit-contents str) (send position-canvas set-str str)) (send (get-info-panel) change-children (λ (l) (cons position-parent (remq position-parent l)))) - + + (define file-text-mode-msg-parent (new horizontal-panel% + [stretchable-width #f] + [stretchable-height #f] + [parent (get-info-panel)])) + (define file-text-mode-msg (new file-text-mode-msg% [parent file-text-mode-msg-parent])) + (send file-text-mode-msg-parent change-children (λ (l) '())) + (send (get-info-panel) change-children + (λ (l) + (cons file-text-mode-msg-parent (remq file-text-mode-msg-parent l)))) (define-values (anchor-message overwrite-message @@ -1133,7 +1157,28 @@ (send macro-recording-message show #f) (send anchor-message show #f) (send overwrite-message show #f) - (editor-position-changed))) + (editor-position-changed) + (use-file-text-mode-changed))) + +(define crlf-string "CRLF") +(define file-text-mode-msg% + (class canvas% + (inherit min-width min-height get-dc refresh) + (define/override (on-paint) + (define dc (get-dc)) + (send dc set-pen "black" 1 'transparent) + (send dc set-brush "orange" 'solid) + (define-values (w h d a) (send dc get-text-extent crlf-string)) + (send dc draw-rectangle 0 0 (+ w 4) h) + (send dc draw-text crlf-string 2 0)) + (super-new) + (inherit stretchable-width) + (stretchable-width #f) + (send (get-dc) set-font small-control-font) + (let () + (define-values (w h d a) (send (get-dc) get-text-extent crlf-string)) + (min-width (inexact->exact (ceiling (+ w 4)))) + (min-height (inexact->exact (ceiling h)))))) (define click-pref-panel% (class horizontal-panel% diff --git a/collects/framework/private/main.rkt b/collects/framework/private/main.rkt index c0e8ed906c..0b85867ab2 100644 --- a/collects/framework/private/main.rkt +++ b/collects/framework/private/main.rkt @@ -25,6 +25,8 @@ ;; 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)) +(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?) diff --git a/collects/framework/private/preferences.rkt b/collects/framework/private/preferences.rkt index 2e98c5917f..24dd3d9f52 100644 --- a/collects/framework/private/preferences.rkt +++ b/collects/framework/private/preferences.rkt @@ -494,6 +494,11 @@ the state transitions / contracts are: 'framework:automatic-parens (string-constant enable-automatic-parens) values values) + (when (eq? (system-type) 'windows) + (make-check editor-panel + 'framework:always-use-platform-specific-linefeed-convention + (string-constant always-use-platform-specific-linefeed-convention) + values values)) (editor-panel-procs editor-panel))))]) (add-editor-checkbox-panel))) diff --git a/collects/framework/private/sig.rkt b/collects/framework/private/sig.rkt index 9f43200363..d44b5673c5 100644 --- a/collects/framework/private/sig.rkt +++ b/collects/framework/private/sig.rkt @@ -181,6 +181,7 @@ info<%> file<%> clever-file-format<%> + crlf-line-endings<%> ports<%> input-box<%> autocomplete<%> @@ -218,6 +219,7 @@ info-mixin file-mixin clever-file-format-mixin + crlf-line-endings-mixin ports-mixin input-box-mixin autocomplete-mixin)) diff --git a/collects/framework/private/text.rkt b/collects/framework/private/text.rkt index 28fc67b670..8f5750fe99 100644 --- a/collects/framework/private/text.rkt +++ b/collects/framework/private/text.rkt @@ -1724,6 +1724,13 @@ (define/augment (after-set-position) (maybe-queue-editor-position-update) (inner (void) after-set-position)) + (define/override use-file-text-mode + (case-lambda + [() (super use-file-text-mode)] + [(x) (super use-file-text-mode x) + (enqueue-for-frame + (λ (x) (send x use-file-text-mode-changed)) + 'framework:file-text-mode-changed)])) ;; maybe-queue-editor-position-update : -> void ;; updates the editor-position in the frame, @@ -1754,9 +1761,9 @@ (define clever-file-format-mixin (mixin ((class->interface text%)) (clever-file-format<%>) (inherit get-file-format set-file-format find-first-snip) - + ;; all-string-snips : -> boolean - ;; returns #t when it is safe to save this file in 'text mode. + ;; returns #t when it is safe to save this file in regular (non-WXME) mode. (define/private (all-string-snips) (let loop ([s (find-first-snip)]) (cond @@ -1788,7 +1795,41 @@ (set-file-format 'standard)] [else (void)])) (inner (void) on-save-file name format)) - (super-instantiate ()))) + + (super-new))) + +(define unix-line-endings-regexp #rx"(^$)|((^|[^\r])\n)") +(unless (and (regexp-match? unix-line-endings-regexp "") + (regexp-match? unix-line-endings-regexp "\n") + (regexp-match? unix-line-endings-regexp "a\n") + (not (regexp-match? unix-line-endings-regexp "\r\n")) + (regexp-match? unix-line-endings-regexp "x\ny\r\nz\n") + (regexp-match? unix-line-endings-regexp "\n\r\n") + (not (regexp-match? unix-line-endings-regexp "a\r\nb\r\nc\r\n")) + (regexp-match? unix-line-endings-regexp "a\r\nb\r\nc\n") + (regexp-match? unix-line-endings-regexp "a\nb\r\nc\r\n")) + (error 'framework/private/text.rkt "unix-line-endings-regexp test failure")) + +(define crlf-line-endings<%> (interface ((class->interface text%)))) + +(define crlf-line-endings-mixin + (mixin ((class->interface text%)) (crlf-line-endings<%>) + (inherit get-filename use-file-text-mode) + (define/augment (after-load-file success?) + (cond + [(preferences:get 'framework:always-use-platform-specific-linefeed-convention) + (define unix-endings? + (with-handlers ((exn:fail:filesystem? (λ (x) #t))) + (call-with-input-file (get-filename) + (λ (port) + (regexp-match? unix-line-endings-regexp port))))) + (use-file-text-mode + (and (eq? (system-type) 'windows) + unix-endings?))] + [else (use-file-text-mode #t)]) + (inner (void) after-load-file success?)) + + (super-new))) (define file<%> @@ -3464,11 +3505,16 @@ designates the character that triggers autocompletion (define completion-box% (class* object% (completion-box<%>) - (init-field completions ; scroll-manager% the possible completions (all of which have base-word as a prefix) - line-x ; int the x coordinate of the line where the menu goes - line-y-above ; int the y coordinate of the top of the line where the menu goes - line-y-below ; int the y coordinate of the bottom of the line where the menu goes - editor ; editor<%> the owner of this completion box + (init-field completions ; scroll-manager% + ; the possible completions (all of which have base-word as a prefix) + line-x ; int + ; the x coordinate of the line where the menu goes + line-y-above ; int + ; the y coordinate of the top of the line where the menu goes + line-y-below ; int + ; the y coordinate of the bottom of the line where the menu goes + editor ; editor<%> + ; the owner of this completion box ) (define/public (empty?) (send completions empty?)) @@ -3524,7 +3570,9 @@ designates the character that triggers autocompletion (cond [(null? pc) (let-values ([(hidden?) (send completions items-are-hidden?)] - [(tw th _1 _2) (send dc get-text-extent hidden-completions-text (get-reg-font))]) + [(tw th _1 _2) (send dc get-text-extent + hidden-completions-text + (get-reg-font))]) (let ([w (if hidden? (max tw w) w)] [h (if hidden? (+ th h) h)]) (initialize-mouse-offset-map! coord-map) @@ -3578,7 +3626,10 @@ designates the character that triggers autocompletion [(send completions empty?) (let ([font (send dc get-font)]) (send dc set-font (get-mt-font)) - (send dc draw-text (string-constant no-completions) (+ mx dx menu-padding-x) (+ menu-padding-y my dy)) + (send dc draw-text + (string-constant no-completions) + (+ mx dx menu-padding-x) + (+ menu-padding-y my dy)) (send dc set-font font))] [else (send dc set-font (get-reg-font)) @@ -3641,7 +3692,8 @@ designates the character that triggers autocompletion (set! highlighted-menu-item 0) (scroll-display-down)] [else - (set! highlighted-menu-item (modulo (add1 highlighted-menu-item) (send completions get-visible-length))) + (set! highlighted-menu-item (modulo (add1 highlighted-menu-item) + (send completions get-visible-length))) (redraw)])) ;; prev-item : -> void @@ -3654,7 +3706,8 @@ designates the character that triggers autocompletion (sub1 (send completions get-visible-length))) (scroll-display-up)] [else - (set! highlighted-menu-item (modulo (sub1 highlighted-menu-item) (send completions get-visible-length))) + (set! highlighted-menu-item (modulo (sub1 highlighted-menu-item) + (send completions get-visible-length))) (redraw)])) ;; scroll-display-down : -> void @@ -3697,8 +3750,11 @@ designates the character that triggers autocompletion (define/public (handle-mouse-movement x y) (let*-values ([(mx my w h) (get-menu-coordinates)]) (when (and (<= mx x (+ mx w)) - (< (+ my menu-padding-y) y (+ my (vector-length (geometry-mouse->menu-item-vector geometry))))) - (set! highlighted-menu-item (vector-ref (geometry-mouse->menu-item-vector geometry) (inexact->exact (- y my)))) + (< (+ my menu-padding-y) + y + (+ my (vector-length (geometry-mouse->menu-item-vector geometry))))) + (set! highlighted-menu-item (vector-ref (geometry-mouse->menu-item-vector geometry) + (inexact->exact (- y my)))) (redraw)))) ;; get-current-selection : -> string @@ -4100,7 +4156,7 @@ designates the character that triggers autocompletion (define return% (return-mixin -keymap%)) (define autowrap% (editor:autowrap-mixin -keymap%)) (define file% (file-mixin (editor:file-mixin autowrap%))) -(define clever-file-format% (clever-file-format-mixin file%)) +(define clever-file-format% (crlf-line-endings-mixin (clever-file-format-mixin file%))) (define backup-autosave% (editor:backup-autosave-mixin clever-file-format%)) (define searching% (searching-mixin backup-autosave%)) (define info% (info-mixin (editor:info-mixin searching%))) diff --git a/collects/scribblings/drracket/prefs.scrbl b/collects/scribblings/drracket/prefs.scrbl index e39fa0df85..cc05af1abd 100644 --- a/collects/scribblings/drracket/prefs.scrbl +++ b/collects/scribblings/drracket/prefs.scrbl @@ -56,10 +56,6 @@ The @onscreen{Editing} panel consists of several sub-panels: @item{@PrefItem{Wrap words in editor buffers} --- If checked, DrRacket editors auto-wrap text lines by default. Changing this preference affects new windows only.} - @item{@PrefItem{Reuse existing frames when opening new files} --- - If checked, new files are opened in the same DrRacket - window, rather than creating a new DrRacket window for each - new file.} @item{@PrefItem{Enable keybindings in menus} --- If checked, some DrRacket menu items have keybindings. Otherwise, no menu items have key bindings. This preference is designed for @@ -68,7 +64,7 @@ The @onscreen{Editing} panel consists of several sub-panels: keybindings.} @item{@PrefItem{Treat command key as meta} --- If checked, DrRacket will use the command key for some Emacs-like - keybindings, instead of using it for menu shortcuts. This + keybindings, instead of using it for menu shortcuts. This option is only available on Mac OS X.} @item{@PrefItem{Color syntax interactively} --- If checked, DrRacket colors your syntax as you type.} @@ -89,6 +85,18 @@ The @onscreen{Editing} panel consists of several sub-panels: @item{@PrefItem{Enable automatic parentheses} --- If checked, typing an open parenthesis, curley brace, square bracket, or a double quote character automatically inserts a matching one.} + @item{@PrefItem{Always use the platform-specific linefeed convention} --- + If checked, DrRacket always saves files with CRLF line terminators. + If unchecked, DrRacket looks at each file as it is opened and if every + line is terminated with CRLF (and there is at least one line), + then it saves the file with CRLF terminators + and otherwise it is saved with LF terminators (following the + Mac OS X and Linux convention). When a file is going to be saved + with CRLF terminators, then the status line at the bottom of the + DrRacket window shows ``CRLF''. + + This option is only available under Windows. On other operating + systems, all files are always saved with LF line terminators.} @item{@PrefItem{Show line numbers} --- If checked, DrRacket shows line numbers for the file being edited in the left-hand column}]} diff --git a/collects/scribblings/framework/text.scrbl b/collects/scribblings/framework/text.scrbl index cb81645ea3..83899a1177 100644 --- a/collects/scribblings/framework/text.scrbl +++ b/collects/scribblings/framework/text.scrbl @@ -699,6 +699,25 @@ } } +@definterface[text:crlf-line-endings<%> (text%)]{ + Objects supporting this interface use + @method[editor<%> use-file-text-mode] to + change the line ending style under windows. See + @method[text:crlf-line-endings-mixin after-load-file] for more information. +} + + +@defmixin[text:crlf-line-endings-mixin (text%) (text:crlf-line-endings<%>)]{ + @defmethod[#:mode override (after-load-file [success? any/c]) void?]{ + Checks to see if the newly loaded file has any lines terminated with + @racket["\n"] (i.e., not @racket["\r\n"]) or if the file is empty. + If so, and if the @racket[system-type] returns @racket['windows], then + this method calls @method[editor<%> use-file-text-mode], passing @racket[#f]. + + Otherwise, calls @method[editor<%> use-file-text-mode] with @racket[#t]. + } +} + @definterface[text:file<%> (editor:file<%> text:basic<%>)]{ Mixins that implement this interface lock themselves when the file they are editing is read only. diff --git a/collects/string-constants/private/english-string-constants.rkt b/collects/string-constants/private/english-string-constants.rkt index 7fe337add1..d821d98590 100644 --- a/collects/string-constants/private/english-string-constants.rkt +++ b/collects/string-constants/private/english-string-constants.rkt @@ -1632,4 +1632,6 @@ please adhere to these guidelines: (normalize-string-preference "Normalize pasted strings") (ask-about-normalizing-strings "Ask about normalizing strings") + (always-use-platform-specific-linefeed-convention "Always use the platform-specific linefeed convention") + ) diff --git a/doc/release-notes/drracket/HISTORY.txt b/doc/release-notes/drracket/HISTORY.txt index 00b4fec1e9..59ba90b665 100644 --- a/doc/release-notes/drracket/HISTORY.txt +++ b/doc/release-notes/drracket/HISTORY.txt @@ -10,6 +10,17 @@ The preferences dialog (general tab) has a checkbox to restore the old behavior. + . Under Windows, DrRacket now saves files, in some situations, + with LF terminators. Previously, under windows, all files + were saved with CRLF terminators. Now, a file is saved with + CRLF terminators when every line in the file ends with CRLF. + In there is any one line that ends with just LF, then the + file is saved with LF's for each line. Also, newly created + files are also saved with LFs instead of CRLFs. + + There is a preference in the Edit|General preferences panel + to go back to the behavior of previous versions of DrRacket. + . added online expansion and check syntax . removed the "open here" functionality (both from