lib / index.tclon commit Merge branch 'maint' (b2bd310)
   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
 355        # Split question between singular and plural cases, because
 356        # such distinction is needed in some languages. Previously, the
 357        # code used "Revert changes in" for both, but that can't work
 358        # in languages where 'in' must be combined with word from
 359        # rest of string (in diffrent way for both cases of course).
 360        #
 361        # FIXME: Unfortunately, even that isn't enough in some languages
 362        # as they have quite complex plural-form rules. Unfortunately,
 363        # msgcat doesn't seem to support that kind of string translation.
 364        #
 365        set n [llength $pathList]
 366        if {$n == 0} {
 367                unlock_index
 368                return
 369        } elseif {$n == 1} {
 370                set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]]
 371        } else {
 372                set query [mc "Revert changes in these %i files?" $n]
 373        }
 374
 375        set reply [tk_dialog \
 376                .confirm_revert \
 377                "[appname] ([reponame])" \
 378                [mc "Any unstaged changes will be permanently lost by the revert."] \
 379                question \
 380                1 \
 381                [mc "Do Nothing"] \
 382                [mc "Revert Changes"] \
 383                ]
 384        if {$reply == 1} {
 385                checkout_index \
 386                        $txt \
 387                        $pathList \
 388                        [concat $after [list ui_ready]]
 389        } else {
 390                unlock_index
 391        }
 392}
 393
 394proc do_revert_selection {} {
 395        global current_diff_path selected_paths
 396
 397        if {[array size selected_paths] > 0} {
 398                revert_helper \
 399                        {Reverting selected files} \
 400                        [array names selected_paths]
 401        } elseif {$current_diff_path ne {}} {
 402                revert_helper \
 403                        "Reverting [short_path $current_diff_path]" \
 404                        [list $current_diff_path]
 405        }
 406}
 407
 408proc do_select_commit_type {} {
 409        global commit_type selected_commit_type
 410
 411        if {$selected_commit_type eq {new}
 412                && [string match amend* $commit_type]} {
 413                create_new_commit
 414        } elseif {$selected_commit_type eq {amend}
 415                && ![string match amend* $commit_type]} {
 416                load_last_commit
 417
 418                # The amend request was rejected...
 419                #
 420                if {![string match amend* $commit_type]} {
 421                        set selected_commit_type new
 422                }
 423        }
 424}