2
# Tcl ignores the next line -*- tcl -*- \
3
exec wish "$0" -- "$@"
4
5
-# Copyright (C) 2005-2006 Paul Mackerras. All rights reserved.
5
+# Copyright © 2005-2008 Paul Mackerras. All rights reserved.
6
# This program is free software; it may be used, copied, modified
7
# and distributed under the terms of the GNU General Public Licence,
8
# either version 2, or (at your option) any later version.
117
}
118
119
proc parseviewargs {n arglist} {
120
- global viewargs vdatemode vmergeonly
120
+ global vdatemode vmergeonly vflags vdflags vrevs vfiltered vorigargs
121
122
set vdatemode($n) 0
123
set vmergeonly($n) 0
124
- set glargs {}
125
- foreach arg $viewargs($n) {
124
+ set glflags {}
125
+ set diffargs {}
126
+ set nextisval 0
127
+ set revargs {}
128
+ set origargs $arglist
129
+ set allknown 1
130
+ set filtered 0
131
+ set i -1
132
+ foreach arg $arglist {
133
+ incr i
134
+ if {$nextisval} {
135
+ lappend glflags $arg
136
+ set nextisval 0
137
+ continue
138
+ }
139
switch -glob -- $arg {
140
"-d" -
141
"--date-order" {
142
set vdatemode($n) 1
143
+ # remove from origargs in case we hit an unknown option
144
+ set origargs [lreplace $origargs $i $i]
145
+ incr i -1
146
+ }
147
+ # These request or affect diff output, which we don't want.
148
+ # Some could be used to set our defaults for diff display.
149
+ "-[puabwcrRBMC]" -
150
+ "--no-renames" - "--full-index" - "--binary" - "--abbrev=*" -
151
+ "--find-copies-harder" - "-l*" - "--ext-diff" - "--no-ext-diff" -
152
+ "--src-prefix=*" - "--dst-prefix=*" - "--no-prefix" -
153
+ "-O*" - "--text" - "--full-diff" - "--ignore-space-at-eol" -
154
+ "--ignore-space-change" - "-U*" - "--unified=*" {
155
+ lappend diffargs $arg
156
+ }
157
+ # These cause our parsing of git log's output to fail, or else
158
+ # they're options we want to set ourselves, so ignore them.
159
+ "--raw" - "--patch-with-raw" - "--patch-with-stat" -
160
+ "--name-only" - "--name-status" - "--color" - "--color-words" -
161
+ "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" -
162
+ "--cc" - "-z" - "--header" - "--parents" - "--boundary" -
163
+ "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" -
164
+ "--timestamp" - "relative-date" - "--date=*" - "--stdin" -
165
+ "--objects" - "--objects-edge" - "--reverse" {
166
+ }
167
+ # These are harmless, and some are even useful
168
+ "--stat=*" - "--numstat" - "--shortstat" - "--summary" -
169
+ "--check" - "--exit-code" - "--quiet" - "--topo-order" -
170
+ "--full-history" - "--dense" - "--sparse" -
171
+ "--follow" - "--left-right" - "--encoding=*" {
172
+ lappend glflags $arg
173
+ }
174
+ # These mean that we get a subset of the commits
175
+ "--diff-filter=*" - "--no-merges" - "--unpacked" -
176
+ "--max-count=*" - "--skip=*" - "--since=*" - "--after=*" -
177
+ "--until=*" - "--before=*" - "--max-age=*" - "--min-age=*" -
178
+ "--author=*" - "--committer=*" - "--grep=*" - "-[iE]" -
179
+ "--remove-empty" - "--first-parent" - "--cherry-pick" -
180
+ "-S*" - "--pickaxe-all" - "--pickaxe-regex" - {
181
+ set filtered 1
182
+ lappend glflags $arg
183
+ }
184
+ # This appears to be the only one that has a value as a
185
+ # separate word following it
186
+ "-n" {
187
+ set filtered 1
188
+ set nextisval 1
189
+ lappend glflags $arg
190
+ }
191
+ "--not" {
192
+ set notflag [expr {!$notflag}]
193
+ lappend revargs $arg
194
+ }
195
+ "--all" {
196
+ lappend revargs $arg
197
}
198
"--merge" {
199
set vmergeonly($n) 1
133
- lappend glargs $arg
200
+ # git rev-parse doesn't understand --merge
201
+ lappend revargs --gitk-symmetric-diff-marker MERGE_HEAD...HEAD
202
}
203
+ # Other flag arguments including -<n>
204
+ "-*" {
205
+ if {[string is digit -strict [string range $arg 1 end]]} {
206
+ set filtered 1
207
+ } else {
208
+ # a flag argument that we don't recognize;
209
+ # that means we can't optimize
210
+ set allknown 0
211
+ }
212
+ lappend glflags $arg
213
+ }
214
+ # Non-flag arguments specify commits or ranges of commits
215
default {
136
- lappend glargs $arg
216
+ if {[string match "*...*" $arg]} {
217
+ lappend revargs --gitk-symmetric-diff-marker
218
+ }
219
+ lappend revargs $arg
220
+ }
221
+ }
222
+ }
223
+ set vdflags($n) $diffargs
224
+ set vflags($n) $glflags
225
+ set vrevs($n) $revargs
226
+ set vfiltered($n) $filtered
227
+ set vorigargs($n) $origargs
228
+ return $allknown
229
+}
230
+
231
+proc parseviewrevs {view revs} {
232
+ global vposids vnegids
233
+
234
+ if {$revs eq {}} {
235
+ set revs HEAD
236
+ }
237
+ if {[catch {set ids [eval exec git rev-parse $revs]} err]} {
238
+ # we get stdout followed by stderr in $err
239
+ # for an unknown rev, git rev-parse echoes it and then errors out
240
+ set errlines [split $err "\n"]
241
+ set badrev {}
242
+ for {set l 0} {$l < [llength $errlines]} {incr l} {
243
+ set line [lindex $errlines $l]
244
+ if {!([string length $line] == 40 && [string is xdigit $line])} {
245
+ if {[string match "fatal:*" $line]} {
246
+ if {[string match "fatal: ambiguous argument*" $line]
247
+ && $badrev ne {}} {
248
+ if {[llength $badrev] == 1} {
249
+ set err "unknown revision $badrev"
250
+ } else {
251
+ set err "unknown revisions: [join $badrev ", "]"
252
+ }
253
+ } else {
254
+ set err [join [lrange $errlines $l end] "\n"]
255
+ }
256
+ break
257
+ }
258
+ lappend badrev $line
259
+ }
260
+ }
261
+ error_popup "Error parsing revisions: $err"
262
+ return {}
263
+ }
264
+ set ret {}
265
+ set pos {}
266
+ set neg {}
267
+ set sdm 0
268
+ foreach id [split $ids "\n"] {
269
+ if {$id eq "--gitk-symmetric-diff-marker"} {
270
+ set sdm 4
271
+ } elseif {[string match "^*" $id]} {
272
+ if {$sdm != 1} {
273
+ lappend ret $id
274
+ if {$sdm == 3} {
275
+ set sdm 0
276
+ }
277
}
278
+ lappend neg [string range $id 1 end]
279
+ } else {
280
+ if {$sdm != 2} {
281
+ lappend ret $id
282
+ } else {
283
+ lset ret end [lindex $ret end]...$id
284
+ }
285
+ lappend pos $id
286
}
287
+ incr sdm -1
288
}
140
- return $glargs
289
+ set vposids($view) $pos
290
+ set vnegids($view) $neg
291
+ return $ret
292
}
293
294
# Start off a git log process and arrange to read its output
295
proc start_rev_list {view} {
296
global startmsecs commitidx viewcomplete
297
global commfd leftover tclencoding
147
- global viewargs viewargscmd vactualargs viewfiles vfilelimit
298
+ global viewargs viewargscmd viewfiles vfilelimit
299
global showlocalchanges commitinterest mainheadid
300
global progressdirn progresscoords proglastnc curview
301
global viewactive loginstance viewinstances vmergeonly
302
global pending_select mainheadid
303
+ global vcanopt vflags vrevs vorigargs
304
305
set startmsecs [clock clicks -milliseconds]
306
set commitidx($view) 0
319
}
320
set args [concat $args [split $str "\n"]]
321
}
170
- set args [parseviewargs $view $args]
171
- set vactualargs($view) $args
322
+ set vcanopt($view) [parseviewargs $view $args]
323
324
set files $viewfiles($view)
325
if {$vmergeonly($view)} {
338
}
339
set vfilelimit($view) $files
340
341
+ if {$vcanopt($view)} {
342
+ set revs [parseviewrevs $view $vrevs($view)]
343
+ if {$revs eq {}} {
344
+ return 0
345
+ }
346
+ set args [concat $vflags($view) $revs]
347
+ } else {
348
+ set args $vorigargs($view)
349
+ }
350
+
351
if {[catch {
352
set fd [open [concat | git log --no-color -z --pretty=raw --parents \
353
--boundary $args "--" $files] r]
409
}
410
411
proc updatecommits {} {
251
- global curview vactualargs vfilelimit viewinstances
412
+ global curview vcanopt vorigargs vfilelimit viewinstances
413
global viewactive viewcomplete loginstance tclencoding mainheadid
414
global startmsecs commfd showneartags showlocalchanges leftover
415
global mainheadid pending_select
416
global isworktree
417
+ global varcid vposids vnegids vflags vrevs
418
419
set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
420
set oldmainid $mainheadid
428
}
429
}
430
set view $curview
431
+ if {$vcanopt($view)} {
432
+ set oldpos $vposids($view)
433
+ set oldneg $vnegids($view)
434
+ set revs [parseviewrevs $view $vrevs($view)]
435
+ if {$revs eq {}} {
436
+ return
437
+ }
438
+ # note: getting the delta when negative refs change is hard,
439
+ # and could require multiple git log invocations, so in that
440
+ # case we ask git log for all the commits (not just the delta)
441
+ if {$oldneg eq $vnegids($view)} {
442
+ set newrevs {}
443
+ set npos 0
444
+ # take out positive refs that we asked for before or
445
+ # that we have already seen
446
+ foreach rev $revs {
447
+ if {[string length $rev] == 40} {
448
+ if {[lsearch -exact $oldpos $rev] < 0
449
+ && ![info exists varcid($view,$rev)]} {
450
+ lappend newrevs $rev
451
+ incr npos
452
+ }
453
+ } else {
454
+ lappend $newrevs $rev
455
+ }
456
+ }
457
+ if {$npos == 0} return
458
+ set revs $newrevs
459
+ set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
460
+ }
461
+ set args [concat $vflags($view) $revs --not $oldpos]
462
+ } else {
463
+ set args $vorigargs($view)
464
+ }
465
if {[catch {
466
set fd [open [concat | git log --no-color -z --pretty=raw --parents \
271
- --boundary $vactualargs($view) --not [seeds $view] \
272
- "--" $vfilelimit($view)] r]
467
+ --boundary $args "--" $vfilelimit($view)] r]
468
} err]} {
469
error_popup "Error executing git log: $err"
275
- exit 1
470
+ return
471
}
472
if {$viewactive($view) == 0} {
473
set startmsecs [clock clicks -milliseconds]
2412
message $w.m -text [mc "
2413
Gitk - a commit viewer for git
2414
2220
-Copyright © 2005-2006 Paul Mackerras
2415
+Copyright © 2005-2008 Paul Mackerras
2416
2417
Use and redistribute under the terms of the GNU General Public License"] \
2418
-justify center -aspect 400 -border 2 -bg white -relief groove