#!/bin/perl use strict; use warnings; use feature("signatures"); use File::Basename; use Cwd; sub fs_root ($file_name) { chomp( my $ret = `stat -c %m $file_name` ); return $ret; } sub trash_dir ($file_fs_root) { my $data_path = "$ENV{'XDG_DATA_HOME'}" // "$ENV{'HOME'}/.local/share"; return "$data_path/Trash/" if ( $file_fs_root eq fs_root($data_path) ); return "$file_fs_root/.Trash/"; } sub trashed_files ( $search_path, $trash_path ) { my @ret; opendir( my $dir, "$trash_path/info" ) or die "$!\n"; for ( readdir $dir ) { $_ =~ /\.~\d~$/ or next; open( FH, "<", "$trash_path/info/$_" ) or next; eq "[Trash Info]\n" or next; my ( $name, $path, $suffix ) = fileparse( ( =~ /(?<=Path=)(.+)$/ )[0] ); $path =~ /^$search_path\/?$/ or next; my $deletion_date = ( =~ /(?<=DeletionDate=)(.+)$/ )[0]; chomp( $deletion_date = `date -d ${deletion_date} +'%x %X'` ); push( @ret, [ $path, "${name}${suffix}", $deletion_date, $_ ] ); } return @ret; } sub fzf_files (@files) { my $n = 0; my $str; for my $e (@files) { $str .= "\n" if $n > 0; $str .= "$n | $$e[2] | $$e[1]"; $n++; } chomp($str); my $sel = `echo '$str' | fzf`; !$sel and exit; my $index = substr( $sel, 0, index( $sel, ' ' ) ); return $index; } # NOTE: Execution starts here # my $target_directory; if ( $#ARGV + 1 > 1 ) { die "Bad Arguments\n"; } elsif ( $#ARGV + 1 == 1 ) { $target_directory = shift; chomp( $target_directory = `realpath -s $target_directory` ); stat $target_directory or die "$!\n"; } else { $target_directory = getcwd(); } my $trash_dir = trash_dir( fs_root($target_directory) ); my @files = trashed_files( $target_directory, $trash_dir ); !@files and exit; my $index = fzf_files(@files); my $file_dest = $files[$index][0] . $files[$index][1]; my $file_src = $trash_dir . "files/" . $files[$index][3]; my $file_info = $trash_dir . "info/" . $files[$index][3]; rename( $file_src, $file_dest ) or die "$!\n"; unlink($file_info);