Skip to content

Commit 0d2448c

Browse files
Merge pull request #1 from TomfromBerlin/TomfromBerlin-patch-1
Enhance user feedback and error handling
2 parents 81f8cec + adde007 commit 0d2448c

File tree

1 file changed

+177
-27
lines changed

1 file changed

+177
-27
lines changed

zsh-disk-guard.zsh

Lines changed: 177 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
# Author: Tom from Berlin
1010
# License: MIT
1111
# Repository: https://github.com/TomfromBerlin/zsh-disk-guard
12+
# ──────────────────────────────────────────────────────────────────
13+
# "You can lead a horse to water, but you can't make it read warnings."
14+
# — Ancient IT Wisdom
15+
# ──────────────────────────────────────────────────────────────────
1216
# ===================================================================
1317
# ──────────────────────────────────────────────────────────────────
1418
# Version Check
@@ -253,6 +257,13 @@ _zsh_disk_guard_verify() {
253257
shift
254258
local sources=("$@")
255259

260+
# Color definitions
261+
local GREEN=$'\e[0;32;40m'
262+
local CYAN=$'\e[0;36;4m' # underlined
263+
local YELLOW=$'\e[1;33;40m'
264+
local RED=$'\e[0;31;40m'
265+
local NC=$'\e[0m'
266+
256267
_zsh_disk_guard_debug "Checking target: $target"
257268
[[ -z "$target" ]] && return 0
258269

@@ -295,7 +306,7 @@ _zsh_disk_guard_verify() {
295306
_zsh_disk_guard_debug "Quick check: $(_zsh_disk_guard_format_size $estimated_size)"
296307
if (( estimated_size < ZSH_DISK_GUARD_DEEP_THRESHOLD )); then
297308
if (( usage >= ZSH_DISK_GUARD_THRESHOLD )); then
298-
echo "⚠️ Warning: Partition $mountpoint is ${usage}% full!" >&2
309+
printf '\n%s\n' "⚠️ ${RED}Warning${NC}: Partition ${CYAN}$mountpoint${NC} is ${YELLOW}${usage}%${NC} full!" >&2
299310
if [[ -o interactive || -t 0 ]]; then
300311
read -q "REPLY?Continue anyway? [y/N] "
301312
echo
@@ -436,7 +447,7 @@ _zsh_disk_guard_progress_bar() {
436447
# Display progress bar at bottom of terminal
437448
printf '\e[s' # Save cursor position
438449
printf '\e[%d;1H' "$LINES" # Move to bottom row, first column
439-
printf '%s%s%s%s' "$bar" "$perc_color" "$suffix" "$NC"
450+
printf '%s Files: %d (%s%d%%%s)' "$bar" "$file_count" "$perc_color" "$perc_done" "$NC"
440451
printf '\e[K' # Clear rest of line
441452
printf '\e[u' # Restore cursor position
442453
}
@@ -496,13 +507,72 @@ _zsh_disk_guard_cp() {
496507
local LC_ALL=C
497508

498509
# If plugin is disabled, just run normal cp
499-
(( ZSH_DISK_GUARD_ENABLED )) || { command cp "$@"; return $?; }
510+
(( ZSH_DISK_GUARD_ENABLED )) || { cp "$@"; return $?; }
500511

501512
local args=("$@")
502513
local target="${args[-1]}"
503514
local sources=("${args[@]:0:-1}")
504515

505-
# Verify disk space before starting
516+
# Color definitions
517+
local GREEN=$'\e[0;32;40m'
518+
local CYAN=$'\e[0;36;1m'
519+
local YELLOW=$'\e[1;33;40m'
520+
local RED=$'\e[0;31;40m'
521+
local NC=$'\e[0m'
522+
523+
# ──────────────────────────────────────────────────────────────
524+
# Check for missing source files BEFORE any other operation
525+
# ──────────────────────────────────────────────────────────────
526+
local missing_files=()
527+
local existing_sources=()
528+
529+
for source in "${sources[@]}"; do
530+
if [[ ! -e "$source" ]]; then
531+
missing_files+=("${source:t}")
532+
else
533+
existing_sources+=("$source")
534+
fi
535+
done
536+
537+
# If files are missing, warn user and ask whether to continue
538+
if (( ${#missing_files[@]} > 0 )); then
539+
printf '\n%s\n' "⚠️ ${RED}Warning${NC}: ${YELLOW}${#missing_files[@]}${NC} source file(s) ${RED}not found${NC}:" >&2
540+
for file in "${missing_files[@]}"; do
541+
printf ' %s %s\n' "" "${CYAN}${file}${NC}" >&2
542+
done
543+
printf '\n'
544+
545+
if (( ${#existing_sources[@]} > 0 )); then
546+
read -q "reply?Continue with remaining ${YELLOW}${#existing_sources[@]}${NC} file(s)? [y/N] " </dev/tty
547+
echo
548+
if [[ "$reply" != [Yy] ]]; then
549+
printf '%s\n' "Operation cancelled."
550+
# Restore settings before returning
551+
if (( reporttime_was_set )); then
552+
REPORTTIME=$saved_reporttime
553+
else
554+
unset REPORTTIME
555+
fi
556+
(( xtrace_was_set )) && set -x
557+
return 1
558+
fi
559+
else
560+
printf '%s\n' "${RED}Error${NC}: No valid source files found. Operation cancelled." >&2
561+
# Restore settings before returning
562+
if (( reporttime_was_set )); then
563+
REPORTTIME=$saved_reporttime
564+
else
565+
unset REPORTTIME
566+
fi
567+
(( xtrace_was_set )) && set -x
568+
return 1
569+
fi
570+
571+
# Update sources to only include existing files
572+
sources=("${existing_sources[@]}")
573+
fi
574+
575+
# Verify disk space before starting (only for existing files)
506576
_zsh_disk_guard_verify "$target" "${sources[@]}" || return 1
507577

508578
local total_files=${#sources[@]}
@@ -523,16 +593,17 @@ _zsh_disk_guard_cp() {
523593

524594
# Display current file with size
525595
local size_display=$(_zsh_disk_guard_format_size $source_size)
526-
printf '→ %s (%s)\n' "${source:t}" "$size_display"
596+
printf '\n → %s (%s)' "${source:t}" "$size_display"
527597

528598
local target_file="$target/${source:t}"
529599

530600
# Check if target file exists and prompt for overwrite (interactive mode only)
531601
if [[ -f "$target_file" ]] && [[ -o interactive ]]; then
532-
read -q "reply?File exists. Overwrite ${target_file:t}? [y/N] " </dev/tty
602+
printf '\n%s\n' "⚠️ ${RED}Warning${NC}: ${CYAN}${target_file:t}${NC} already exists in ${CYAN}${args[-1]}${NC}!" >&2
603+
read -q "reply? Overwrite ${target_file:t}? [y/N] " </dev/tty
533604
echo
534605
if [[ "$reply" != [Yy] ]]; then
535-
printf "Skipped: %s\n" "${source:t}"
606+
printf '%s\n' " Skipped: ${source:t}"
536607
continue
537608
fi
538609
fi
@@ -579,7 +650,7 @@ _zsh_disk_guard_cp() {
579650
if (( cp_status != 0 )); then
580651
printf '\n❌ Error copying %s (exit code: %d)\n' "${source:t}" "$cp_status" >&2
581652
_zsh_disk_guard_deinit_term
582-
# Restore settings
653+
# Restore REPORTTIME settings
583654
if (( reporttime_was_set )); then
584655
REPORTTIME=$saved_reporttime
585656
else
@@ -598,7 +669,6 @@ _zsh_disk_guard_cp() {
598669

599670
# Ensure 100% at the end
600671
_zsh_disk_guard_progress_bar 100 100 $total_files
601-
602672
_zsh_disk_guard_deinit_term
603673

604674
# Calculate elapsed time and format it cleanly
@@ -622,7 +692,11 @@ _zsh_disk_guard_cp() {
622692
fi
623693

624694
# Display success summary
625-
printf '\n✅ Done! Copied %s in %s\n\n' "$(_zsh_disk_guard_format_size $total_bytes_copied)" "$elapsed_display"
695+
if [[ $total_bytes_copied = 0 ]]; then
696+
printf '\n%s\n\n' "ℹ️ Nothing has changed!"
697+
else
698+
printf '\n\n✅ Done! Copied %s in %s\n\n' "$(_zsh_disk_guard_format_size $total_bytes_copied)" "$elapsed_display"
699+
fi
626700

627701
# Restore REPORTTIME to original state
628702
if (( reporttime_was_set )); then
@@ -660,7 +734,66 @@ _zsh_disk_guard_mv() {
660734
local target="${args[-1]}"
661735
local sources=("${args[@]:0:-1}")
662736

663-
# Verify disk space before starting
737+
# Color definitions
738+
local GREEN=$'\e[0;32;40m'
739+
local CYAN=$'\e[0;36;1m'
740+
local YELLOW=$'\e[1;33;40m'
741+
local RED=$'\e[0;31;40m'
742+
local NC=$'\e[0m'
743+
744+
# ──────────────────────────────────────────────────────────────
745+
# Check for missing source files BEFORE any other operation
746+
# ──────────────────────────────────────────────────────────────
747+
local missing_files=()
748+
local existing_sources=()
749+
750+
for source in "${sources[@]}"; do
751+
if [[ ! -e "$source" ]]; then
752+
missing_files+=("${source:t}")
753+
else
754+
existing_sources+=("$source")
755+
fi
756+
done
757+
758+
# If files are missing, warn user and ask whether to continue
759+
if (( ${#missing_files[@]} > 0 )); then
760+
printf '\n%s\n' "⚠️ ${RED}Warning${NC}: ${YELLOW}${#missing_files[@]}${NC} source file(s) ${RED}not found${NC}:" >&2
761+
for file in "${missing_files[@]}"; do
762+
printf ' %s %s\n' "" "${CYAN}${file}${NC}" >&2
763+
done
764+
printf '\n'
765+
766+
if (( ${#existing_sources[@]} > 0 )); then
767+
read -q "reply?Continue with remaining ${YELLOW}${#existing_sources[@]}${NC} file(s)? [y/N] " </dev/tty
768+
echo
769+
if [[ "$reply" != [Yy] ]]; then
770+
printf '%s\n' "Operation cancelled."
771+
# Restore settings before returning
772+
if (( reporttime_was_set )); then
773+
REPORTTIME=$saved_reporttime
774+
else
775+
unset REPORTTIME
776+
fi
777+
(( xtrace_was_set )) && set -x
778+
return 1
779+
fi
780+
else
781+
printf '%s\n' "${RED}Error${NC}: No valid source files found. Operation cancelled." >&2
782+
# Restore settings before returning
783+
if (( reporttime_was_set )); then
784+
REPORTTIME=$saved_reporttime
785+
else
786+
unset REPORTTIME
787+
fi
788+
(( xtrace_was_set )) && set -x
789+
return 1
790+
fi
791+
792+
# Update sources to only include existing files
793+
sources=("${existing_sources[@]}")
794+
fi
795+
796+
# Verify disk space before starting (only for existing files)
664797
_zsh_disk_guard_verify "$target" "${sources[@]}" || return 1
665798

666799
local total_files=${#sources[@]}
@@ -687,10 +820,11 @@ _zsh_disk_guard_mv() {
687820

688821
# Check if target file exists and prompt for overwrite (interactive mode only)
689822
if [[ -f "$target_file" ]] && [[ -o interactive ]]; then
690-
read -q "reply?File exists. Overwrite ${target_file:t}? [y/N] " </dev/tty
823+
printf '\n%s\n' "⚠️ ${RED}Warning${NC}: ${CYAN}${target_file:t}${NC} already exists in ${CYAN}${args[-1]}${NC}!" >&2
824+
read -q "reply? Overwrite ${target_file:t}? [y/N] " </dev/tty
691825
echo
692826
if [[ "$reply" != [Yy] ]]; then
693-
printf "Skipped: %s\n" "${source:t}"
827+
printf '%s\n' " Skipped: ${source:t}"
694828
continue
695829
fi
696830
fi
@@ -703,35 +837,41 @@ _zsh_disk_guard_mv() {
703837
if (( source_size > 0 )); then
704838
while kill -0 $mv_pid 2>/dev/null; do
705839
if [[ -f "$target_file" ]]; then
840+
# Get current size of destination file
706841
local cur_size=$(set +x; command stat -c%s "$target_file" 2>/dev/null || command stat -f%z "$target_file" 2>/dev/null || echo 0)
707842

843+
# Calculate progress: (completed_files * 100 + current_file_percent) / total_files
708844
local cur_file_pct=$((cur_size * 100 / source_size))
709845
(( cur_file_pct > 100 )) && cur_file_pct=100
710846

711847
local tot_pct=$(( (file_idx - 1) * 100 + cur_file_pct ))
712848
local overall_pct=$(( tot_pct / total_files ))
713849

850+
# Show progress with file count
714851
_zsh_disk_guard_progress_bar $overall_pct 100 $total_files
715852
else
853+
# File doesn't exist yet, show progress for completed files
716854
_zsh_disk_guard_progress_bar $((file_idx - 1)) $total_files $total_files
717855
fi
718856
sleep 0.1
719857
done
720858
else
859+
# Unknown size or directory, just show file count progress
721860
while kill -0 $mv_pid 2>/dev/null; do
722861
_zsh_disk_guard_progress_bar $file_idx $total_files $total_files
723862
sleep 0.2
724863
done
725864
fi
726865

866+
# Wait for mv to complete and get exit status
727867
wait $mv_pid
728868
local mv_status=$?
729869

730870
# Check if mv failed
731871
if (( mv_status != 0 )); then
732872
printf '\n❌ Error moving %s (exit code: %d)\n' "${source:t}" "$mv_status" >&2
733873
_zsh_disk_guard_deinit_term
734-
# Restore settings
874+
# Restore REPORTTIME settings
735875
if (( reporttime_was_set )); then
736876
REPORTTIME=$saved_reporttime
737877
else
@@ -744,30 +884,40 @@ _zsh_disk_guard_mv() {
744884
# Add to total bytes moved
745885
(( total_bytes_moved += source_size ))
746886

887+
# Update progress bar for completed file
747888
_zsh_disk_guard_progress_bar $(( file_idx * 100 / total_files )) 100 $total_files
748889
done
749890

891+
# Ensure 100% at the end
750892
_zsh_disk_guard_progress_bar 100 100 $total_files
751893
_zsh_disk_guard_deinit_term
752894

753895
# Calculate elapsed time and format it cleanly
754896
local elapsed=$((SECONDS - start_time))
755897
local elapsed_display
756-
if (( elapsed < 60 )); then
757-
elapsed_display="${elapsed}s"
758-
elif (( elapsed < 3600 )); then
759-
local minutes=$((elapsed / 60))
760-
local seconds=$((elapsed % 60))
761-
elapsed_display="${minutes}m ${seconds}s"
898+
899+
# Convert to integer to avoid floating point issues
900+
local elapsed_int=${elapsed%.*}
901+
902+
if (( elapsed_int < 60 )); then
903+
elapsed_display=$(printf '%ds' "$elapsed_int")
904+
elif (( elapsed_int < 3600 )); then
905+
local minutes=$((elapsed_int / 60))
906+
local seconds=$((elapsed_int % 60))
907+
elapsed_display=$(printf '%dm %ds' "$minutes" "$seconds")
762908
else
763-
local hours=$((elapsed / 3600))
764-
local minutes=$(((elapsed % 3600) / 60))
765-
local seconds=$((elapsed % 60))
766-
elapsed_display="${hours}h ${minutes}m ${seconds}s"
909+
local hours=$((elapsed_int / 3600))
910+
local minutes=$(((elapsed_int % 3600) / 60))
911+
local seconds=$((elapsed_int % 60))
912+
elapsed_display=$(printf '%dh %dm %ds' "$hours" "$minutes" "$seconds")
767913
fi
768914

769915
# Display success summary
770-
printf '\n✅ Done! Moved %s in %s\n\n' "$(_zsh_disk_guard_format_size $total_bytes_moved)" "$elapsed_display"
916+
if [[ $total_bytes_moved = 0 ]]; then
917+
printf '\n%s\n\n' "ℹ️ Nothing has changed!"
918+
else
919+
printf '\n✅ Done! Moved %s in %s\n\n' "$(_zsh_disk_guard_format_size $total_bytes_moved)" "$elapsed_display"
920+
fi
771921

772922
# Restore REPORTTIME to original state
773923
if (( reporttime_was_set )); then
@@ -784,7 +934,7 @@ _zsh_disk_guard_mv() {
784934

785935
# ──────────────────────────────────────────────────────────────────
786936
# Wrapper for 'rsync' command with disk guard
787-
# Note: rsync has its own progress display, so we don't add our own
937+
# Note: rsync has its own progress display, so we don't need one to add
788938
# ──────────────────────────────────────────────────────────────────
789939
_zsh_disk_guard_rsync() {
790940
local LC_ALL=C
@@ -815,7 +965,7 @@ _zsh_disk_guard_rsync() {
815965
return $?
816966
fi
817967

818-
# Verify disk space, then run rsync with its own progress
968+
# Verify disk space, then run rsync
819969
_zsh_disk_guard_verify "$target" "${sources[@]}" || return 1
820970
command rsync "$@"
821971
return $?

0 commit comments

Comments
 (0)