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