1 # git-gui revision chooser
2 # Copyright (C) 2006, 2007 Shawn Pearce
6 image create
photo ::choose_rev::img_find -data {R0lGODlhEAAQAIYAAPwCBCQmJDw
+PBQSFAQCBMza3NTm5MTW1HyChOT29Ozq7MTq7Kze5Kzm7Oz6
/NTy9Iza5GzGzKzS1Nzy9Nz29Kzq9HTGzHTK1Lza3AwKDLzu9JTi7HTW5GTCzITO1Mzq7Hza5FTK1ESyvHzKzKzW3DQyNDyqtDw6PIzW5HzGzAT
+/Dw
+RKyurNTOzMTGxMS
+tJSGdATCxHRydLSqpLymnLSijBweHERCRNze3Pz69PTy9Oze1OTSxOTGrMSqlLy
+vPTu5OzSvMymjNTGvNS
+tMy2pMyunMSefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe4gACCAAECA4OIiAIEBQYHBAKJgwIICQoLDA0IkZIECQ4PCxARCwSSAxITFA8VEBYXGBmJAQYLGhUbHB0eH7KIGRIMEBAgISIjJKaIJQQLFxERIialkieUGigpKRoIBCqJKyyLBwvJAioEyoICLS4v6QQwMQQyLuqLli8zNDU2BCf1lN3AkUPHDh49fAQAAEnGD1MCCALZEaSHkIUMBQS8wWMIkSJGhBzBmFEGgRsBUqpMiSgdAD
+BAAAh
/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7
}
8 field w
; # our megawidget path
9 field w_list
; # list of currently filtered specs
10 field w_filter
; # filter entry for $w_list
12 field c_expr
{}; # current revision expression
13 field filter
; # current filter string
14 field revtype head
; # type of revision chosen
15 field cur_specs
[list]; # list of specs for $revtype
16 field spec_head
; # list of all head specs
17 field spec_trck
; # list of all tracking branch specs
18 field spec_tag
; # list of all tag specs
19 field tip_data
; # array of tip commit info by refname
21 field tooltip_wm
{} ; # Current tooltip toplevel, if open
22 field tooltip_t
{} ; # Text widget in $tooltip_wm
23 field tooltip_timer
{} ; # Current timer event for our tooltip
25 proc new
{path
{title
{}}} {
26 return [_new
$path 0 $title]
29 proc new_unmerged
{path
{title
{}}} {
30 return [_new
$path 1 $title]
33 constructor _new
{path unmerged_only title
} {
34 global current_branch is_detached
39 labelframe $w -text $title
43 bind $w <Destroy
> [cb _delete
%W
]
46 radiobutton $w.detachedhead_r
\
48 -text {This Detached Checkout
} \
51 grid $w.detachedhead_r
-sticky we
-padx {0 5} -columnspan 2
54 radiobutton $w.expr_r
\
55 -text {Revision Expression
:} \
62 -textvariable @c_expr
\
64 -validatecommand [cb _validate
%d
%S
]
65 grid $w.expr_r
$w.expr_t
-sticky we
-padx {0 5}
68 radiobutton $w.types.head_r
\
69 -text {Local Branch
} \
72 pack $w.types.head_r
-side left
73 radiobutton $w.types.trck_r
\
74 -text {Tracking Branch
} \
77 pack $w.types.trck_r
-side left
78 radiobutton $w.types.tag_r
\
82 pack $w.types.tag_r
-side left
83 set w_filter
$w.types.filter
88 -textvariable @filter
\
90 -validatecommand [cb _filter
%P
]
91 pack $w_filter -side right
92 pack [label $w.types.filter_icon
\
93 -image ::choose_rev::img_find \
95 grid $w.types
-sticky we
-padx {0 5} -columnspan 2
104 -exportselection false
\
105 -xscrollcommand [cb _sb_set
$w.
list.sbx h
] \
106 -yscrollcommand [cb _sb_set
$w.
list.sby v
]
107 pack $w_list -fill both
-expand 1
108 grid $w.
list -sticky nswe
-padx {20 5} -columnspan 2
109 bind $w_list <Any-Motion
> [cb _show_tooltip
@%x
,%y
]
110 bind $w_list <Any-Enter
> [cb _hide_tooltip
]
111 bind $w_list <Any-Leave
> [cb _hide_tooltip
]
112 bind $w_list <Destroy
> [cb _hide_tooltip
]
114 grid columnconfigure
$w 1 -weight 1
116 grid rowconfigure
$w 3 -weight 1
118 grid rowconfigure
$w 2 -weight 1
121 trace add
variable @revtype write
[cb _select
]
122 bind $w_filter <Key-Return
> [list focus $w_list]\;break
123 bind $w_filter <Key-Down
> [list focus $w_list]
126 append fmt
{ %(refname
)}
128 append fmt
{ %(objecttype
)}
129 append fmt
{ %(objectname
)}
130 append fmt
{ [concat %(taggername
) %(authorname
)]}
131 append fmt
{ [concat %(taggerdate
) %(authordate
)]}
132 append fmt
{ %(subject
)}
134 append fmt
{ %(*objecttype
)}
135 append fmt
{ %(*objectname
)}
136 append fmt
{ %(*authorname
)}
137 append fmt
{ %(*authordate
)}
138 append fmt
{ %(*subject
)}
141 set fr_fd
[git_read for-each-ref
\
149 fconfigure $fr_fd -translation lf
-encoding utf-8
150 while {[gets $fr_fd line
] > 0} {
151 set line
[eval $line]
152 if {[lindex $line 1 0] eq
{tag
}} {
153 if {[lindex $line 2 0] eq
{commit
}} {
154 set sha1
[lindex $line 2 1]
158 } elseif
{[lindex $line 1 0] eq
{commit
}} {
159 set sha1
[lindex $line 1 1]
163 set refn
[lindex $line 0]
164 set tip_data
($refn) [lrange $line 1 end
]
165 lappend cmt_refn
($sha1) $refn
166 lappend all_refn
$refn
170 if {$unmerged_only} {
171 set fr_fd
[git_read rev-list
--all ^
$::HEAD]
172 while {[gets $fr_fd sha1
] > 0} {
173 if {[catch {set rlst
$cmt_refn($sha1)}]} continue
180 foreach refn
$all_refn {
186 foreach name
[load_all_heads
] {
187 set refn refs
/heads
/$name
188 if {[info exists inc
($refn)]} {
189 lappend spec_head
[list $name $refn]
194 foreach spec
[all_tracking_branches
] {
195 set refn
[lindex $spec 0]
196 if {[info exists inc
($refn)]} {
197 regsub ^refs
/(heads|remotes
)/ $refn {} name
198 lappend spec_trck
[concat $name $spec]
203 foreach name
[load_all_tags
] {
204 set refn refs
/tags
/$name
205 if {[info exists inc
($refn)]} {
206 lappend spec_tag
[list $name $refn]
210 if {$is_detached} { set revtype HEAD
211 } elseif
{[llength $spec_head] > 0} { set revtype head
212 } elseif
{[llength $spec_trck] > 0} { set revtype trck
213 } elseif
{[llength $spec_tag ] > 0} { set revtype tag
214 } else { set revtype
expr
217 if {$revtype eq
{head
} && $current_branch ne
{}} {
219 foreach spec
$spec_head {
220 if {[lindex $spec 0] eq
$current_branch} {
221 $w_list selection clear
0 end
222 $w_list selection set $i
233 if {![winfo exists
$w.none_r
]} {
234 radiobutton $w.none_r
\
238 grid $w.none_r
-sticky we
-padx {0 5} -columnspan 2
240 $w.none_r configure
-text $text
248 set i
[$w_list curselection
]
250 return [lindex $cur_specs $i 0]
257 expr { return $c_expr }
259 default { error "unknown type of revision" }
263 method pick_tracking_branch
{} {
267 method focus_filter
{} {
268 if {[$w_filter cget
-state] eq
{normal
}} {
273 method bind_listbox
{event script
} {
274 bind $w_list $event $script
277 method get_local_branch
{} {
278 if {$revtype eq
{head
}} {
285 method get_tracking_branch
{} {
286 set i
[$w_list curselection
]
287 if {$i eq
{} ||
$revtype ne
{trck
}} {
290 return [lrange [lindex $cur_specs $i] 1 end
]
293 method get_commit
{} {
298 return [git rev-parse
--verify "$e^0"]
301 method commit_or_die
{} {
302 if {[catch {set new
[get_commit
$this]} err
]} {
304 # Cleanup the not-so-friendly error from rev-parse.
306 regsub {^fatal
:\s
*} $err {} err
307 if {$err eq
{Needed a single revision
}} {
311 set top
[winfo toplevel $w]
312 set msg
"Invalid revision: [get $this]\n\n$err"
316 -title [wm title
$top] \
329 set i
[$w_list curselection
]
331 return [lindex $cur_specs $i 1]
333 error "No revision selected."
341 error "Revision expression is empty."
346 default { error "unknown type of revision" }
350 method _validate
{d S
} {
352 if {[regexp {\s
} $S]} {
355 if {[string length
$S] > 0} {
363 if {[regexp {\s
} $P]} {
370 method _select
{args
} {
371 _rebuild
$this $filter
375 method _rebuild
{pat
} {
378 head
{ set new
$spec_head }
379 trck
{ set new
$spec_trck }
380 tag
{ set new
$spec_tag }
389 if {[$w_list cget
-state] eq
{disabled
}} {
390 $w_list configure
-state normal
399 set txt
[lindex $spec 0]
400 if {$pat eq
{} ||
[string match
$pat $txt]} {
401 lappend cur_specs
$spec
402 $w_list insert end
$txt
405 if {$cur_specs ne
{}} {
406 $w_list selection clear
0 end
407 $w_list selection set 0
410 if {[$w_filter cget
-state] ne
$ste} {
411 $w_list configure
-state $ste
412 $w_filter configure
-state $ste
416 method _delete
{current
} {
417 if {$current eq
$w} {
422 method _sb_set
{sb orient first last
} {
423 set old_focus
[focus -lastfor $w]
425 if {$first == 0 && $last == 1} {
426 if {[winfo exists
$sb]} {
428 if {$old_focus ne
{}} {
436 if {![winfo exists
$sb]} {
437 if {$orient eq
{h
}} {
438 scrollbar $sb -orient h
-command [list $w_list xview
]
439 pack $sb -fill x
-side bottom
-before $w_list
441 scrollbar $sb -orient v
-command [list $w_list yview
]
442 pack $sb -fill y
-side right
-before $w_list
444 if {$old_focus ne
{}} {
452 method _show_tooltip
{pos
} {
453 if {$tooltip_wm ne
{}} {
455 } elseif
{$tooltip_timer eq
{}} {
456 set tooltip_timer
[after 1000 [cb _open_tooltip
]]
460 method _open_tooltip
{} {
464 set pos_x
[winfo pointerx
$w_list]
465 set pos_y
[winfo pointery
$w_list]
466 if {[winfo containing
$pos_x $pos_y] ne
$w_list} {
471 set pos
@[join [list \
472 [expr {$pos_x - [winfo rootx
$w_list]}] \
473 [expr {$pos_y - [winfo rooty
$w_list]}]] ,]
474 set lno
[$w_list index
$pos]
480 set spec
[lindex $cur_specs $lno]
481 set refn
[lindex $spec 1]
487 if {$tooltip_wm eq
{}} {
488 set tooltip_wm
[toplevel $w_list.tooltip
-borderwidth 1]
489 wm overrideredirect
$tooltip_wm 1
490 wm transient
$tooltip_wm [winfo toplevel $w_list]
491 set tooltip_t
$tooltip_wm.
label
494 -highlightthickness 0 \
498 -background lightyellow
\
500 $tooltip_t tag conf section_header
-font font_uibold
501 bind $tooltip_wm <Escape
> [cb _hide_tooltip
]
504 $tooltip_t conf
-state normal
505 $tooltip_t delete
0.0 end
508 set data
$tip_data($refn)
509 if {[lindex $data 0 0] eq
{tag
}} {
510 set tag
[lindex $data 0]
511 if {[lindex $data 1 0] eq
{commit
}} {
512 set cmit
[lindex $data 1]
516 } elseif
{[lindex $data 0 0] eq
{commit
}} {
518 set cmit
[lindex $data 0]
521 $tooltip_t insert end
"[lindex $spec 0]\n"
524 $tooltip_t insert end
"\n"
525 $tooltip_t insert end
"tag" section_header
526 $tooltip_t insert end
" [lindex $tag 1]\n"
527 $tooltip_t insert end
[lindex $tag 2]
528 $tooltip_t insert end
" ([lindex $tag 3])\n"
529 $tooltip_t insert end
[lindex $tag 4]
530 $tooltip_t insert end
"\n"
534 $tooltip_t insert end
"\n"
535 $tooltip_t insert end
"commit" section_header
536 $tooltip_t insert end
" [lindex $cmit 1]\n"
537 $tooltip_t insert end
[lindex $cmit 2]
538 $tooltip_t insert end
" ([lindex $cmit 3])\n"
539 $tooltip_t insert end
[lindex $cmit 4]
542 if {[llength $spec] > 2} {
543 $tooltip_t insert end
"\n"
544 $tooltip_t insert end
"remote" section_header
545 $tooltip_t insert end
" [lindex $spec 2]\n"
546 $tooltip_t insert end
"url"
547 $tooltip_t insert end
" $remote_url([lindex $spec 2])\n"
548 $tooltip_t insert end
"branch"
549 $tooltip_t insert end
" [lindex $spec 3]"
552 $tooltip_t conf
-state disabled
553 _position_tooltip
$this
556 method _position_tooltip
{} {
557 set max_h
[lindex [split [$tooltip_t index end
] .
] 0]
559 for {set i
1} {$i <= $max_h} {incr i
} {
560 set c
[lindex [split [$tooltip_t index
"$i.0 lineend"] .
] 1]
561 if {$c > $max_w} {set max_w
$c}
563 $tooltip_t conf
-width $max_w -height $max_h
565 set req_w
[winfo reqwidth
$tooltip_t]
566 set req_h
[winfo reqheight
$tooltip_t]
567 set pos_x
[expr {[winfo pointerx .
] + 5}]
568 set pos_y
[expr {[winfo pointery .
] + 10}]
570 set g
"${req_w}x${req_h}"
571 if {$pos_x >= 0} {append g
+}
573 if {$pos_y >= 0} {append g
+}
576 wm geometry
$tooltip_wm $g
580 method _hide_tooltip
{} {
581 if {$tooltip_wm ne
{}} {
585 if {$tooltip_timer ne
{}} {
586 after cancel
$tooltip_timer