git-gui: offer a list of recent repositories on startup
authorSteffen Prohaska <prohaska@zib.de>
Mon, 8 Oct 2007 06:25:47 +0000 (08:25 +0200)
committerShawn O. Pearce <spearce@spearce.org>
Fri, 12 Oct 2007 05:13:55 +0000 (01:13 -0400)
If git-gui is started outside a work tree the repository chooser
will offer a list of recently opened repositories.  Clicking on
any list entry directly opens the repository.

The list of recently opened repositories is stored in the config
as the multi-valued option gui.recentrepo. If the list grows beyond
10 entries it will be truncated by removing one of the older entries.

Only repositories that are opened through the repository chooser
will get added to the recent list.  Repositories opened from the
shell will not yet be added to the recent list, as users are likely
to have a way to easily return to the same directory via their shell.

[sp: This is actually a combined work from both Steffen and myself.
     Most of the ideas are Steffen's, as is the basic outline of
     the code, but any outstanding bugs are entirely my fault.]

Signed-off-by: Steffen Prohaska <prohaska@zib.de>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
git-gui.sh
lib/choose_repository.tcl

index a6e2d57..dd320fb 100755 (executable)
@@ -205,6 +205,7 @@ proc disable_option {option} {
 
 proc is_many_config {name} {
        switch -glob -- $name {
+       gui.recentrepo -
        remote.*.fetch -
        remote.*.push
                {return 1}
index 5d5bc81..8dc8506 100644 (file)
@@ -9,6 +9,7 @@ field w_body      ; # Widget holding the center content
 field w_next      ; # Next button
 field o_cons      ; # Console object (if active)
 field w_types     ; # List of type buttons in clone
+field w_recentlist ; # Listbox containing recent repositories
 
 field action          new ; # What action are we going to perform?
 field done              0 ; # Finished picking the repository?
@@ -17,6 +18,7 @@ field origin_url       {} ; # Where we are cloning from
 field origin_name  origin ; # What we shall call 'origin'
 field clone_type hardlink ; # Type of clone to construct
 field readtree_err        ; # Error output from read-tree (if any)
+field sorted_recent       ; # recent repositories (sorted)
 
 constructor pick {} {
        global M1T M1B
@@ -82,6 +84,40 @@ constructor pick {} {
        pack $w_body.new -anchor w -fill x
        pack $w_body.clone -anchor w -fill x
        pack $w_body.open -anchor w -fill x
+
+       set sorted_recent [_get_recentrepos]
+       if {[llength $sorted_recent] > 0} {
+               label $w_body.space
+               label $w_body.recentlabel \
+                       -anchor w \
+                       -text [mc "Open Recent Repository:"]
+               set w_recentlist $w_body.recentlist
+               text $w_recentlist \
+                       -cursor $::cursor_ptr \
+                       -relief flat \
+                       -background [$w_body.recentlabel cget -background] \
+                       -wrap none \
+                       -width 50 \
+                       -height 10
+               $w_recentlist tag conf link \
+                       -foreground blue \
+                       -underline 1
+               set home "[file normalize $::env(HOME)][file separator]"
+               set hlen [string length $home]
+               foreach p $sorted_recent {
+                       if {[string equal -length $hlen $home $p]} {
+                               set p "~[file separator][string range $p $hlen end]"
+                       }
+                       regsub -all "\n" $p "\\n" p
+                       $w_recentlist insert end $p link
+                       $w_recentlist insert end "\n"
+               }
+               $w_recentlist conf -state disabled
+               $w_recentlist tag bind link <1> [cb _open_recent %x,%y]
+               pack $w_body.space -anchor w -fill x
+               pack $w_body.recentlabel -anchor w -fill x
+               pack $w_recentlist -anchor w -fill x
+       }
        pack $w_body -fill x -padx 10 -pady 10
 
        frame $w.buttons
@@ -134,6 +170,50 @@ method _invoke_next {} {
        }
 }
 
+proc _get_recentrepos {} {
+       set recent [list]
+       foreach p [get_config gui.recentrepo] {
+               if {[_is_git [file join $p .git]]} {
+                       lappend recent $p
+               }
+       }
+       return [lsort $recent]
+}
+
+proc _unset_recentrepo {p} {
+       regsub -all -- {([()\[\]{}\.^$+*?\\])} $p {\\\1} p
+       git config --global --unset gui.recentrepo "^$p\$"
+}
+
+proc _append_recentrepos {path} {
+       set path [file normalize $path]
+       set recent [get_config gui.recentrepo]
+
+       if {[lindex $recent end] eq $path} {
+               return
+       }
+
+       set i [lsearch $recent $path]
+       if {$i >= 0} {
+               _unset_recentrepo $path
+               set recent [lreplace $recent $i $i]
+       }
+
+       lappend recent $path
+       git config --global --add gui.recentrepo $path
+
+       while {[llength $recent] > 10} {
+               _unset_recentrepo [lindex $recent 0]
+               set recent [lrange $recent 1 end]
+       }
+}
+
+method _open_recent {xy} {
+       set id [lindex [split [$w_recentlist index @$xy] .] 0]
+       set local_path [lindex $sorted_recent [expr {$id - 1}]]
+       _do_open2 $this
+}
+
 method _next {} {
        destroy $w_body
        _do_$action $this
@@ -174,6 +254,7 @@ method _git_init {} {
                return 0
        }
 
+       _append_recentrepos [pwd]
        set ::_gitdir .git
        set ::_prefix {}
        return 1
@@ -856,6 +937,7 @@ method _do_open2 {} {
                return
        }
 
+       _append_recentrepos [pwd]
        set ::_gitdir .git
        set ::_prefix {}
        set done 1