diff --git a/drracket/drracket/HISTORY.txt b/drracket/drracket/HISTORY.txt index bf76f95e1..0a52a8508 100644 --- a/drracket/drracket/HISTORY.txt +++ b/drracket/drracket/HISTORY.txt @@ -1,3 +1,12 @@ +------------------------------ + Version 8.5 +------------------------------ + + . added new file menu item 'Reopen Closed Tab' to open previously + closed tabs. + . Removed keyboard shortcut for 'Spell Check test' in edit menu due + to conflict with 'Reopen Closed Tab'. + ------------------------------ Version 8.4 ------------------------------ diff --git a/drracket/drracket/private/main.rkt b/drracket/drracket/private/main.rkt index e1b7b9aa7..0699a73ce 100644 --- a/drracket/drracket/private/main.rkt +++ b/drracket/drracket/private/main.rkt @@ -617,6 +617,41 @@ (preferences:set-default 'drracket:show-killed-dialog #t boolean?) + (preferences:set-default + 'drracket:recently-closed-tabs + 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 + 'drracket:recently-closed-tabs + (λ (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 'drracket:recently-closed-tabs-max-count + 1000 + (λ (x) (and (number? x) + (x . > . 0) + (integer? x)))) (drr:set-default 'drracket:large-letters-font #f (or/c #f diff --git a/drracket/drracket/private/unit.rkt b/drracket/drracket/private/unit.rkt index e088ca64c..010dd4deb 100644 --- a/drracket/drracket/private/unit.rkt +++ b/drracket/drracket/private/unit.rkt @@ -3075,7 +3075,7 @@ ;; create-new-tab : -> void ;; creates a new tab and updates the GUI for that new tab (define/public create-new-tab - (lambda ([filename #f]) + (lambda ([filename #f] #:start-pos [start-pos 0] #:end-pos [end-pos 'same]) (let* ([defs (new (drracket:get/extend:get-definitions-text))] [tab-count (length tabs)] [new-tab (new (drracket:get/extend:get-tab) @@ -3086,6 +3086,7 @@ (ints-shown? (not filename)))] [ints (make-object (drracket:get/extend:get-interactions-text) new-tab)]) (send new-tab set-ints ints) + (send (send new-tab get-defs) set-position start-pos end-pos) (set! tabs (append tabs (list new-tab))) (send tabs-panel append (gui-utils:trim-string @@ -3248,6 +3249,7 @@ (send tab set-i (- (send tab get-i) 1))) (set! tabs (remq tab-to-close tabs)) (send tabs-panel delete (send tab-to-close get-i)) + (update-closed-tabs tab) (update-menu-bindings) (cond [(eq? tab-to-close current-tab) @@ -3265,9 +3267,31 @@ #t] [else #f])) - (define/public (open-in-new-tab filename) - (create-new-tab filename)) - + (define/public (open-in-new-tab filename #:start-pos [start-pos 0] #:end-pos [end-pos 'same]) + (create-new-tab filename #:start-pos start-pos #:end-pos end-pos)) + + ;; reopen-closed-tab : -> void + ;; Opens previously closed tabs. If no tabs were closed in current session, files from + ;; previous sessions are opened. + (define/public reopen-closed-tab + (lambda () + (define closed-tabs (preferences:get 'drracket:recently-closed-tabs)) + (define file-to-open + (for/or ([file (in-list closed-tabs)]) + (define filename (first file)) + (and (file-exists? filename) + (set! closed-tabs (cdr closed-tabs)) + file))) + (when file-to-open + (let ([tab (find-matching-tab (car file-to-open))] + [start-pos (cadr file-to-open)] + [end-pos (caddr file-to-open)]) + (if tab + (change-to-tab tab) + (open-in-new-tab (car file-to-open) #:start-pos start-pos #:end-pos end-pos)))) + (preferences:set 'drracket:recently-closed-tabs closed-tabs) + #f)) + (define/public (get-tab-count) (length tabs)) (define/public (change-to-nth-tab n) (unless (< n (length tabs)) @@ -3397,6 +3421,32 @@ (update-close-tab-menu-item-shortcut close-tab-menu-item)) (update-close-menu-item-shortcut (file-menu:get-close-item))) + ;; truncate-list : (listof X) -> (listof X)[< new-len] + ;; takes a list and returns the + ;; front of the list, up to 'new-len' number of items + (define/private (truncate-list l new-len) + (define len (length l)) + (cond + [(<= len new-len) l] + [else (drop-right l (- len new-len))])) + + (define/private (update-closed-tabs tab) + (define tab-filename (send (send tab get-defs) get-filename)) + (when tab-filename + (let* ([old-closed-tabs (preferences:get 'drracket:recently-closed-tabs)] + [max-list-len (preferences:get 'drracket:recently-closed-tabs-max-count)] + [defs (send tab get-defs)] + [start-pos (send defs get-start-position)] + [end-pos (send defs get-end-position)] + [new-ent (list tab-filename start-pos end-pos)]) + (define new-closed-tabs (cons new-ent + (remove* (list new-ent) + old-closed-tabs + (λ (l1 l2) + (pathname-equal? (car l1) (car l2)))))) + (set! new-closed-tabs (truncate-list new-closed-tabs max-list-len)) + (preferences:set 'drracket:recently-closed-tabs new-closed-tabs)))) + (define/private (update-close-tab-menu-item-shortcut item) (define just-one? (and (pair? tabs) (null? (cdr tabs)))) (send item set-label (if just-one? @@ -3932,6 +3982,14 @@ (let-values ([(base name dir?) (split-path editing-path)]) base)))) (when pth (handler:edit-file pth)))]) + (new menu:can-restore-menu-item% + (label (string-constant reopen-closed-tab)) + (shortcut #\t) + (shortcut-prefix (cons 'shift (get-default-shortcut-prefix))) + (parent file-menu) + (callback + (λ (x y) + (reopen-closed-tab)))) (super file-menu:between-open-and-revert file-menu) (make-object separator-menu-item% file-menu))] (define close-tab-menu-item #f) @@ -4055,7 +4113,7 @@ (mk-menu-item (λ (ed) (send ed get-spell-check-text)) (λ (ed new-val) (send ed set-spell-check-text new-val)) 'framework:spell-check-text? - #\t + #f (string-constant spell-check-scribble-text)) (new menu:can-restore-menu-item% diff --git a/drracket/scribblings/drracket/menus.scrbl b/drracket/scribblings/drracket/menus.scrbl index 61abaa694..262080996 100644 --- a/drracket/scribblings/drracket/menus.scrbl +++ b/drracket/scribblings/drracket/menus.scrbl @@ -30,6 +30,10 @@ or @litchar{"x.rkt"}) and edit the corresponding files in the @tech{definitions window}.} + @item{@defmenuitem{Reopen Closed Tab} Opens previously closed tabs. + If no tabs were closed in current session, files from + previous sessions are opened.} + @item{@defmenuitem{Install PLT File...} Opens a dialog asking for the location of the @filepath{.plt} file (either on the local disk or on the web) and installs the contents of the file.} diff --git a/drracket/scribblings/tools/unit.scrbl b/drracket/scribblings/tools/unit.scrbl index 38c123876..ca92fb741 100644 --- a/drracket/scribblings/tools/unit.scrbl +++ b/drracket/scribblings/tools/unit.scrbl @@ -619,15 +619,23 @@ Returns the currently active tab. Returns the number of open tabs in the frame. } -@defmethod[(open-in-new-tab [filename (or/c path-string? #f)]) void?]{ +@defmethod[(open-in-new-tab [filename (or/c path-string? #f)] + [#:start-pos start-pos exact-nonnegative-integer? 0] + [#:end-pos end-pos (or/c exact-nonnegative-integer? 'same) 'same]) + void?]{ Opens a new tab in this frame. If @racket[filename] is a @racket[path-string?], - It loads that file in the definitions window of the new tab. + It loads that file in the definitions window of the new tab. If @racket[start-pos] and + @racket[end-pos] are provided, it updates the tab's corresponding insertion positions. } @defmethod[(create-new-tab) void?]{ Creates a new tab. } +@defmethod[(reopen-closed-tab) void?]{ + Opens the most recently closed tabs. +} + @defmethod[(next-tab) void?]{ Switches to the next tab. }