2 # Tcl ignores the next line -*- tcl -*- \
5 # Copyright (C) 2006 Shawn Pearce, 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.
10 ######################################################################
19 set update_index_fd
{}
21 set disable_on_lock
[list
]
22 set index_lock_type none
24 proc lock_index
{type} {
25 global index_lock_type disable_on_lock
27 if {$index_lock_type == {none
}} {
28 set index_lock_type
$type
29 foreach w
$disable_on_lock {
30 uplevel
#0 $w disabled
33 } elseif
{$index_lock_type == {begin-update
} && $type == {update
}} {
34 set index_lock_type
$type
40 proc unlock_index
{} {
41 global index_lock_type disable_on_lock
43 set index_lock_type none
44 foreach w
$disable_on_lock {
49 ######################################################################
53 proc repository_state
{hdvar ctvar
} {
55 upvar
$hdvar hd
$ctvar ct
57 if {[catch
{set hd
[exec git rev-parse
--verify HEAD
]}]} {
59 } elseif
{[file exists
[file join $gitdir MERGE_HEAD
]]} {
66 proc update_status
{} {
67 global HEAD commit_type
68 global ui_index ui_other ui_status_value ui_comm
69 global status_active file_states
71 if {$status_active ||
![lock_index
read]} return
73 repository_state HEAD commit_type
74 array
unset file_states
75 foreach w
[list
$ui_index $ui_other] {
78 $w conf
-state disabled
81 if {![$ui_comm edit modified
]
82 ||
[string trim
[$ui_comm get
0.0 end
]] == {}} {
83 if {[load_message GITGUI_MSG
]} {
84 } elseif
{[load_message MERGE_MSG
]} {
85 } elseif
{[load_message SQUASH_MSG
]} {
87 $ui_comm edit modified false
91 set ui_status_value
{Refreshing
file status...
}
92 set fd_rf
[open
"| git update-index -q --unmerged --refresh" r
]
93 fconfigure
$fd_rf -blocking 0 -translation binary
94 fileevent
$fd_rf readable
[list read_refresh
$fd_rf]
97 proc read_refresh
{fd
} {
98 global gitdir HEAD commit_type
99 global ui_index ui_other ui_status_value ui_comm
100 global status_active file_states
103 if {![eof
$fd]} return
106 set ls_others
[list | git ls-files
--others -z \
107 --exclude-per-directory=.gitignore
]
108 set info_exclude
[file join $gitdir info exclude
]
109 if {[file readable
$info_exclude]} {
110 lappend ls_others
"--exclude-from=$info_exclude"
114 set ui_status_value
{Scanning
for modified files ...
}
115 set fd_di
[open
"| git diff-index --cached -z $HEAD" r
]
116 set fd_df
[open
"| git diff-files -z" r
]
117 set fd_lo
[open
$ls_others r
]
119 fconfigure
$fd_di -blocking 0 -translation binary
120 fconfigure
$fd_df -blocking 0 -translation binary
121 fconfigure
$fd_lo -blocking 0 -translation binary
122 fileevent
$fd_di readable
[list read_diff_index
$fd_di]
123 fileevent
$fd_df readable
[list read_diff_files
$fd_df]
124 fileevent
$fd_lo readable
[list read_ls_others
$fd_lo]
127 proc load_message
{file} {
128 global gitdir ui_comm
130 set f
[file join $gitdir $file]
131 if {[file exists
$f]} {
132 if {[catch
{set fd
[open
$f r
]}]} {
135 set content
[read $fd]
137 $ui_comm delete
0.0 end
138 $ui_comm insert end
$content
144 proc read_diff_index
{fd
} {
147 append buf_rdi
[read $fd]
148 set pck
[split $buf_rdi "\0"]
149 set buf_rdi
[lindex
$pck end
]
150 foreach
{m p
} [lrange
$pck 0 end-1
] {
151 if {$m != {} && $p != {}} {
152 display_file
$p [string index
$m end
]_
155 status_eof
$fd buf_rdi
158 proc read_diff_files
{fd
} {
161 append buf_rdf
[read $fd]
162 set pck
[split $buf_rdf "\0"]
163 set buf_rdf
[lindex
$pck end
]
164 foreach
{m p
} [lrange
$pck 0 end-1
] {
165 if {$m != {} && $p != {}} {
166 display_file
$p _
[string index
$m end
]
169 status_eof
$fd buf_rdf
172 proc read_ls_others
{fd
} {
175 append buf_rlo
[read $fd]
176 set pck
[split $buf_rlo "\0"]
177 set buf_rlo
[lindex
$pck end
]
178 foreach p
[lrange
$pck 0 end-1
] {
181 status_eof
$fd buf_rlo
184 proc status_eof
{fd buf
} {
185 global status_active
$buf
186 global ui_fname_value ui_status_value
191 if {[incr status_active
-1] == 0} {
193 set ui_status_value
{Ready.
}
194 if {$ui_fname_value != {}} {
195 show_diff
$ui_fname_value
201 ######################################################################
206 global ui_diff ui_fname_value ui_fstatus_value
208 $ui_diff conf
-state normal
209 $ui_diff delete
0.0 end
210 $ui_diff conf
-state disabled
211 set ui_fname_value
{}
212 set ui_fstatus_value
{}
215 proc show_diff
{path
} {
216 global file_states HEAD diff_3way diff_active
217 global ui_diff ui_fname_value ui_fstatus_value ui_status_value
219 if {$diff_active ||
![lock_index
read]} return
222 set s
$file_states($path)
226 set ui_fname_value
$path
227 set ui_fstatus_value
[mapdesc
$m $path]
228 set ui_status_value
"Loading diff of $path..."
230 set cmd
[list | git diff-index
-p $HEAD -- $path]
235 set cmd
[list | git diff-index
-p -c $HEAD $path]
239 set fd
[open
$path r
]
240 set content
[read $fd]
245 set ui_status_value
"Unable to display $path"
246 error_popup
"Error loading file:\n$err"
249 $ui_diff conf
-state normal
250 $ui_diff insert end
$content
251 $ui_diff conf
-state disabled
256 if {[catch
{set fd
[open
$cmd r
]} err
]} {
259 set ui_status_value
"Unable to display $path"
260 error_popup
"Error loading diff:\n$err"
264 fconfigure
$fd -blocking 0 -translation auto
265 fileevent
$fd readable
[list read_diff
$fd]
268 proc read_diff
{fd
} {
269 global ui_diff ui_status_value diff_3way diff_active
271 while {[gets
$fd line
] >= 0} {
272 if {[string match
{diff --git *} $line]} continue
273 if {[string match
{diff --combined *} $line]} continue
274 if {[string match
{--- *} $line]} continue
275 if {[string match
{+++ *} $line]} continue
276 if {[string match index
* $line]} {
277 if {[string first
, $line] >= 0} {
282 $ui_diff conf
-state normal
284 set x
[string index
$line 0]
289 default
{set tags
{}}
292 set x
[string range
$line 0 1]
294 default
{set tags
{}}
296 "++" {set tags dp
; set x
" +"}
297 " +" {set tags
{di bold
}; set x
"++"}
298 "+ " {set tags dni
; set x
"-+"}
299 "--" {set tags dm
; set x
" -"}
300 " -" {set tags
{dm bold
}; set x
"--"}
301 "- " {set tags di
; set x
"+-"}
302 default
{set tags
{}}
304 set line
[string replace
$line 0 1 $x]
306 $ui_diff insert end
$line $tags
307 $ui_diff insert end
"\n"
308 $ui_diff conf
-state disabled
315 set ui_status_value
{Ready.
}
319 ######################################################################
323 proc commit_tree
{} {
324 global tcl_platform HEAD gitdir commit_type file_states
325 global commit_active ui_status_value
328 if {$commit_active ||
![lock_index update
]} return
330 # -- Our in memory state should match the repository.
332 repository_state curHEAD cur_type
333 if {$commit_type != $cur_type ||
$HEAD != $curHEAD} {
334 error_popup
{Last scanned state does not match repository state.
336 Its highly likely that another Git program modified the
337 repository since our last scan. A rescan is required
345 # -- At least one file should differ in the index.
348 foreach path
[array names file_states
] {
349 set s
$file_states($path)
350 switch
-glob -- [lindex
$s 0] {
354 M
* {set files_ready
1; break}
356 error_popup
"Unmerged files cannot be committed.
358 File $path has merge conflicts.
359 You must resolve them and check the file in before committing.
365 error_popup
"Unknown file state [lindex $s 0] detected.
367 File $path cannot be committed by this program.
373 error_popup
{No checked-in files to commit.
375 You must check-in
at least
1 file before you can commit.
381 # -- A message is required.
383 set msg
[string trim
[$ui_comm get
1.0 end
]]
385 error_popup
{Please supply a commit message.
387 A good commit message has the following format
:
389 - First line
: Describe
in one sentance what you did.
391 - Remaining lines
: Describe why this change is good.
397 # -- Ask the pre-commit hook for the go-ahead.
399 set pchook
[file join $gitdir hooks pre-commit
]
400 if {$tcl_platform(platform
) == {windows
} && [file exists
$pchook]} {
401 set pchook
[list sh
-c \
402 "if test -x \"$pchook\"; then exec \"$pchook\"; fi"]
403 } elseif
{[file executable
$pchook]} {
404 set pchook
[list
$pchook]
408 if {$pchook != {} && [catch
{eval exec $pchook} err
]} {
409 hook_failed_popup pre-commit
$err
414 # -- Write the tree in the background.
417 set ui_status_value
{Committing changes...
}
419 set fd_wt
[open
"| git write-tree" r
]
420 fileevent
$fd_wt readable \
421 [list commit_stage2
$fd_wt $curHEAD $msg]
424 proc commit_stage2
{fd_wt curHEAD msg
} {
425 global single_commit gitdir HEAD commit_type
426 global commit_active ui_status_value comm_ui
431 if {$tree_id == {}} {
432 error_popup
"write-tree failed"
434 set ui_status_value
{Commit failed.
}
439 # -- Create the commit.
441 set cmd
[list git commit-tree
$tree_id]
442 if {$commit_type != {initial
}} {
445 if {$commit_type == {merge
}} {
447 set fd_mh
[open
[file join $gitdir MERGE_HEAD
] r
]
448 while {[gets
$fd_mh merge_head
] > 0} {
449 lappend
-p $merge_head
453 error_popup
"Loading MERGE_HEADs failed:\n$err"
455 set ui_status_value
{Commit failed.
}
460 if {$commit_type == {initial
}} {
461 # git commit-tree writes to stderr during initial commit.
462 lappend cmd
2>/dev
/null
465 if {[catch
{set cmt_id
[eval exec $cmd]} err
]} {
466 error_popup
"commit-tree failed:\n$err"
468 set ui_status_value
{Commit failed.
}
473 # -- Update the HEAD ref.
476 if {$commit_type != {normal
}} {
477 append reflogm
" ($commit_type)"
479 set i
[string first
"\n" $msg]
481 append reflogm
{: } [string range
$msg 0 [expr $i - 1]]
483 append reflogm
{: } $msg
485 set cmd
[list git update-ref \
487 HEAD
$cmt_id $curHEAD]
488 if {[catch
{eval exec $cmd} err
]} {
489 error_popup
"update-ref failed:\n$err"
491 set ui_status_value
{Commit failed.
}
496 # -- Cleanup after ourselves.
498 catch
{file delete
[file join $gitdir MERGE_HEAD
]}
499 catch
{file delete
[file join $gitdir MERGE_MSG
]}
500 catch
{file delete
[file join $gitdir SQUASH_MSG
]}
501 catch
{file delete
[file join $gitdir GITGUI_MSG
]}
503 # -- Let rerere do its thing.
505 if {[file isdirectory
[file join $gitdir rr-cache
]]} {
506 catch
{exec git rerere
}
509 $comm_ui delete
0.0 end
510 $comm_ui edit modified false
512 if {$single_commit} do_quit
515 set ui_status_value
"Changes committed as $cmt_id."
520 ######################################################################
524 proc mapcol
{state path
} {
527 if {[catch
{set r
$all_cols($state)}]} {
528 puts
"error: no column for state={$state} $path"
534 proc mapicon
{state path
} {
537 if {[catch
{set r
$all_icons($state)}]} {
538 puts
"error: no icon for state={$state} $path"
544 proc mapdesc
{state path
} {
547 if {[catch
{set r
$all_descs($state)}]} {
548 puts
"error: no desc for state={$state} $path"
554 proc bsearch
{w path
} {
555 set hi
[expr [lindex
[split [$w index end
] .
] 0] - 2]
561 set mi
[expr [expr $lo + $hi] / 2]
562 set ti
[expr $mi + 1]
563 set cmp [string compare
[$w get
$ti.1 $ti.end
] $path]
566 } elseif
{$cmp == 0} {
572 return -[expr $lo + 1]
575 proc merge_state
{path state
} {
578 if {[array names file_states
-exact $path] == {}} {
580 set s
[list
$o none none
]
582 set s
$file_states($path)
587 if {[string index
$state 0] == "_"} {
588 set state
[string index
$m 0][string index
$state 1]
589 } elseif
{[string index
$state 0] == "*"} {
590 set state _
[string index
$state 1]
593 if {[string index
$state 1] == "_"} {
594 set state
[string index
$state 0][string index
$m 1]
595 } elseif
{[string index
$state 1] == "*"} {
596 set state
[string index
$state 0]_
599 set file_states
($path) [lreplace
$s 0 0 $state]
603 proc display_file
{path state
} {
604 global ui_index ui_other file_states
606 set old_m
[merge_state
$path $state]
607 set s
$file_states($path)
610 if {[mapcol
$m $path] == "o"} {
622 set d
[lindex
$s $ii]
624 set lno
[bsearch
$iw $path]
627 $iw conf
-state normal
628 $iw delete
$lno.0 [expr $lno + 1].0
629 $iw conf
-state disabled
630 set s
[lreplace
$s $ii $ii none
]
634 set d
[lindex
$s $ai]
636 set lno
[expr abs
([bsearch
$aw $path] + 1) + 1]
637 $aw conf
-state normal
638 set ico
[$aw image create
$lno.0 \
639 -align center
-padx 5 -pady 1 \
640 -image [mapicon
$m $path]]
641 $aw insert
$lno.1 "$path\n"
642 $aw conf
-state disabled
643 set file_states
($path) [lreplace
$s $ai $ai [list
$ico]]
644 } elseif
{[mapicon
$m $path] != [mapicon
$old_m $path]} {
645 set ico
[lindex
$d 0]
646 $aw image conf
$ico -image [mapicon
$m $path]
650 proc with_update_index
{body
} {
651 global update_index_fd
653 if {$update_index_fd == {}} {
654 if {![lock_index update
]} return
655 set update_index_fd
[open \
656 "| git update-index --add --remove -z --stdin" \
658 fconfigure
$update_index_fd -translation binary
660 close
$update_index_fd
661 set update_index_fd
{}
668 proc update_index
{path
} {
669 global update_index_fd
671 if {$update_index_fd == {}} {
672 error
{not
in with_update_index
}
674 puts
-nonewline $update_index_fd "$path\0"
678 proc toggle_mode
{path
} {
681 set s
$file_states($path)
693 with_update_index
{update_index
$path}
694 display_file
$path $new
697 ######################################################################
702 #define mask_width 14
703 #define mask_height 15
704 static unsigned char mask_bits
[] = {
705 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
706 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
707 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
710 image create bitmap file_plain
-background white
-foreground black
-data {
711 #define plain_width 14
712 #define plain_height 15
713 static unsigned char plain_bits
[] = {
714 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
715 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
716 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
717 } -maskdata $filemask
719 image create bitmap file_mod
-background white
-foreground blue
-data {
721 #define mod_height 15
722 static unsigned char mod_bits
[] = {
723 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
724 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
725 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
726 } -maskdata $filemask
728 image create bitmap file_fulltick
-background white
-foreground "#007000" -data {
729 #define file_fulltick_width 14
730 #define file_fulltick_height 15
731 static unsigned char file_fulltick_bits
[] = {
732 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
733 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
734 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
735 } -maskdata $filemask
737 image create bitmap file_parttick
-background white
-foreground "#005050" -data {
738 #define parttick_width 14
739 #define parttick_height 15
740 static unsigned char parttick_bits
[] = {
741 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
742 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
743 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
744 } -maskdata $filemask
746 image create bitmap file_question
-background white
-foreground black
-data {
747 #define file_question_width 14
748 #define file_question_height 15
749 static unsigned char file_question_bits
[] = {
750 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
751 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
752 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
753 } -maskdata $filemask
755 image create bitmap file_removed
-background white
-foreground red
-data {
756 #define file_removed_width 14
757 #define file_removed_height 15
758 static unsigned char file_removed_bits
[] = {
759 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
760 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
761 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
762 } -maskdata $filemask
764 image create bitmap file_merge
-background white
-foreground blue
-data {
765 #define file_merge_width 14
766 #define file_merge_height 15
767 static unsigned char file_merge_bits
[] = {
768 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
769 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
770 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
771 } -maskdata $filemask
773 set max_status_desc
0
775 {__ i plain
"Unmodified"}
776 {_M i mod
"Modified"}
777 {M_ i fulltick
"Checked in"}
778 {MM i parttick
"Partially checked in"}
780 {_O o plain
"Untracked"}
781 {A_ o fulltick
"Added"}
782 {AM o parttick
"Partially added"}
784 {_D i question
"Missing"}
785 {D_ i removed
"Removed"}
786 {DD i removed
"Removed"}
787 {DO i removed
"Removed (still exists)"}
789 {UM i merge
"Merge conflicts"}
790 {U_ i merge
"Merge conflicts"}
792 if {$max_status_desc < [string length
[lindex
$i 3]]} {
793 set max_status_desc
[string length
[lindex
$i 3]]
795 set all_cols
([lindex
$i 0]) [lindex
$i 1]
796 set all_icons
([lindex
$i 0]) file_
[lindex
$i 2]
797 set all_descs
([lindex
$i 0]) [lindex
$i 3]
801 ######################################################################
805 proc error_popup
{msg
} {
812 proc show_msg
{w top msg
} {
813 global gitdir appname
815 message
$w.m
-text $msg -justify left
-aspect 400
816 pack
$w.m
-side top
-fill x
-padx 5 -pady 10
817 button
$w.ok
-text OK \
819 -command "destroy $top"
820 pack
$w.ok
-side bottom
821 bind $top <Visibility
> "grab $top; focus $top"
822 bind $top <Key-Return
> "destroy $top"
823 wm title
$top "error: $appname ([file normalize [file dirname $gitdir]])"
827 proc hook_failed_popup
{hook msg
} {
828 global gitdir mainfont difffont appname
835 label
$w.m.l1
-text "$hook hook failed:" \
838 -font [concat
$mainfont bold
]
840 -background white
-borderwidth 1 \
842 -width 80 -height 10 \
844 -yscrollcommand [list
$w.m.sby
set]
846 -text {You must correct the above errors before committing.
} \
849 -font [concat
$mainfont bold
]
850 scrollbar
$w.m.sby
-command [list
$w.m.t yview
]
851 pack
$w.m.l1
-side top
-fill x
852 pack
$w.m.l2
-side bottom
-fill x
853 pack
$w.m.sby
-side right
-fill y
854 pack
$w.m.t
-side left
-fill both
-expand 1
855 pack
$w.m
-side top
-fill both
-expand 1 -padx 5 -pady 10
857 $w.m.t insert
1.0 $msg
858 $w.m.t conf
-state disabled
860 button
$w.ok
-text OK \
862 -command "destroy $w"
863 pack
$w.ok
-side bottom
865 bind $w <Visibility
> "grab $w; focus $w"
866 bind $w <Key-Return
> "destroy $w"
867 wm title
$w "error: $appname ([file normalize [file dirname $gitdir]])"
871 ######################################################################
875 set starting_gitk_msg
{Please
wait... Starting gitk...
}
877 global tcl_platform ui_status_value starting_gitk_msg
879 set ui_status_value
$starting_gitk_msg
881 if {$ui_status_value == $starting_gitk_msg} {
882 set ui_status_value
{Ready.
}
886 if {$tcl_platform(platform
) == "windows"} {
894 global gitdir ui_comm
896 set save
[file join $gitdir GITGUI_MSG
]
897 set msg
[string trim
[$ui_comm get
0.0 end
]]
898 if {[$ui_comm edit modified
] && $msg != {}} {
900 set fd
[open
$save w
]
901 puts
$fd [string trim
[$ui_comm get
0.0 end
]]
904 } elseif
{$msg == {} && [file exists
$save]} {
915 proc do_checkin_all
{} {
916 global checkin_active ui_status_value
918 if {$checkin_active ||
![lock_index begin-update
]} return
921 set ui_status_value
{Checking
in all files...
}
924 foreach path
[array names file_states
] {
925 set s
$file_states($path)
931 _D
{toggle_mode
$path}
936 set ui_status_value
{Ready.
}
944 set me
[exec git var GIT_COMMITTER_IDENT
]
945 if {[regexp
{(.
*) [0-9]+ [-+0-9]+$
} $me me name
]} {
946 set str
"Signed-off-by: $name"
947 if {[$ui_comm get
{end
-1c linestart
} {end
-1c}] != $str} {
948 $ui_comm insert end
"\n"
949 $ui_comm insert end
$str
960 # shift == 1: left click
962 proc click
{w x y
shift wx wy
} {
963 global ui_index ui_other
965 set pos
[split [$w index @
$x,$y] .
]
966 set lno
[lindex
$pos 0]
967 set col [lindex
$pos 1]
968 set path
[$w get
$lno.1 $lno.end
]
969 if {$path == {}} return
971 if {$col > 0 && $shift == 1} {
972 $ui_index tag remove in_diff
0.0 end
973 $ui_other tag remove in_diff
0.0 end
974 $w tag add in_diff
$lno.0 [expr $lno + 1].0
979 proc unclick
{w x y
} {
980 set pos
[split [$w index @
$x,$y] .
]
981 set lno
[lindex
$pos 0]
982 set col [lindex
$pos 1]
983 set path
[$w get
$lno.1 $lno.end
]
984 if {$path == {}} return
991 ######################################################################
995 set mainfont
{Helvetica
10}
996 set difffont
{Courier
10}
997 set maincursor
[. cget
-cursor]
999 switch
-- $tcl_platform(platform
) {
1000 windows
{set M1B Control
; set M1T Ctrl
}
1001 default
{set M1B M1
; set M1T M1
}
1005 menu .mbar
-tearoff 0
1006 .mbar add cascade
-label Project
-menu .mbar.project
1007 .mbar add cascade
-label Commit
-menu .mbar.commit
1008 .mbar add cascade
-label Fetch
-menu .mbar.fetch
1009 .mbar add cascade
-label Pull
-menu .mbar.pull
1010 . configure
-menu .mbar
1014 .mbar.project add
command -label Visualize \
1017 .mbar.project add
command -label Quit \
1019 -accelerator $M1T-Q \
1024 .mbar.commit add
command -label Rescan \
1025 -command do_rescan \
1028 lappend disable_on_lock \
1029 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1030 .mbar.commit add
command -label {Check-in All Files
} \
1031 -command do_checkin_all \
1032 -accelerator $M1T-U \
1034 lappend disable_on_lock \
1035 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1036 .mbar.commit add
command -label {Sign Off
} \
1037 -command do_signoff \
1038 -accelerator $M1T-S \
1040 .mbar.commit add
command -label Commit \
1041 -command do_commit \
1042 -accelerator $M1T-Return \
1044 lappend disable_on_lock \
1045 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1053 # -- Main Window Layout
1054 panedwindow .vpane
-orient vertical
1055 panedwindow .vpane.files
-orient horizontal
1056 .vpane add .vpane.files
-sticky nsew
-height 100 -width 400
1057 pack .vpane
-anchor n
-side top
-fill both
-expand 1
1059 # -- Index File List
1060 set ui_index .vpane.files.index.list
1061 frame .vpane.files.index
-height 100 -width 400
1062 label .vpane.files.index.title
-text {Modified Files
} \
1065 text
$ui_index -background white
-borderwidth 0 \
1066 -width 40 -height 10 \
1068 -yscrollcommand {.vpane.files.index.sb
set} \
1069 -cursor $maincursor \
1071 scrollbar .vpane.files.index.sb
-command [list
$ui_index yview
]
1072 pack .vpane.files.index.title
-side top
-fill x
1073 pack .vpane.files.index.sb
-side right
-fill y
1074 pack
$ui_index -side left
-fill both
-expand 1
1075 .vpane.files add .vpane.files.index
-sticky nsew
1077 # -- Other (Add) File List
1078 set ui_other .vpane.files.other.list
1079 frame .vpane.files.other
-height 100 -width 100
1080 label .vpane.files.other.title
-text {Untracked Files
} \
1083 text
$ui_other -background white
-borderwidth 0 \
1084 -width 40 -height 10 \
1086 -yscrollcommand {.vpane.files.other.sb
set} \
1087 -cursor $maincursor \
1089 scrollbar .vpane.files.other.sb
-command [list
$ui_other yview
]
1090 pack .vpane.files.other.title
-side top
-fill x
1091 pack .vpane.files.other.sb
-side right
-fill y
1092 pack
$ui_other -side left
-fill both
-expand 1
1093 .vpane.files add .vpane.files.other
-sticky nsew
1095 $ui_index tag conf in_diff
-font [concat
$mainfont bold
]
1096 $ui_other tag conf in_diff
-font [concat
$mainfont bold
]
1099 set ui_fname_value
{}
1100 set ui_fstatus_value
{}
1101 frame .vpane.
diff -height 200 -width 400
1102 frame .vpane.
diff.header
1103 label .vpane.
diff.header.l1
-text {File
:} -font $mainfont
1104 label .vpane.
diff.header.l2
-textvariable ui_fname_value \
1108 label .vpane.
diff.header.l3
-text {Status
:} -font $mainfont
1109 label .vpane.
diff.header.l4
-textvariable ui_fstatus_value \
1110 -width $max_status_desc \
1114 pack .vpane.
diff.header.l1
-side left
1115 pack .vpane.
diff.header.l2
-side left
-fill x
1116 pack .vpane.
diff.header.l4
-side right
1117 pack .vpane.
diff.header.l3
-side right
1120 frame .vpane.
diff.body
1121 set ui_diff .vpane.
diff.body.t
1122 text
$ui_diff -background white
-borderwidth 0 \
1123 -width 80 -height 15 -wrap none \
1125 -xscrollcommand {.vpane.
diff.body.sbx
set} \
1126 -yscrollcommand {.vpane.
diff.body.sby
set} \
1127 -cursor $maincursor \
1129 scrollbar .vpane.
diff.body.sbx
-orient horizontal \
1130 -command [list
$ui_diff xview
]
1131 scrollbar .vpane.
diff.body.sby
-orient vertical \
1132 -command [list
$ui_diff yview
]
1133 pack .vpane.
diff.body.sbx
-side bottom
-fill x
1134 pack .vpane.
diff.body.sby
-side right
-fill y
1135 pack
$ui_diff -side left
-fill both
-expand 1
1136 pack .vpane.
diff.header
-side top
-fill x
1137 pack .vpane.
diff.body
-side bottom
-fill both
-expand 1
1138 .vpane add .vpane.
diff -stick nsew
1140 $ui_diff tag conf dm
-foreground red
1141 $ui_diff tag conf dp
-foreground blue
1142 $ui_diff tag conf da
-font [concat
$difffont bold
]
1143 $ui_diff tag conf di
-foreground "#00a000"
1144 $ui_diff tag conf dni
-foreground "#a000a0"
1145 $ui_diff tag conf bold
-font [concat
$difffont bold
]
1148 frame .vpane.commarea
-height 150
1149 .vpane add .vpane.commarea
-stick nsew
1151 # -- Commit Area Buttons
1152 frame .vpane.commarea.buttons
1153 label .vpane.commarea.buttons.l
-text {} \
1157 pack .vpane.commarea.buttons.l
-side top
-fill x
1158 pack .vpane.commarea.buttons
-side left
-fill y
1160 button .vpane.commarea.buttons.rescan
-text {Rescan
} \
1161 -command do_rescan \
1163 pack .vpane.commarea.buttons.rescan
-side top
-fill x
1164 lappend disable_on_lock
{.vpane.commarea.buttons.rescan conf
-state}
1166 button .vpane.commarea.buttons.ciall
-text {Check-in All
} \
1167 -command do_checkin_all \
1169 pack .vpane.commarea.buttons.ciall
-side top
-fill x
1170 lappend disable_on_lock
{.vpane.commarea.buttons.ciall conf
-state}
1172 button .vpane.commarea.buttons.signoff
-text {Sign Off
} \
1173 -command do_signoff \
1175 pack .vpane.commarea.buttons.signoff
-side top
-fill x
1177 button .vpane.commarea.buttons.commit
-text {Commit
} \
1178 -command do_commit \
1180 pack .vpane.commarea.buttons.commit
-side top
-fill x
1181 lappend disable_on_lock
{.vpane.commarea.buttons.commit conf
-state}
1183 # -- Commit Message Buffer
1184 frame .vpane.commarea.buffer
1185 set ui_comm .vpane.commarea.buffer.t
1186 label .vpane.commarea.buffer.l
-text {Commit Message
:} \
1190 text
$ui_comm -background white
-borderwidth 1 \
1192 -width 75 -height 10 -wrap none \
1194 -yscrollcommand {.vpane.commarea.buffer.sby
set} \
1196 scrollbar .vpane.commarea.buffer.sby
-command [list
$ui_comm yview
]
1197 pack .vpane.commarea.buffer.l
-side top
-fill x
1198 pack .vpane.commarea.buffer.sby
-side right
-fill y
1199 pack
$ui_comm -side left
-fill y
1200 pack .vpane.commarea.buffer
-side left
-fill y
1203 set ui_status_value
{Initializing...
}
1204 label .status
-textvariable ui_status_value \
1210 pack .status
-anchor w
-side bottom
-fill x
1213 bind $ui_comm <$M1B-Key-Return> {do_commit
;break}
1214 bind .
<Destroy
> do_quit
1215 bind .
<Key-F5
> do_rescan
1216 bind .
<$M1B-Key-r> do_rescan
1217 bind .
<$M1B-Key-R> do_rescan
1218 bind .
<$M1B-Key-s> do_signoff
1219 bind .
<$M1B-Key-S> do_signoff
1220 bind .
<$M1B-Key-u> do_checkin_all
1221 bind .
<$M1B-Key-U> do_checkin_all
1222 bind .
<$M1B-Key-Return> do_commit
1223 bind .
<$M1B-Key-q> do_quit
1224 bind .
<$M1B-Key-Q> do_quit
1225 foreach i
[list
$ui_index $ui_other] {
1226 bind $i <Button-1
> {click
%W
%x
%y
1 %X
%Y
; break}
1227 bind $i <Button-3
> {click
%W
%x
%y
3 %X
%Y
; break}
1228 bind $i <ButtonRelease-1
> {unclick
%W
%x
%y
; break}
1232 ######################################################################
1236 if {[catch
{set gitdir
[exec git rev-parse
--git-dir]} err
]} {
1237 show_msg
{} .
"Cannot find the git directory: $err"
1241 set appname
[lindex
[file split $argv0] end
]
1242 if {$appname == {git-citool
}} {
1246 wm title .
"$appname ([file normalize [file dirname $gitdir]])"
1247 focus
-force $ui_comm