Adding upstream version 1:2.47.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
parent
fd5a0bafa2
commit
54102a2c29
4535 changed files with 1510258 additions and 0 deletions
753
git-gui/lib/index.tcl
Normal file
753
git-gui/lib/index.tcl
Normal file
|
@ -0,0 +1,753 @@
|
|||
# git-gui index (add/remove) support
|
||||
# Copyright (C) 2006, 2007 Shawn Pearce
|
||||
|
||||
proc _delete_indexlock {} {
|
||||
if {[catch {file delete -- [gitdir index.lock]} err]} {
|
||||
error_popup [strcat [mc "Unable to unlock the index."] "\n\n$err"]
|
||||
}
|
||||
}
|
||||
|
||||
proc close_and_unlock_index {fd after} {
|
||||
if {![catch {_close_updateindex $fd} err]} {
|
||||
unlock_index
|
||||
uplevel #0 $after
|
||||
} else {
|
||||
rescan_on_error $err $after
|
||||
}
|
||||
}
|
||||
|
||||
proc _close_updateindex {fd} {
|
||||
fconfigure $fd -blocking 1
|
||||
close $fd
|
||||
}
|
||||
|
||||
proc rescan_on_error {err {after {}}} {
|
||||
global use_ttk NS
|
||||
|
||||
set w .indexfried
|
||||
Dialog $w
|
||||
wm withdraw $w
|
||||
wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
|
||||
wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
|
||||
set s [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."]
|
||||
text $w.msg -yscrollcommand [list $w.vs set] \
|
||||
-width [string length $s] -relief flat \
|
||||
-borderwidth 0 -highlightthickness 0 \
|
||||
-background [get_bg_color $w]
|
||||
$w.msg tag configure bold -font font_uibold -justify center
|
||||
${NS}::scrollbar $w.vs -command [list $w.msg yview]
|
||||
$w.msg insert end $s bold \n\n$err {}
|
||||
$w.msg configure -state disabled
|
||||
|
||||
${NS}::button $w.continue \
|
||||
-text [mc "Continue"] \
|
||||
-command [list destroy $w]
|
||||
${NS}::button $w.unlock \
|
||||
-text [mc "Unlock Index"] \
|
||||
-command "destroy $w; _delete_indexlock"
|
||||
grid $w.msg - $w.vs -sticky news
|
||||
grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2
|
||||
grid columnconfigure $w 0 -weight 1
|
||||
grid rowconfigure $w 0 -weight 1
|
||||
|
||||
wm protocol $w WM_DELETE_WINDOW update
|
||||
bind $w.continue <Visibility> "
|
||||
grab $w
|
||||
focus %W
|
||||
"
|
||||
wm deiconify $w
|
||||
tkwait window $w
|
||||
|
||||
$::main_status stop_all
|
||||
unlock_index
|
||||
rescan [concat $after {ui_ready;}] 0
|
||||
}
|
||||
|
||||
proc update_indexinfo {msg path_list after} {
|
||||
global update_index_cp
|
||||
|
||||
if {![lock_index update]} return
|
||||
|
||||
set update_index_cp 0
|
||||
set path_list [lsort $path_list]
|
||||
set total_cnt [llength $path_list]
|
||||
set batch [expr {int($total_cnt * .01) + 1}]
|
||||
if {$batch > 25} {set batch 25}
|
||||
|
||||
set status_bar_operation [$::main_status start $msg [mc "files"]]
|
||||
set fd [git_write update-index -z --index-info]
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-buffering full \
|
||||
-buffersize 512 \
|
||||
-encoding binary \
|
||||
-translation binary
|
||||
fileevent $fd writable [list \
|
||||
write_update_indexinfo \
|
||||
$fd \
|
||||
$path_list \
|
||||
$total_cnt \
|
||||
$batch \
|
||||
$status_bar_operation \
|
||||
$after \
|
||||
]
|
||||
}
|
||||
|
||||
proc write_update_indexinfo {fd path_list total_cnt batch status_bar_operation \
|
||||
after} {
|
||||
global update_index_cp
|
||||
global file_states current_diff_path
|
||||
|
||||
if {$update_index_cp >= $total_cnt} {
|
||||
$status_bar_operation stop
|
||||
close_and_unlock_index $fd $after
|
||||
return
|
||||
}
|
||||
|
||||
for {set i $batch} \
|
||||
{$update_index_cp < $total_cnt && $i > 0} \
|
||||
{incr i -1} {
|
||||
set path [lindex $path_list $update_index_cp]
|
||||
incr update_index_cp
|
||||
|
||||
set s $file_states($path)
|
||||
switch -glob -- [lindex $s 0] {
|
||||
A? {set new _O}
|
||||
MT -
|
||||
TM -
|
||||
T_ {set new _T}
|
||||
M? {set new _M}
|
||||
TD -
|
||||
D_ {set new _D}
|
||||
D? {set new _?}
|
||||
?? {continue}
|
||||
}
|
||||
set info [lindex $s 2]
|
||||
if {$info eq {}} continue
|
||||
|
||||
puts -nonewline $fd "$info\t[encoding convertto utf-8 $path]\0"
|
||||
display_file $path $new
|
||||
}
|
||||
|
||||
$status_bar_operation update $update_index_cp $total_cnt
|
||||
}
|
||||
|
||||
proc update_index {msg path_list after} {
|
||||
global update_index_cp
|
||||
|
||||
if {![lock_index update]} return
|
||||
|
||||
set update_index_cp 0
|
||||
set path_list [lsort $path_list]
|
||||
set total_cnt [llength $path_list]
|
||||
set batch [expr {int($total_cnt * .01) + 1}]
|
||||
if {$batch > 25} {set batch 25}
|
||||
|
||||
set status_bar_operation [$::main_status start $msg [mc "files"]]
|
||||
set fd [git_write update-index --add --remove -z --stdin]
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-buffering full \
|
||||
-buffersize 512 \
|
||||
-encoding binary \
|
||||
-translation binary
|
||||
fileevent $fd writable [list \
|
||||
write_update_index \
|
||||
$fd \
|
||||
$path_list \
|
||||
$total_cnt \
|
||||
$batch \
|
||||
$status_bar_operation \
|
||||
$after \
|
||||
]
|
||||
}
|
||||
|
||||
proc write_update_index {fd path_list total_cnt batch status_bar_operation \
|
||||
after} {
|
||||
global update_index_cp
|
||||
global file_states current_diff_path
|
||||
|
||||
if {$update_index_cp >= $total_cnt} {
|
||||
$status_bar_operation stop
|
||||
close_and_unlock_index $fd $after
|
||||
return
|
||||
}
|
||||
|
||||
for {set i $batch} \
|
||||
{$update_index_cp < $total_cnt && $i > 0} \
|
||||
{incr i -1} {
|
||||
set path [lindex $path_list $update_index_cp]
|
||||
incr update_index_cp
|
||||
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
AD {set new __}
|
||||
?D {set new D_}
|
||||
_O -
|
||||
AT -
|
||||
AM {set new A_}
|
||||
TM -
|
||||
MT -
|
||||
_T {set new T_}
|
||||
_U -
|
||||
U? {
|
||||
if {[file exists $path]} {
|
||||
set new M_
|
||||
} else {
|
||||
set new D_
|
||||
}
|
||||
}
|
||||
?M {set new M_}
|
||||
?? {continue}
|
||||
}
|
||||
puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
|
||||
display_file $path $new
|
||||
}
|
||||
|
||||
$status_bar_operation update $update_index_cp $total_cnt
|
||||
}
|
||||
|
||||
proc checkout_index {msg path_list after capture_error} {
|
||||
global update_index_cp
|
||||
|
||||
if {![lock_index update]} return
|
||||
|
||||
set update_index_cp 0
|
||||
set path_list [lsort $path_list]
|
||||
set total_cnt [llength $path_list]
|
||||
set batch [expr {int($total_cnt * .01) + 1}]
|
||||
if {$batch > 25} {set batch 25}
|
||||
|
||||
set status_bar_operation [$::main_status start $msg [mc "files"]]
|
||||
set fd [git_write checkout-index \
|
||||
--index \
|
||||
--quiet \
|
||||
--force \
|
||||
-z \
|
||||
--stdin \
|
||||
]
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-buffering full \
|
||||
-buffersize 512 \
|
||||
-encoding binary \
|
||||
-translation binary
|
||||
fileevent $fd writable [list \
|
||||
write_checkout_index \
|
||||
$fd \
|
||||
$path_list \
|
||||
$total_cnt \
|
||||
$batch \
|
||||
$status_bar_operation \
|
||||
$after \
|
||||
$capture_error \
|
||||
]
|
||||
}
|
||||
|
||||
proc write_checkout_index {fd path_list total_cnt batch status_bar_operation \
|
||||
after capture_error} {
|
||||
global update_index_cp
|
||||
global file_states current_diff_path
|
||||
|
||||
if {$update_index_cp >= $total_cnt} {
|
||||
$status_bar_operation stop
|
||||
|
||||
# We do not unlock the index directly here because this
|
||||
# operation expects to potentially run in parallel with file
|
||||
# deletions scheduled by revert_helper. We're done with the
|
||||
# update index, so we close it, but actually unlocking the index
|
||||
# and dealing with potential errors is deferred to the chord
|
||||
# body that runs when all async operations are completed.
|
||||
#
|
||||
# (See after_chord in revert_helper.)
|
||||
|
||||
if {[catch {_close_updateindex $fd} err]} {
|
||||
uplevel #0 $capture_error [list $err]
|
||||
}
|
||||
|
||||
uplevel #0 $after
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for {set i $batch} \
|
||||
{$update_index_cp < $total_cnt && $i > 0} \
|
||||
{incr i -1} {
|
||||
set path [lindex $path_list $update_index_cp]
|
||||
incr update_index_cp
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
U? {continue}
|
||||
?M -
|
||||
?T -
|
||||
?D {
|
||||
puts -nonewline $fd "[encoding convertto utf-8 $path]\0"
|
||||
display_file $path ?_
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$status_bar_operation update $update_index_cp $total_cnt
|
||||
}
|
||||
|
||||
proc unstage_helper {txt paths} {
|
||||
global file_states current_diff_path
|
||||
|
||||
if {![lock_index begin-update]} return
|
||||
|
||||
set path_list [list]
|
||||
set after {}
|
||||
foreach path $paths {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
A? -
|
||||
M? -
|
||||
T? -
|
||||
D? {
|
||||
lappend path_list $path
|
||||
if {$path eq $current_diff_path} {
|
||||
set after {reshow_diff;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$path_list eq {}} {
|
||||
unlock_index
|
||||
} else {
|
||||
update_indexinfo \
|
||||
$txt \
|
||||
$path_list \
|
||||
[concat $after {ui_ready;}]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_unstage_selection {} {
|
||||
global current_diff_path selected_paths
|
||||
|
||||
if {[array size selected_paths] > 0} {
|
||||
unstage_helper \
|
||||
[mc "Unstaging selected files from commit"] \
|
||||
[array names selected_paths]
|
||||
} elseif {$current_diff_path ne {}} {
|
||||
unstage_helper \
|
||||
[mc "Unstaging %s from commit" [short_path $current_diff_path]] \
|
||||
[list $current_diff_path]
|
||||
}
|
||||
}
|
||||
|
||||
proc add_helper {txt paths} {
|
||||
global file_states current_diff_path
|
||||
|
||||
if {![lock_index begin-update]} return
|
||||
|
||||
set path_list [list]
|
||||
set after {}
|
||||
foreach path $paths {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
_U -
|
||||
U? {
|
||||
if {$path eq $current_diff_path} {
|
||||
unlock_index
|
||||
merge_stage_workdir $path
|
||||
return
|
||||
}
|
||||
}
|
||||
_O -
|
||||
?M -
|
||||
?D -
|
||||
?T {
|
||||
lappend path_list $path
|
||||
if {$path eq $current_diff_path} {
|
||||
set after {reshow_diff;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$path_list eq {}} {
|
||||
unlock_index
|
||||
} else {
|
||||
update_index \
|
||||
$txt \
|
||||
$path_list \
|
||||
[concat $after {ui_status [mc "Ready to commit."];}]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_add_selection {} {
|
||||
global current_diff_path selected_paths
|
||||
|
||||
if {[array size selected_paths] > 0} {
|
||||
add_helper \
|
||||
[mc "Adding selected files"] \
|
||||
[array names selected_paths]
|
||||
} elseif {$current_diff_path ne {}} {
|
||||
add_helper \
|
||||
[mc "Adding %s" [short_path $current_diff_path]] \
|
||||
[list $current_diff_path]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_add_all {} {
|
||||
global file_states
|
||||
|
||||
set paths [list]
|
||||
set untracked_paths [list]
|
||||
foreach path [array names file_states] {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
U? {continue}
|
||||
?M -
|
||||
?T -
|
||||
?D {lappend paths $path}
|
||||
?O {lappend untracked_paths $path}
|
||||
}
|
||||
}
|
||||
if {[llength $untracked_paths]} {
|
||||
set reply 0
|
||||
switch -- [get_config gui.stageuntracked] {
|
||||
no {
|
||||
set reply 0
|
||||
}
|
||||
yes {
|
||||
set reply 1
|
||||
}
|
||||
ask -
|
||||
default {
|
||||
set reply [ask_popup [mc "Stage %d untracked files?" \
|
||||
[llength $untracked_paths]]]
|
||||
}
|
||||
}
|
||||
if {$reply} {
|
||||
set paths [concat $paths $untracked_paths]
|
||||
}
|
||||
}
|
||||
add_helper [mc "Adding all changed files"] $paths
|
||||
}
|
||||
|
||||
# Copied from TclLib package "lambda".
|
||||
proc lambda {arguments body args} {
|
||||
return [list ::apply [list $arguments $body] {*}$args]
|
||||
}
|
||||
|
||||
proc revert_helper {txt paths} {
|
||||
global file_states current_diff_path
|
||||
|
||||
if {![lock_index begin-update]} return
|
||||
|
||||
# Common "after" functionality that waits until multiple asynchronous
|
||||
# operations are complete (by waiting for them to activate their notes
|
||||
# on the chord).
|
||||
#
|
||||
# The asynchronous operations are each indicated below by a comment
|
||||
# before the code block that starts the async operation.
|
||||
set after_chord [SimpleChord::new {
|
||||
if {[string trim $err] != ""} {
|
||||
rescan_on_error $err
|
||||
} else {
|
||||
unlock_index
|
||||
if {$should_reshow_diff} { reshow_diff }
|
||||
ui_ready
|
||||
}
|
||||
}]
|
||||
|
||||
$after_chord eval { set should_reshow_diff 0 }
|
||||
|
||||
# This function captures an error for processing when after_chord is
|
||||
# completed. (The chord is curried into the lambda function.)
|
||||
set capture_error [lambda \
|
||||
{chord error} \
|
||||
{ $chord eval [list set err $error] } \
|
||||
$after_chord]
|
||||
|
||||
# We don't know how many notes we're going to create (it's dynamic based
|
||||
# on conditional paths below), so create a common note that will delay
|
||||
# the chord's completion until we activate it, and then activate it
|
||||
# after all the other notes have been created.
|
||||
set after_common_note [$after_chord add_note]
|
||||
|
||||
set path_list [list]
|
||||
set untracked_list [list]
|
||||
|
||||
foreach path $paths {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
U? {continue}
|
||||
?O {
|
||||
lappend untracked_list $path
|
||||
}
|
||||
?M -
|
||||
?T -
|
||||
?D {
|
||||
lappend path_list $path
|
||||
if {$path eq $current_diff_path} {
|
||||
$after_chord eval { set should_reshow_diff 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set path_cnt [llength $path_list]
|
||||
set untracked_cnt [llength $untracked_list]
|
||||
|
||||
# Asynchronous operation: revert changes by checking them out afresh
|
||||
# from the index.
|
||||
if {$path_cnt > 0} {
|
||||
# Split question between singular and plural cases, because
|
||||
# such distinction is needed in some languages. Previously, the
|
||||
# code used "Revert changes in" for both, but that can't work
|
||||
# in languages where 'in' must be combined with word from
|
||||
# rest of string (in different way for both cases of course).
|
||||
#
|
||||
# FIXME: Unfortunately, even that isn't enough in some languages
|
||||
# as they have quite complex plural-form rules. Unfortunately,
|
||||
# msgcat doesn't seem to support that kind of string
|
||||
# translation.
|
||||
#
|
||||
if {$path_cnt == 1} {
|
||||
set query [mc \
|
||||
"Revert changes in file %s?" \
|
||||
[short_path [lindex $path_list]] \
|
||||
]
|
||||
} else {
|
||||
set query [mc \
|
||||
"Revert changes in these %i files?" \
|
||||
$path_cnt]
|
||||
}
|
||||
|
||||
set reply [tk_dialog \
|
||||
.confirm_revert \
|
||||
"[appname] ([reponame])" \
|
||||
"$query
|
||||
|
||||
[mc "Any unstaged changes will be permanently lost by the revert."]" \
|
||||
question \
|
||||
1 \
|
||||
[mc "Do Nothing"] \
|
||||
[mc "Revert Changes"] \
|
||||
]
|
||||
|
||||
if {$reply == 1} {
|
||||
set note [$after_chord add_note]
|
||||
checkout_index \
|
||||
$txt \
|
||||
$path_list \
|
||||
[list $note activate] \
|
||||
$capture_error
|
||||
}
|
||||
}
|
||||
|
||||
# Asynchronous operation: Deletion of untracked files.
|
||||
if {$untracked_cnt > 0} {
|
||||
# Split question between singular and plural cases, because
|
||||
# such distinction is needed in some languages.
|
||||
#
|
||||
# FIXME: Unfortunately, even that isn't enough in some languages
|
||||
# as they have quite complex plural-form rules. Unfortunately,
|
||||
# msgcat doesn't seem to support that kind of string
|
||||
# translation.
|
||||
#
|
||||
if {$untracked_cnt == 1} {
|
||||
set query [mc \
|
||||
"Delete untracked file %s?" \
|
||||
[short_path [lindex $untracked_list]] \
|
||||
]
|
||||
} else {
|
||||
set query [mc \
|
||||
"Delete these %i untracked files?" \
|
||||
$untracked_cnt \
|
||||
]
|
||||
}
|
||||
|
||||
set reply [tk_dialog \
|
||||
.confirm_revert \
|
||||
"[appname] ([reponame])" \
|
||||
"$query
|
||||
|
||||
[mc "Files will be permanently deleted."]" \
|
||||
question \
|
||||
1 \
|
||||
[mc "Do Nothing"] \
|
||||
[mc "Delete Files"] \
|
||||
]
|
||||
|
||||
if {$reply == 1} {
|
||||
$after_chord eval { set should_reshow_diff 1 }
|
||||
|
||||
set note [$after_chord add_note]
|
||||
delete_files $untracked_list [list $note activate]
|
||||
}
|
||||
}
|
||||
|
||||
# Activate the common note. If no other notes were created, this
|
||||
# completes the chord. If other notes were created, then this common
|
||||
# note prevents a race condition where the chord might complete early.
|
||||
$after_common_note activate
|
||||
}
|
||||
|
||||
# Delete all of the specified files, performing deletion in batches to allow the
|
||||
# UI to remain responsive and updated.
|
||||
proc delete_files {path_list after} {
|
||||
# Enable progress bar status updates
|
||||
set status_bar_operation [$::main_status \
|
||||
start \
|
||||
[mc "Deleting"] \
|
||||
[mc "files"]]
|
||||
|
||||
set path_index 0
|
||||
set deletion_errors [list]
|
||||
set batch_size 50
|
||||
|
||||
delete_helper \
|
||||
$path_list \
|
||||
$path_index \
|
||||
$deletion_errors \
|
||||
$batch_size \
|
||||
$status_bar_operation \
|
||||
$after
|
||||
}
|
||||
|
||||
# Helper function to delete a list of files in batches. Each call deletes one
|
||||
# batch of files, and then schedules a call for the next batch after any UI
|
||||
# messages have been processed.
|
||||
proc delete_helper {path_list path_index deletion_errors batch_size \
|
||||
status_bar_operation after} {
|
||||
global file_states
|
||||
|
||||
set path_cnt [llength $path_list]
|
||||
|
||||
set batch_remaining $batch_size
|
||||
|
||||
while {$batch_remaining > 0} {
|
||||
if {$path_index >= $path_cnt} { break }
|
||||
|
||||
set path [lindex $path_list $path_index]
|
||||
|
||||
set deletion_failed [catch {file delete -- $path} deletion_error]
|
||||
|
||||
if {$deletion_failed} {
|
||||
lappend deletion_errors [list "$deletion_error"]
|
||||
} else {
|
||||
remove_empty_directories [file dirname $path]
|
||||
|
||||
# Don't assume the deletion worked. Remove the file from
|
||||
# the UI, but only if it no longer exists.
|
||||
if {![path_exists $path]} {
|
||||
unset file_states($path)
|
||||
display_file $path __
|
||||
}
|
||||
}
|
||||
|
||||
incr path_index 1
|
||||
incr batch_remaining -1
|
||||
}
|
||||
|
||||
# Update the progress bar to indicate that this batch has been
|
||||
# completed. The update will be visible when this procedure returns
|
||||
# and allows the UI thread to process messages.
|
||||
$status_bar_operation update $path_index $path_cnt
|
||||
|
||||
if {$path_index < $path_cnt} {
|
||||
# The Tcler's Wiki lists this as the best practice for keeping
|
||||
# a UI active and processing messages during a long-running
|
||||
# operation.
|
||||
|
||||
after idle [list after 0 [list \
|
||||
delete_helper \
|
||||
$path_list \
|
||||
$path_index \
|
||||
$deletion_errors \
|
||||
$batch_size \
|
||||
$status_bar_operation \
|
||||
$after
|
||||
]]
|
||||
} else {
|
||||
# Finish the status bar operation.
|
||||
$status_bar_operation stop
|
||||
|
||||
# Report error, if any, based on how many deletions failed.
|
||||
set deletion_error_cnt [llength $deletion_errors]
|
||||
|
||||
if {($deletion_error_cnt > 0)
|
||||
&& ($deletion_error_cnt <= [MAX_VERBOSE_FILES_IN_DELETION_ERROR])} {
|
||||
set error_text [mc "Encountered errors deleting files:\n"]
|
||||
|
||||
foreach deletion_error $deletion_errors {
|
||||
append error_text "* [lindex $deletion_error 0]\n"
|
||||
}
|
||||
|
||||
error_popup $error_text
|
||||
} elseif {$deletion_error_cnt == $path_cnt} {
|
||||
error_popup [mc \
|
||||
"None of the %d selected files could be deleted." \
|
||||
$path_cnt \
|
||||
]
|
||||
} elseif {$deletion_error_cnt > 1} {
|
||||
error_popup [mc \
|
||||
"%d of the %d selected files could not be deleted." \
|
||||
$deletion_error_cnt \
|
||||
$path_cnt \
|
||||
]
|
||||
}
|
||||
|
||||
uplevel #0 $after
|
||||
}
|
||||
}
|
||||
|
||||
proc MAX_VERBOSE_FILES_IN_DELETION_ERROR {} { return 10; }
|
||||
|
||||
# This function is from the TCL documentation:
|
||||
#
|
||||
# https://wiki.tcl-lang.org/page/file+exists
|
||||
#
|
||||
# [file exists] returns false if the path does exist but is a symlink to a path
|
||||
# that doesn't exist. This proc returns true if the path exists, regardless of
|
||||
# whether it is a symlink and whether it is broken.
|
||||
proc path_exists {name} {
|
||||
expr {![catch {file lstat $name finfo}]}
|
||||
}
|
||||
|
||||
# Remove as many empty directories as we can starting at the specified path,
|
||||
# walking up the directory tree. If we encounter a directory that is not
|
||||
# empty, or if a directory deletion fails, then we stop the operation and
|
||||
# return to the caller. Even if this procedure fails to delete any
|
||||
# directories at all, it does not report failure.
|
||||
proc remove_empty_directories {directory_path} {
|
||||
set parent_path [file dirname $directory_path]
|
||||
|
||||
while {$parent_path != $directory_path} {
|
||||
set contents [glob -nocomplain -dir $directory_path *]
|
||||
|
||||
if {[llength $contents] > 0} { break }
|
||||
if {[catch {file delete -- $directory_path}]} { break }
|
||||
|
||||
set directory_path $parent_path
|
||||
set parent_path [file dirname $directory_path]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_revert_selection {} {
|
||||
global current_diff_path selected_paths
|
||||
|
||||
if {[array size selected_paths] > 0} {
|
||||
revert_helper \
|
||||
[mc "Reverting selected files"] \
|
||||
[array names selected_paths]
|
||||
} elseif {$current_diff_path ne {}} {
|
||||
revert_helper \
|
||||
[mc "Reverting %s" [short_path $current_diff_path]] \
|
||||
[list $current_diff_path]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_select_commit_type {} {
|
||||
global commit_type commit_type_is_amend
|
||||
|
||||
if {$commit_type_is_amend == 0
|
||||
&& [string match amend* $commit_type]} {
|
||||
create_new_commit
|
||||
} elseif {$commit_type_is_amend == 1
|
||||
&& ![string match amend* $commit_type]} {
|
||||
load_last_commit
|
||||
|
||||
# The amend request was rejected...
|
||||
#
|
||||
if {![string match amend* $commit_type]} {
|
||||
set commit_type_is_amend 0
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue