Skip to content

New file menu item - Reopen Closed Tab #543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions drracket/drracket/HISTORY.txt
Original file line number Diff line number Diff line change
@@ -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
------------------------------
Expand Down
35 changes: 35 additions & 0 deletions drracket/drracket/private/main.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
68 changes: 63 additions & 5 deletions drracket/drracket/private/unit.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work properly? Maybe better to remove file-to-open from closed-tabs after this loop completes? And if any files were skipped because they don't exist anymore, those should probably be removed from the preference too.

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))
Expand Down Expand Up @@ -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?
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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%
Expand Down
4 changes: 4 additions & 0 deletions drracket/scribblings/drracket/menus.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -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.}
Expand Down
12 changes: 10 additions & 2 deletions drracket/scribblings/tools/unit.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lowercase "i" in "it".

@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.
}
Expand Down