From d54d47d944cbc6fbd72126f26f9edea3b4d6de72 Mon Sep 17 00:00:00 2001 From: joe Date: Mon, 8 Sep 2025 19:01:27 +0200 Subject: in progress --- .config/env | 12 +- .config/nnn/plugins/joe_preview | 418 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 423 insertions(+), 7 deletions(-) create mode 100755 .config/nnn/plugins/joe_preview diff --git a/.config/env b/.config/env index b8fc6b6..82f6e23 100644 --- a/.config/env +++ b/.config/env @@ -103,18 +103,16 @@ export NNN_OPTS='aAdrRQ' export NNN_COLORS='4132' export NNN_FCOLORS='030304020005060801ac0507' export NNN_ARCHIVE="\\.(7z|a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|rar|rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)$" -export NNN_PLUG='t:joe_fzfcd;p:joe_preview' export NNN_TERMINAL=$TERMINAL export NNN_PAGER='less' +export NNN_BATTHEME='gruvbox-dark' +export NNN_BATSTYLE='plain' +export NNN_PREVIEWIMGPROG='icat' +export NNN_ICONLOOKUP=0 +export NNN_PLUG='t:-joe_fzfcd;p:-joe_preview;P:-preview-tui;s:-!du -sh;f:-fzopen' export RUSTFLAGS='-L /usr/local/lib' export WWW_HOME='https://start.duckduckgo.com/' export YTFZF_HIST='0' -# wayland -export WLR_DRM_NO_ATOMIC=1 -export XDG_SESSION_TYPE=wayland -export XDG_CURRENT_DESKTOP=dwl -export MOZ_ENABLE_WAYLAND=1 - # PATH export PATH="$HOME"/.local/bin:"$HOME"/.local/bin/status:/usr/local/llvm13/bin:"$HOME"/.pyenv/bin:"$PATH" diff --git a/.config/nnn/plugins/joe_preview b/.config/nnn/plugins/joe_preview new file mode 100755 index 0000000..6620cd3 --- /dev/null +++ b/.config/nnn/plugins/joe_preview @@ -0,0 +1,418 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use Cwd qw(cwd); +use POSIX qw(mkfifo); +# use POSIX qw(:signal_h); +use File::Spec; +use File::Basename; +use Term::ANSIColor; + + +my $parent = ''; +if ($ENV{'NNN_FIFO'}) { + ($parent = $ENV{'NNN_FIFO'}) =~ s/^[^.]*\.//; +} +my $tmpdir = '/tmp'; +my $cwd = cwd(); + +$ENV{'PWD'} = $cwd; +$ENV{'FIFOPID'} = "$tmpdir/nnn-preview-joe-fifopid.$parent"; +$ENV{'FIFOPATH'} = "$tmpdir/nnn-preview-joe-fifo.$parent"; +$ENV{'PREVIEWPID'} = "$tmpdir/nnn-preview-joe-previewpid.$parent"; +$ENV{'CURSEL'} = "$tmpdir/nnn-preview-joe-selection.$parent"; +$ENV{'POSOFFSET'} = "$tmpdir/nnn-preview-joe-posoffset"; +$ENV{'NNN_PAGER'} ||= 'less'; +$ENV{'NNN_BATSTYLE'} ||= 'numbers'; +$ENV{'NNN_BATTHEME'} ||= 'ansi'; + +sub image_preview +{ + print "IMAGE PREVIEW\n"; + return; +} + +sub generate_preview +{ + print "GENERAL PREVIEW\n"; + return; +} + +sub fifo_pager +{ + my ($cmd, @args) = @_; + my $reader_pid; + my $writer_pid; + my $pager; + + $pager = $ENV{'NNN_PAGER'} // 'less'; + + mkfifo($ENV{'FIFOPATH'}, 0700) or return; + + $reader_pid = fork(); + die $! unless defined $reader_pid; + if ($reader_pid == 0) { + open(STDIN, '<', $ENV{'FIFOPATH'}) or die $!; + exec($pager) or die $!; + } + + open(my $pid_fh, '>', $ENV{'PREVIEWPID'}) or die $!; + print $pid_fh $reader_pid; + close($pid_fh); + + $writer_pid = fork(); + die $! unless defined $writer_pid; + if ($writer_pid == 0) { + open(STDOUT, '>', $ENV{'FIFOPATH'}) or die $!; + if ($cmd eq 'pager') { + my $cols = `tput cols`; + chomp $cols; + exec("bat", + "--terminal-width=$cols", + "--decorations=always", + "--color=always", + "--paging=never", + "--style=$ENV{'NNN_BATSTYLE'}", + "--theme=$ENV{'NNN_BATTHEME'}", + @args + ) or die $!; + } + elsif ($cmd eq 'print_bin_info') { + print "-------- ", + color('bold red'), + "Binary file", + color('reset'), + " --------\n"; + exec('mediainfo', @args); + } + else { + exec($cmd, @args) or die $!; + } + } + waitpid($writer_pid, 0); + unlink $ENV{'FIFOPATH'} or warn $!; + return; +} + +sub handle_ext +{ + my ($file, $ext, $type) = @_; + + if ($ext eq 'epub') { + generate_preview($file, 'epub'); + } + elsif ($ext eq 'pdf') { + generate_preview($file, 'pdf'); + } + elsif ( + $ext eq 'gz' || + $ext eq 'bz2' + ) { + fifo_pager('tar', '-tvf', $file); + } + elsif ($ext eq 'md') { + fifo_pager('glow', '-s', 'dark', $file); + } + elsif ( + $ext eq 'htm' || + $ext eq 'html' || + $ext eq 'xhtml' + ) { + fifo_pager('w3m', $file); + } + elsif ( + $ext eq '7z' || + $ext eq 'a' || + $ext eq 'ace' || + $ext eq 'alz' || + $ext eq 'arc' || + $ext eq 'arj' || + $ext eq 'bz' || + $ext eq 'cab' || + $ext eq 'cpio' || + $ext eq 'deb' || + $ext eq 'jar' || + $ext eq 'lha' || + $ext eq 'lz' || + $ext eq 'lzh' || + $ext eq 'lzma' || + $ext eq 'lzo' || + $ext eq 'rar' || + $ext eq 'rpm' || + $ext eq 'rz' || + $ext eq 't7z' || + $ext eq 'tar' || + $ext eq 'tbz' || + $ext eq 'tbz2' || + $ext eq 'tgz' || + $ext eq 'tlz' || + $ext eq 'txz' || + $ext eq 'tZ' || + $ext eq 'tzo' || + $ext eq 'war' || + $ext eq 'xpi' || + $ext eq 'xz' || + $ext eq 'xz' || + $ext eq 'zst' || + $ext eq 'Z' + ) { + fifo_pager('atool', '-l', $file); + } + elsif ($ext eq 'json') { + fifo_pager('jq', '--color-output', '.', $file); + } + elsif ($type eq 'bin') { + fifo_pager('print_bin_info', $file); + } + else { + fifo_pager('pager', $file); + } + return; +} + +sub handle_mime +{ + my ($file, $mimetype, $ext, $type) = @_; + + if ($mimetype eq 'image/jpeg') { + image_preview($file); + } + elsif ($mimetype eq 'image/gif') { + generate_preview($file, 'gif'); + } + elsif ($mimetype eq 'image/vnd.djvu') { + generate_preview($file, 'djvu'); + } + elsif ($mimetype =~ /^image\//) { + generate_preview($file, 'image'); + } + elsif ($mimetype =~ /^video\//) { + generate_preview($file, 'video'); + } + elsif ($mimetype =~ /^audio\//) { + generate_preview($file, 'audio'); + } + elsif ( + $mimetype =~ /^application\/font/ || + $mimetype =~ /^application\/.*opentype/ || + $mimetype =~ /^font\// + ) { + generate_preview($file, 'font'); + } + elsif ( + $mimetype =~ m{/.+office.+} || + $mimetype =~ m{/.+document.+} || + $mimetype =~ m{/.+msword} || + $mimetype =~ m{/.+ms-excel} + ) { + generate_preview($file, 'office'); + } + elsif ($mimetype eq 'application/zip') { + fifo_pager('unzip', '-l', $file); + } + elsif ($mimetype eq 'text/troff') { + fifo_pager('man', '-Pcat', '-l', $file); + } + else { + handle_ext($file, $ext, $type); + } + return; +} + +sub preview_file +{ + my ($file) = @_; + my ($ext) = $file =~ /\.([^.]*)$/; + my $encoding; + my $mimetype; + my $lines; + my $cols; + + system('clear'); + $encoding = `file -bL --mime-encoding -- $file`; + $mimetype = `file -bL --mime-type -- $file`; + $ext = lc($ext) if length($ext) > 0; + $lines = `tput lines`; + $cols = `tput cols`; + + if (-d $file) { + chdir $file or return; + fifo_pager( + 'eza', + '-T', + '--group-directories-first', + '--colour=always', + '-L', + '3' + ); + chdir '..'; + } + elsif ($encoding =~ /\)/) { + my ($suffix) = $encoding =~ /\)(.*)/; + if (defined $suffix && $suffix eq 'binary') { + handle_mime($file, $mimetype, $ext, 'bin'); + } + else { + handle_mime($file, $mimetype, $ext); + } + } + return; +} + +sub preview_fifo +{ + while (1) { + open(my $fh, '<', $ENV{'NNN_FIFO'}) or die $!; + while (my $selection = <$fh>) { + chomp $selection; + if ($selection) { + pidkill($ENV{'PREVIEWPID'}); + last if $selection eq 'close'; + preview_file($selection); + open(my $cursel_fh, '>', $ENV{'CURSEL'}) or die $!; + print $cursel_fh $selection; + close($cursel_fh); + } + } + close $fh; + } + return; +} + +sub pidkill { + my ($pidfile) = @_; + my $pid; + my $ret; + + if (-e $pidfile) { + $pid = `cat $pidfile 2>/dev/null` or return 1; + $ret = system("kill $pid >/dev/null 2>&1"); + system("wait $pid 2>/dev/null"); + return $ret; + } + return 1; +} + +sub winch_handler +{ + my $filepath; + + system('clear'); + pidkill($ENV{'PREVIEWPID'}); + open(my $fh, '<', $ENV{'CURSEL'}) or die $!; + $filepath = <$fh>; + chomp $filepath if $filepath; + close($fh); + preview_file($filepath) if $filepath; + return; +} + +sub start_preview +{ + my ($file) = @_; + my $pid; + + $ENV{'NNN_TERMINAL'} = $ENV{'NNN_TERMINAL'} // 'xterm'; + $ENV{'PREVIEW_MODE'} = 1; + $pid = fork(); + die $! unless defined $pid; + if ($pid == 0) { + exec($ENV{'NNN_TERMINAL'}, '-e', $0, $file) or die $!; + } + return; +} + +sub toggle_preview +{ + my ($file) = @_; + my $nnn_ppipe; + + $ENV{'PWD'} = cwd(); + $ENV{'PATH'} = $ENV{'PATH'}; + $ENV{'NNN_FIFO'} = $ENV{'NNN_FIFO'}; + $nnn_ppipe = $ENV{'NNN_PPIPE'} // ''; + if (pidkill($ENV{'FIFOPID'})) { + if ($nnn_ppipe && -p $nnn_ppipe) { + open(my $fh, '>', $nnn_ppipe) or warn $!; + print $fh "0"; + close($fh); + } + pidkill($ENV{'PREVIEWPID'}); + } + else { + if ($nnn_ppipe && -p $nnn_ppipe) { + open(my $fh, '>', $nnn_ppipe) or warn $!; + print $fh "1"; + close($fh); + } + start_preview($file); + } + return; +} + +sub joe_preview +{ + my $file; + my $pid; + my $cwd; + + $cwd = cwd(); + + $SIG{PIPE} = 'IGNORE'; + + $file = $ARGV[0]; + if (($ENV{'PREVIEW_MODE'} || 0) == 1) { + preview_file($cwd . '/' . $file); + + $pid = fork(); + die $! unless defined $pid; + if ($pid == 0) { + preview_fifo(); + return; + } + + open(my $pidfh, '>', $ENV{'FIFOPID'}) or die $!; + print $pidfh "$pid\n"; + close($pidfh); + + open(my $curselfh, '>', $ENV{'CURSEL'}) or die $!; + print $curselfh "$cwd/$file\n"; + close($curselfh); + + $SIG{WINCH} = sub { + winch_handler(); + }; + + for my $signal (qw(INT HUP EXIT)) { + $SIG{$signal} = sub { + unlink( + $ENV{'PREVIEWPID'}, + $ENV{'CURSEL'}, + $ENV{'FIFOPID'}, + $ENV{'POSOFFSET'} + ); + exit 0; + }; + } + + while (kill 0, $pid) { + waitpid($pid, 0); + } + + return; + } + else { + # $pid = fork(); + # die $! unless defined $pid; + # if ($pid == 0) { + toggle_preview($file); + # return; + # } + } + return; +} + +joe_preview(); + +__END__ -- cgit v1.2.3