summaryrefslogtreecommitdiff
path: root/git-gui/lib/browser.tcl
blob: 3d6341bcc53d0e61b0817dcc5d9778f714b026b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# git-gui tree browser
# Copyright (C) 2006, 2007 Shawn Pearce
 
class browser {
 
field w
field browser_commit
field browser_path
field browser_files  {}
field browser_status {Starting...}
field browser_stack  {}
field browser_busy   1
 
constructor new {commit} {
	global cursor_ptr M1B
	make_toplevel top w
	wm title $top "[appname] ([reponame]): File Browser"
 
	set browser_commit $commit
	set browser_path $browser_commit:
 
	label $w.path \
		-textvariable @browser_path \
		-anchor w \
		-justify left \
		-borderwidth 1 \
		-relief sunken \
		-font font_uibold
	pack $w.path -anchor w -side top -fill x
 
	frame $w.list
	set w_list $w.list.l
	text $w_list -background white -borderwidth 0 \
		-cursor $cursor_ptr \
		-state disabled \
		-wrap none \
		-height 20 \
		-width 70 \
		-xscrollcommand [list $w.list.sbx set] \
		-yscrollcommand [list $w.list.sby set]
	$w_list tag conf in_sel \
		-background [$w_list cget -foreground] \
		-foreground [$w_list cget -background]
	scrollbar $w.list.sbx -orient h -command [list $w_list xview]
	scrollbar $w.list.sby -orient v -command [list $w_list yview]
	pack $w.list.sbx -side bottom -fill x
	pack $w.list.sby -side right -fill y
	pack $w_list -side left -fill both -expand 1
	pack $w.list -side top -fill both -expand 1
 
	label $w.status \
		-textvariable @browser_status \
		-anchor w \
		-justify left \
		-borderwidth 1 \
		-relief sunken
	pack $w.status -anchor w -side bottom -fill x
 
	bind $w_list <Button-1>        "[cb _click 0 @%x,%y];break"
	bind $w_list <Double-Button-1> "[cb _click 1 @%x,%y];break"
	bind $w_list <$M1B-Up>         "[cb _parent]        ;break"
	bind $w_list <$M1B-Left>       "[cb _parent]        ;break"
	bind $w_list <Up>              "[cb _move -1]       ;break"
	bind $w_list <Down>            "[cb _move  1]       ;break"
	bind $w_list <$M1B-Right>      "[cb _enter]         ;break"
	bind $w_list <Return>          "[cb _enter]         ;break"
	bind $w_list <Prior>           "[cb _page -1]       ;break"
	bind $w_list <Next>            "[cb _page  1]       ;break"
	bind $w_list <Left>            break
	bind $w_list <Right>           break
 
	bind $w_list <Visibility> [list focus $w_list]
	set w $w_list
	_ls $this $browser_commit
	return $this
}
 
method _move {dir} {
	if {$browser_busy} return
	set lno [lindex [split [$w index in_sel.first] .] 0]
	incr lno $dir
	if {[lindex $browser_files [expr {$lno - 1}]] ne {}} {
		$w tag remove in_sel 0.0 end
		$w tag add in_sel $lno.0 [expr {$lno + 1}].0
		$w see $lno.0
	}
}
 
method _page {dir} {
	if {$browser_busy} return
	$w yview scroll $dir pages
	set lno [expr {int(
		  [lindex [$w yview] 0]
		* [llength $browser_files]
		+ 1)}]
	if {[lindex $browser_files [expr {$lno - 1}]] ne {}} {
		$w tag remove in_sel 0.0 end
		$w tag add in_sel $lno.0 [expr {$lno + 1}].0
		$w see $lno.0
	}
}
 
method _parent {} {
	if {$browser_busy} return
	set info [lindex $browser_files 0]
	if {[lindex $info 0] eq {parent}} {
		set parent [lindex $browser_stack end-1]
		set browser_stack [lrange $browser_stack 0 end-2]
		if {$browser_stack eq {}} {
			regsub {:.*$} $browser_path {:} browser_path
		} else {
			regsub {/[^/]+$} $browser_path {} browser_path
		}
		set browser_status "Loading $browser_path..."
		_ls $this [lindex $parent 0] [lindex $parent 1]
	}
}
 
method _enter {} {
	if {$browser_busy} return
	set lno [lindex [split [$w index in_sel.first] .] 0]
	set info [lindex $browser_files [expr {$lno - 1}]]
	if {$info ne {}} {
		switch -- [lindex $info 0] {
		parent {
			_parent $this
		}
		tree {
			set name [lindex $info 2]
			set escn [escape_path $name]
			set browser_status "Loading $escn..."
			append browser_path $escn
			_ls $this [lindex $info 1] $name
		}
		blob {
			set name [lindex $info 2]
			set p {}
			foreach n $browser_stack {
				append p [lindex $n 1]
			}
			append p $name
			blame::new $browser_commit $p
		}
		}
	}
}
 
method _click {was_double_click pos} {
	if {$browser_busy} return
	set lno [lindex [split [$w index $pos] .] 0]
	focus $w
 
	if {[lindex $browser_files [expr {$lno - 1}]] ne {}} {
		$w tag remove in_sel 0.0 end
		$w tag add in_sel $lno.0 [expr {$lno + 1}].0
		if {$was_double_click} {
			_enter $this
		}
	}
}
 
method _ls {tree_id {name {}}} {
	set browser_buffer {}
	set browser_files {}
	set browser_busy 1
 
	$w conf -state normal
	$w tag remove in_sel 0.0 end
	$w delete 0.0 end
	if {$browser_stack ne {}} {
		$w image create end \
			-align center -padx 5 -pady 1 \
			-name icon0 \
			-image file_uplevel
		$w insert end {[Up To Parent]}
		lappend browser_files parent
	}
	lappend browser_stack [list $tree_id $name]
	$w conf -state disabled
 
	set cmd [list git ls-tree -z $tree_id]
	set fd [open "| $cmd" r]
	fconfigure $fd -blocking 0 -translation binary -encoding binary
	fileevent $fd readable [cb _read $fd]
}
 
method _read {fd} {
	append browser_buffer [read $fd]
	set pck [split $browser_buffer "\0"]
	set browser_buffer [lindex $pck end]
 
	set n [llength $browser_files]
	$w conf -state normal
	foreach p [lrange $pck 0 end-1] {
		set info [split $p "\t"]
		set path [lindex $info 1]
		set info [split [lindex $info 0] { }]
		set type [lindex $info 1]
		set object [lindex $info 2]
 
		switch -- $type {
		blob {
			set image file_mod
		}
		tree {
			set image file_dir
			append path /
		}
		default {
			set image file_question
		}
		}
 
		if {$n > 0} {$w insert end "\n"}
		$w image create end \
			-align center -padx 5 -pady 1 \
			-name icon[incr n] \
			-image $image
		$w insert end [escape_path $path]
		lappend browser_files [list $type $object $path]
	}
	$w conf -state disabled
 
	if {[eof $fd]} {
		close $fd
		set browser_status Ready.
		set browser_busy 0
		unset browser_buffer
		if {$n > 0} {
			$w tag add in_sel 1.0 2.0
			focus -force $w
		}
	}
} ifdeleted {
	catch {close $fd}
}
 
}