lib / index.tclon commit git-gui: offer a list of recent repositories on startup (24f7c64)
   1# git-gui index (add/remove) support
   2# Copyright (C) 2006, 2007 Shawn Pearce
   3
   4proc update_indexinfo {msg pathList after} {
   5        global update_index_cp
   6
   7        if {![lock_index update]} return
   8
   9        set update_index_cp 0
  10        set pathList [lsort $pathList]
  11        set totalCnt [llength $pathList]
  12        set batch [expr {int($totalCnt * .01) + 1}]
  13        if {$batch > 25} {set batch 25}
  14
  15        $::main_status start $msg [mc "files"]
  16        set fd [git_write update-index -z --index-info]
  17        fconfigure $fd \
  18                -blocking 0 \
  19                -buffering full \
  20                -buffersize 512 \
  21                -encoding binary \
  22                -translation binary
  23        fileevent $fd writable [list \
  24                write_update_indexinfo \
  25                $fd \
  26                $pathList \
  27                $totalCnt \
  28                $batch \
  29                $after \
  30                ]
  31}
  32
  33proc write_update_indexinfo {fd pathList totalCnt batch after} {
  34        global update_index_cp
  35        global file_states current_diff_path
  36
  37        if {$update_index_cp >= $totalCnt} {
  38                close $fd
  39                unlock_index
  40                $::main_status stop
  41                uplevel #0 $after
  42                return
  43        }
  44
  45        for {set i $batch} \
  46                {$update_index_cp < $totalCnt && $i > 0} \
  47                {incr i -1} {
  48                set path [lindex $pathList $update_index_cp]
  49                incr update_index_cp
  50
  51                set s $file_states($path)
  52                switch -glob -- [lindex $s 0] {
  53                A? {set new _O}
  54                M? {set new _M}
  55                D_ {set new _D}
  56                D? {set new _?}
  57                ?? {continue}
  58                }
  59                set info [lindex $s 2]
  60                if {$info eq {}} continue
  61
  62                puts -nonewline $fd "$info\t[encoding convertto $path]\0"
  63                display_file $path $new
  64        }
  65
  66        $::main_status update $update_index_cp $totalCnt
  67}
  68
  69proc update_index {msg pathList after} {
  70        global update_index_cp
  71
  72        if {![lock_index update]} return
  73
  74        set update_index_cp 0
  75        set pathList [lsort $pathList]
  76        set totalCnt [llength $pathList]
  77        set batch [expr {int($totalCnt * .01) + 1}]
  78        if {$batch > 25} {set batch 25}
  79
  80        $::main_status start $msg [mc "files"]
  81        set fd [git_write update-index --add --remove -z --stdin]
  82        fconfigure $fd \
  83                -blocking 0 \
  84                -buffering full \
  85                -buffersize 512 \
  86                -encoding binary \
  87                -translation binary
  88        fileevent $fd writable [list \
  89                write_update_index \
  90                $fd \
  91                $pathList \
  92                $totalCnt \
  93                $batch \
  94                $after \
  95                ]
  96}
  97
  98proc write_update_index {fd pathList totalCnt batch after} {
  99        global update_index_cp
 100        global file_states current_diff_path
 101
 102        if {$update_index_cp >= $totalCnt} {
 103                close $fd
 104                unlock_index
 105                $::main_status stop
 106                uplevel #0 $after
 107                return
 108        }
 109
 110        for {set i $batch} \
 111                {$update_index_cp < $totalCnt && $i > 0} \
 112                {incr i -1} {
 113                set path [lindex $pathList $update_index_cp]
 114                incr update_index_cp
 115
 116                switch -glob -- [lindex $file_states($path) 0] {
 117                AD {set new __}
 118                ?D {set new D_}
 119                _O -
 120                AM {set new A_}
 121                U? {
 122                        if {[file exists $path]} {
 123                                set new M_
 124                        } else {
 125                                set new D_
 126                        }
 127                }
 128                ?M {set new M_}
 129                ?? {continue}
 130                }
 131                puts -nonewline $fd "[encoding convertto $path]\0"
 132                display_file $path $new
 133        }
 134
 135        $::main_status update $update_index_cp $totalCnt
 136}
 137
 138proc checkout_index {msg pathList after} {
 139        global update_index_cp
 140
 141        if {![lock_index update]} return
 142
 143        set update_index_cp 0
 144        set pathList [lsort $pathList]
 145        set totalCnt [llength $pathList]
 146        set batch [expr {int($totalCnt * .01) + 1}]
 147        if {$batch > 25} {set batch 25}
 148
 149        $::main_status start $msg [mc "files"]
 150        set fd [git_write checkout-index \
 151                --index \
 152                --quiet \
 153                --force \
 154                -z \
 155                --stdin \
 156                ]
 157        fconfigure $fd \
 158                -blocking 0 \
 159                -buffering full \
 160                -buffersize 512 \
 161                -encoding binary \
 162                -translation binary
 163        fileevent $fd writable [list \
 164                write_checkout_index \
 165                $fd \
 166                $pathList \
 167                $totalCnt \
 168                $batch \
 169                $after \
 170                ]
 171}
 172
 173proc write_checkout_index {fd pathList totalCnt batch after} {
 174        global update_index_cp
 175        global file_states current_diff_path
 176
 177        if {$update_index_cp >= $totalCnt} {
 178                close $fd
 179                unlock_index
 180                $::main_status stop
 181                uplevel #0 $after
 182                return
 183        }
 184
 185        for {set i $batch} \
 186                {$update_index_cp < $totalCnt && $i > 0} \
 187                {incr i -1} {
 188                set path [lindex $pathList $update_index_cp]
 189                incr update_index_cp
 190                switch -glob -- [lindex $file_states($path) 0] {
 191                U? {continue}
 192                ?M -
 193                ?D {
 194                        puts -nonewline $fd "[encoding convertto $path]\0"
 195                        display_file $path ?_
 196                }
 197                }
 198        }
 199
 200        $::main_status update $update_index_cp $totalCnt
 201}
 202
 203proc unstage_helper {txt paths} {
 204        global file_states current_diff_path
 205
 206        if {![lock_index begin-update]} return
 207
 208        set pathList [list]
 209        set after {}
 210        foreach path $paths {
 211                switch -glob -- [lindex $file_states($path) 0] {
 212                A? -
 213                M? -
 214                D? {
 215                        lappend pathList $path
 216                        if {$path eq $current_diff_path} {
 217                                set after {reshow_diff;}
 218                        }
 219                }
 220                }
 221        }
 222        if {$pathList eq {}} {
 223                unlock_index
 224        } else {
 225                update_indexinfo \
 226                        $txt \
 227                        $pathList \
 228                        [concat $after [list ui_ready]]
 229        }
 230}
 231
 232proc do_unstage_selection {} {
 233        global current_diff_path selected_paths
 234
 235        if {[array size selected_paths] > 0} {
 236                unstage_helper \
 237                        {Unstaging selected files from commit} \
 238                        [array names selected_paths]
 239        } elseif {$current_diff_path ne {}} {
 240                unstage_helper \
 241                        [mc "Unstaging %s from commit" [short_path $current_diff_path]] \
 242                        [list $current_diff_path]
 243        }
 244}
 245
 246proc add_helper {txt paths} {
 247        global file_states current_diff_path
 248
 249        if {![lock_index begin-update]} return
 250
 251        set pathList [list]
 252        set after {}
 253        foreach path $paths {
 254                switch -glob -- [lindex $file_states($path) 0] {
 255                _O -
 256                ?M -
 257                ?D -
 258                U? {
 259                        lappend pathList $path
 260                        if {$path eq $current_diff_path} {
 261                                set after {reshow_diff;}
 262                        }
 263                }
 264                }
 265        }
 266        if {$pathList eq {}} {
 267                unlock_index
 268        } else {
 269                update_index \
 270                        $txt \
 271                        $pathList \
 272                        [concat $after {ui_status {Ready to commit.}}]
 273        }
 274}
 275
 276proc do_add_selection {} {
 277        global current_diff_path selected_paths
 278
 279        if {[array size selected_paths] > 0} {
 280                add_helper \
 281                        {Adding selected files} \
 282                        [array names selected_paths]
 283        } elseif {$current_diff_path ne {}} {
 284                add_helper \
 285                        [mc "Adding %s" [short_path $current_diff_path]] \
 286                        [list $current_diff_path]
 287        }
 288}
 289
 290proc do_add_all {} {
 291        global file_states
 292
 293        set paths [list]
 294        foreach path [array names file_states] {
 295                switch -glob -- [lindex $file_states($path) 0] {
 296                U? {continue}
 297                ?M -
 298                ?D {lappend paths $path}
 299                }
 300        }
 301        add_helper {Adding all changed files} $paths
 302}
 303
 304proc revert_helper {txt paths} {
 305        global file_states current_diff_path
 306
 307        if {![lock_index begin-update]} return
 308
 309        set pathList [list]
 310        set after {}
 311        foreach path $paths {
 312                switch -glob -- [lindex $file_states($path) 0] {
 313                U? {continue}
 314                ?M -
 315                ?D {
 316                        lappend pathList $path
 317                        if {$path eq $current_diff_path} {
 318                                set after {reshow_diff;}
 319                        }
 320                }
 321                }
 322        }
 323
 324
 325        # Split question between singular and plural cases, because
 326        # such distinction is needed in some languages. Previously, the
 327        # code used "Revert changes in" for both, but that can't work
 328        # in languages where 'in' must be combined with word from
 329        # rest of string (in diffrent way for both cases of course).
 330        #
 331        # FIXME: Unfortunately, even that isn't enough in some languages
 332        # as they have quite complex plural-form rules. Unfortunately,
 333        # msgcat doesn't seem to support that kind of string translation.
 334        #
 335        set n [llength $pathList]
 336        if {$n == 0} {
 337                unlock_index
 338                return
 339        } elseif {$n == 1} {
 340                set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]]
 341        } else {
 342                set query [mc "Revert changes in these %i files?" $n]
 343        }
 344
 345        set reply [tk_dialog \
 346                .confirm_revert \
 347                "[appname] ([reponame])" \
 348                [mc "Any unstaged changes will be permanently lost by the revert."] \
 349                question \
 350                1 \
 351                [mc "Do Nothing"] \
 352                [mc "Revert Changes"] \
 353                ]
 354        if {$reply == 1} {
 355                checkout_index \
 356                        $txt \
 357                        $pathList \
 358                        [concat $after [list ui_ready]]
 359        } else {
 360                unlock_index
 361        }
 362}
 363
 364proc do_revert_selection {} {
 365        global current_diff_path selected_paths
 366
 367        if {[array size selected_paths] > 0} {
 368                revert_helper \
 369                        {Reverting selected files} \
 370                        [array names selected_paths]
 371        } elseif {$current_diff_path ne {}} {
 372                revert_helper \
 373                        "Reverting [short_path $current_diff_path]" \
 374                        [list $current_diff_path]
 375        }
 376}
 377
 378proc do_select_commit_type {} {
 379        global commit_type selected_commit_type
 380
 381        if {$selected_commit_type eq {new}
 382                && [string match amend* $commit_type]} {
 383                create_new_commit
 384        } elseif {$selected_commit_type eq {amend}
 385                && ![string match amend* $commit_type]} {
 386                load_last_commit
 387
 388                # The amend request was rejected...
 389                #
 390                if {![string match amend* $commit_type]} {
 391                        set selected_commit_type new
 392                }
 393        }
 394}