#!/bin/sh
# pRecent-Files 2.0
# Purpose:  This script parses recently-used.xbel & creates a list of files
# recently opened by GTK open/save dialogs (C) 2017-2025 GPL3, Roger Grider
# Based on the openbox pipe menu script by John Crawley Copyright (C) 2010.

export TEXTDOMAIN=precent
export OUTPUT_CHARSET=UTF-8

export APPDIR="$HOME/.pRecent" TMPDIR="/tmp/pRecent"
mkdir -p $APPDIR $TMPDIR

GTKDIALOG=gtkdialog

# path of recently-used.xbel
file_path="${HOME}/.local/share/recently-used.xbel"
if [ -r "${HOME}/.recently-used.xbel" ] && [ ! -r "${HOME}/.local/share/recently-used.xbel" ]; then
    ln -sf ${HOME}/.recently-used.xbel ${HOME}/.local/share/recently-used.xbel
fi
if [ ! -r "${HOME}/.local/share/recently-used.xbel" ]; then
    echo "$0: $(gettext 'cannot find a readable recently-used.xbel file')" >&2
fi

# if argument is --clear, remove old file and create new recently-used.xbel
[ "$1" = '--clear' ] && {
Xdialog --title "$(gettext 'Recent Files')" --under-mouse --cancel-label "No" --ok-label "Yes"  --yesno "\n $(gettext 'Start new list of recent files?') \n\n $(gettext 'This will delete the current recently-used.xbel.') \n" 0 0
if [[ $? == 0 ]]; then
cat <<':EOF' > "${file_path}"
<?xml version="1.0" encoding="UTF-8"?>
<xbel version="1.0"
      xmlns:bookmark="http://www.freedesktop.org/standards/desktop-bookmarks"
      xmlns:mime="http://www.freedesktop.org/standards/shared-mime-info"
>
</xbel>
:EOF
fi
precent-files &
exit
}

# auto-adjust header text color for light or dark GTK themes
if [ "`grep 'Stardust_dark' $HOME/.gtkrc-2.0 2>/dev/null`" ]; then #gold text for unique Stardust dark-grey-orange themes
  COLOR=#D7B740
else #light-blue text for common dark themes, otherwise medium blue
  [ "`grep -Ei 'black|dark|dusk|night' $HOME/.gtkrc-2.0 2>/dev/null`" ] && COLOR=#84aad9 || COLOR=#3272C0
fi
export COLOR

# create precent icon
[ ! -s /usr/share/pixmaps/precent.svg ] && printf '%s' "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"100\" width=\"100\">
  <path style=\"fill:#ffffff;stroke:none;\" d=\"m 65,3 0,19 19,0 z\"/>
  <path style=\"fill:#EBEBDA;stroke:#606060;stroke-width:4;\" d=\"m 65,3 0,19 19,0 0,74 -72,0 0,-93 53,0 19,19\"/>
</svg>" > /usr/share/pixmaps/precent.svg

# set global file icon
[ ! -f /usr/share/icons/hicolor/48x48/apps/precent.svg ] && \
ln -sf /usr/share/pixmaps/precent.svg /usr/share/icons/hicolor/48x48/apps && gtk-update-icon-cache -f -i /usr/share/icons/hicolor 2>/dev/null

# splash dialog
SPLASH_SIGNAL=""
SPLASH=$(cat $APPDIR/splash 2>/dev/null)
[ ! "$SPLASH" ] && SPLASH="true"
if [ "$SPLASH" = "true" ]; then
  SPLASH_SIGNAL="<action signal=\"show\">echo 100 > $TMPDIR/precent-splash</action>"
  echo 0 > $TMPDIR/precent-splash
  export PRECENT_SPLASH='
  <window title=" " icon-name="precent" resizable="false" decorated="true" window-position="2">'"
  <vbox>
   <pixmap><input file>/usr/share/pixmaps/precent.svg</input><height>42</height><width>42</width></pixmap>
   <text use-markup=\"true\"><label>\"<b><span size='"'large'"'>      p</span><span size='"'large'"' color='"$COLOR"'>Recent-files      </span></b>\"</label></text>"'
   <text><label>Loading...</label></text>
   <progressbar visible="false">
    <input>while [ "$M" != "100" ]; do M=`cat $TMPDIR/precent-splash`; echo $M; usleep 500000; done</input>
    <action type="exit">Ready</action>
   </progressbar>
  </vbox></window>'
  $GTKDIALOG -p PRECENT_SPLASH &
fi

# maximum number of files parsed in recently-used.xbel
PARSEDFILES="100"

# maximum number of parsed files displayed in GUI (exclude files that no longer exist, see below)
MAXFILES=$(cat $APPDIR/max-files 2>/dev/null)
[ ! "${MAXFILES}" ] && MAXFILES="15"

# optional open command based on file type
xdg_open_cmd(){
  case "$1" in 
    '') exit ;;
    file://*) exec defaultfilemanager "$1" ;;
    *://*)    exec defaultbrowser "$1" ;;
    *@*.*)    exec defaultemail "$1" ;;
    magnet:*) exec defaulttorrent "$1" ;;
    *)        dir=$(dirname "$1") ; exec defaultfilemanager "$dir" ;;
 esac
}
export -f xdg_open_cmd

export XDG_OPEN=xdg_open_cmd

FILETYPE_CMD=$(cat $APPDIR/filetype-cmd 2>/dev/null)
[ ! "$FILETYPE_CMD" ] && FILETYPE_CMD="false" && echo $FILETYPE_CMD > $APPDIR/filetype-cmd

# GUI window height
WIN_HEIGHT=$(cat $APPDIR/window-height 2>/dev/null)
[ ! "$WIN_HEIGHT" ] && WIN_HEIGHT="300"

# GUI window width
WIN_WIDTH=$(cat $APPDIR/window-width 2>/dev/null)
[ ! "$WIN_WIDTH" ] && WIN_WIDTH="400"

# GUI auto-close
AUTO_CLOSE=$(cat $APPDIR/auto-close 2>/dev/null)
if [ "$AUTO_CLOSE" = "true" -o "$AUTO_CLOSE" = "" ]; then #auto-close GUI after opening file
  ACTION_SIGNAL1="<action signal=\"button-release-event\">EXIT:OK</action>"
  ACTION_SIGNAL2="<action signal=\"row-activated\">EXIT:OK</action>"
else
  ACTION_SIGNAL1=""
  ACTION_SIGNAL2=""
fi

# tooltips
TOOLTIPS=$(cat $APPDIR/tooltips 2>/dev/null)
if [ "$TOOLTIPS" = "true" -o "$TOOLTIPS" = "" ]; then #enable tooltips
  export TOOLTIP1="tooltip-text=\" $(gettext 'Maximum number of recent files (10-50)') \""
  export TOOLTIP2="tooltip-text=\" $(gettext 'Default GUI window-height (300-700 px)') \""
  export TOOLTIP3="tooltip-text=\" $(gettext 'Default GUI window-width (300-700 px)') \""
  export TOOLTIP4="tooltip-text=\" $(gettext 'Check box to auto-close, or uncheck 
 to remain open as desktop launcher.') \""
  export TOOLTIP5="tooltip-text=\" $(gettext 'Enable pop-up splash screen') \""
  export TOOLTIP6="tooltip-text=\" $(gettext 'Enable pop-up help text') \""
  export TOOLTIP7="tooltip-text=\" $(gettext 'Open with original command 
 defined in recently-used.xbel.') \""
  export TOOLTIP8="tooltip-text=\" $(gettext "Open with $XDG_OPEN 
 defined by the type of file.") \""
  if [ "$FILETYPE_CMD" = "true" ]; then
   TOOLTIP9="tooltip-text=\" $(gettext "Left or right-click to open the file with $XDG_OPEN") \""
  else
   TOOLTIP9="tooltip-text=\" $(gettext "Left-click to open selected item with original command. 
 Right-click to open parent folder in default filemanager.") \""
  fi
  export TOOLTIP9
  export TOOLTIP10="tooltip-text=\" $(gettext 'Original command : selected file') \""
  export TOOLTIP11="tooltip-text=\" $(gettext 'Clear entries and start 
 new list of recent files.') \""
  export TOOLTIP12="tooltip-text=\" $(gettext 'Manage recent files') \""
else
  export TOOLTIP1="tooltip-text=\"\""
  export TOOLTIP2="tooltip-text=\"\""
  export TOOLTIP3="tooltip-text=\"\""
  export TOOLTIP4="tooltip-text=\"\""
  export TOOLTIP5="tooltip-text=\"\""
  export TOOLTIP6="tooltip-text=\"\""
  export TOOLTIP7="tooltip-text=\"\""
  export TOOLTIP8="tooltip-text=\"\""
  export TOOLTIP9="tooltip-text=\"\""
  export TOOLTIP10="tooltip-text=\"\""
  export TOOLTIP11="tooltip-text=\"\""
  export TOOLTIP12="tooltip-text=\"\""
fi

# Options dialog
[ "${LANG%_*}" = "en" ] && WIDTH="340" || WIDTH="400"
export RF_OPTIONS="
<window title=\"pRecent-files 2.0\" icon-name=\"precent\" resizable=\"false\" width-request=\"$WIDTH\" window-position=\"2\">
 <vbox>
   <hbox homogeneous=\"true\">
   <vbox>
    <text><label>$(gettext 'Files')</label></text>
   <hbox>
     <spinbutton width-request=\"100\" range-min=\"10\" range-max=\"50\" range-step=\"1\" range-value=\"15\" $TOOLTIP1>
      <variable>MAX_FILES</variable>
      <input>cat $APPDIR/max-files 2>/dev/null</input>
      <action>echo \$MAX_FILES > $APPDIR/max-files</action>
     </spinbutton>
   </hbox>
   </vbox>
   <vbox>
    <text><label>$(gettext 'Height')</label></text>
   <hbox>
     <spinbutton width-request=\"100\" range-min=\"300\" range-max=\"700\" range-step=\"10\" range-value=\"300\" $TOOLTIP2>
      <variable>WIN_HEIGHT</variable>
      <input>cat $APPDIR/window-height 2>/dev/null</input>
      <action>echo \$WIN_HEIGHT > $APPDIR/window-height</action>
     </spinbutton>
   </hbox>
   </vbox>
   <vbox>
    <text><label>$(gettext 'Width')</label></text>
   <hbox>
     <spinbutton width-request=\"100\" range-min=\"300\" range-max=\"700\" range-step=\"10\" range-value=\"300\" $TOOLTIP3>
      <variable>WIN_WIDTH</variable>
      <input>cat $APPDIR/window-width 2>/dev/null</input>
      <action>echo \$WIN_WIDTH > $APPDIR/window-width</action>
     </spinbutton>
   </hbox>
   </vbox>
   </hbox>
     <text height-request=\"2\"><label>\"\"</label></text>
   <hbox homogeneous=\"true\">
   <vbox>
     <checkbox $TOOLTIP4>
      <label>$(gettext "Auto-close")</label>
      <variable>AUTO_CLOSE</variable>
      <input>cat $APPDIR/auto-close 2>/dev/null</input>
      <action>if true echo true > $APPDIR/auto-close</action>
      <action>if false echo false > $APPDIR/auto-close</action>
     </checkbox>
   </vbox>
   <vbox>
     <checkbox $TOOLTIP5>
      <label>$(gettext "Splash")</label>
      <variable>SPLASH</variable>
      <input>cat $APPDIR/splash 2>/dev/null</input>
      <action>if true echo true > $APPDIR/splash</action>
      <action>if false echo false > $APPDIR/splash</action>
     </checkbox>
   </vbox>
   <vbox>
     <checkbox $TOOLTIP6>
      <label>$(gettext "Tooltips")</label>
      <variable>TOOLTIPS</variable>
      <input>cat $APPDIR/tooltips 2>/dev/null</input>
      <action>if true echo true > $APPDIR/tooltips</action>
      <action>if false echo false > $APPDIR/tooltips</action>
     </checkbox>
   </vbox>
   </hbox>
     <hseparator></hseparator>
     <text use-markup=\"true\"><label>\"<b><span size='"'small'"' color='"$COLOR"'>$(gettext 'Left-click Command')</span></b>\"</label></text>
   <hbox homogeneous=\"true\">
   <vbox>
     <checkbox $TOOLTIP7>
      <label>$(gettext "Original command")</label>
      <variable>ORIGINAL_CMD</variable>
      <input>cat $APPDIR/original-cmd 2>/dev/null</input>
      <action>if true echo true > $APPDIR/original-cmd</action>
      <action>if true echo false > $APPDIR/filetype-cmd</action>
      <action>if false echo false > $APPDIR/original-cmd</action>
      <action>if false echo true > $APPDIR/filetype-cmd</action>
      <action>refresh:FILETYPE_CMD</action>
     </checkbox>
   </vbox>
   <vbox>
     <checkbox $TOOLTIP8>
      <label>$XDG_OPEN</label>
      <variable>FILETYPE_CMD</variable>
      <input>cat $APPDIR/filetype-cmd 2>/dev/null</input>
      <action>if true echo true > $APPDIR/filetype-cmd</action>
      <action>if true echo false > $APPDIR/original-cmd</action>
      <action>if false echo false > $APPDIR/filetype-cmd</action>
      <action>if false echo true > $APPDIR/original-cmd</action>
      <action>refresh:ORIGINAL_CMD</action>
     </checkbox>
   </vbox>
   </hbox>
     <hseparator></hseparator>
   <hbox space-expand=\"false\" space-fill=\"true\" homogeneous=\"true\">
     <button height-request=\"32\" width-request=\"100\">
      <label>\"$(gettext "OK")\"</label>
      <input file stock=\"gtk-ok\"></input>
      <action>precent-files &</action>
      <action type=\"exit\">quit_now</action>
     </button>
   </hbox>
 </vbox>
 <variable>RF_OPTIONS</variable>
 <action signal=\"delete-event\">EXIT:abort</action>
</window>"

PARSEDFILES=$((PARSEDFILES+2))

files=$( tac "${file_path}" | sed \
    -e "s/;gtkdialog4/;$XDG_OPEN/g" \
    -e "s/;gtkdialog3/;$XDG_OPEN/g" \
    -e "s/;gtkdialog/;$XDG_OPEN/g" | \
    awk -v MAX="$PARSEDFILES" 'BEGIN {
    RS="</bookmark>";
    FS="<info>";
}
(NR == MAX) {exit}
!/<bookmark/ {next}
!/href=[\"'\'']file:\/\// {next}
# $1 is the command, $2 the file path
{
    sub(/^.*exec=\"\&apos\;/,"",$1)
    sub(/\&apos\;.*$/,"",$1)
    sub(/ *%./,"",$1)
    sub(/^.*file:\/\//,"",$2)
    sub(/[\"'\''].*$/,"",$2)
    gsub(/%22/,"\\&quot;",$2)
    gsub(/%3C/,"\\&lt;",$2)
    gsub(/%3E/,"\\&gt;",$2)
    name=$2
    sub(/^.*\//,"",name)
    gsub(/_/,"__",name)
    gsub(/\&apos;/,"\\&apos;\\&quot;\\&apos;\\&quot;\\&apos;",$2)
    print ($1 " " $2 "")
}' 2>/dev/null )

# use perl to decode urlencoded characters
files=$(perl -I $HOME/.pRecent -MURI::Escape -e 'print uri_unescape($ARGV[0]);' "$files")

# parse output and exclude recently-used files that no longer exist
printf '%s' "$files" | awk '!a[$0]++' > $TMPDIR/tmp
echo -n > $TMPDIR/MRU-path
 while read -r line
  do
    [ "$FILETYPE_CMD" = "true" ] && COMMAND="$XDG_OPEN" || COMMAND=$(echo "$line" | cut -d' ' -f1)
    FILE_PATH=$(echo "$line" | cut -d' ' -f2-)
    [ -s "$FILE_PATH" ] && echo "$COMMAND" "$FILE_PATH" >> $TMPDIR/MRU-path
  done < $TMPDIR/tmp

FILES=$(cat $TMPDIR/MRU-path 2>/dev/null)
printf '%s' "$FILES" | awk '!a[$0]++' | head -n ${MAXFILES} > /tmp/tmp && mv -f /tmp/tmp $TMPDIR/MRU-path
[ ! "`cut -d' ' -f2- $TMPDIR/MRU-path 2>/dev/null`" ] && echo "$(gettext 'No-recent-files')" > $TMPDIR/MRU-path

# main dialog
export MRUF_GUI="
<window title=\"pRecent-files\" icon-name=\"precent\" window-position=\"2\">
  <vbox>
   <text use-markup=\"true\"><label>\"<b><span size='large'>$(gettext 'Recently Used Files')</span></b>\"</label></text>
    <hbox space-expand=\"true\" space-fill=\"true\">
    <vbox>
     <tree hover-selection=\"true\" enable-search=\"false\" icon-name=\"precent\" headers-visible=\"false\" $TOOLTIP9>
      <label>$(gettext 'Select a file')</label>
      <height>$WIN_HEIGHT</height><width>$WIN_WIDTH</width>
      <variable>MRUF</variable>
      <input>cut -d' ' -f2- $TMPDIR/MRU-path 2>/dev/null</input>
      <action signal=\"cursor-changed\">[ "\$MRUF" ] && grep -m1 "\$MRUF\$" \$TMPDIR/MRU-path | cut -d' ' -f1 > /tmp/tmp</action>
      <action signal=\"cursor-changed\">[ "\$MRUF" ] && cut -d' ' -f2- \$TMPDIR/MRU-path | grep -x "^\$MRUF\$" | awk -F'/' '{print \$NF}' >> /tmp/tmp</action>
      <action signal=\"cursor-changed\">[ "\$MRUF" ] && cut -d' ' -f2- \$TMPDIR/MRU-path | grep -x "^\$MRUF\$" > /tmp/tmp1</action>
      <action signal=\"cursor-changed\">refresh:MRUF-VIEWER</action>
      <action signal=\"leave-notify-event\">clear:MRUF-VIEWER</action>
      <action signal=\"leave-notify-event\">rm -f /tmp/tmp /tmp/tmp1 2>/dev/null</action>
      <action signal=\"button-release-event\">[ \$PTR_BTN -eq 3 ] && \$XDG_OPEN \"\$(head -n1 /tmp/tmp1)\" || \$(head -n1 /tmp/tmp) \"\$(head -n1 /tmp/tmp1)\" &</action>
      $ACTION_SIGNAL1
      <action signal=\"row-activated\">\$(head -n1 /tmp/tmp) \"\$(head -n1 /tmp/tmp1)\" &</action>
      $ACTION_SIGNAL2
     </tree>
    <hseparator></hseparator>
    <hbox>
     <entry height-request=\"32\" $TOOLTIP10>
      <variable>MRUF-VIEWER</variable>
      <input>[ "\$MRUF" ] && sed 'N;s/\n/: /' /tmp/tmp</input>
     </entry>
     <button height-request=\"32\" width-request=\"32\" $TOOLTIP11>
      <input file stock=\"gtk-clear\"></input>
      <action signal=\"button-release-event\">'"$0"' --clear &</action>
      <action signal=\"button-release-event\">EXIT:OK</action>
     </button>
     </hbox>
    </vbox>
   </hbox>
    <hbox space-expand=\"false\" space-fill=\"false\" homogeneous=\"true\">
     <button space-expand=\"false\" space-fill=\"true\" height-request=\"32\" width-request=\"100\" $TOOLTIP12>
      <label>$(gettext 'Manage')</label>
      <input file stock=\"gtk-jump-to\"></input>
      <action>launch:RF_OPTIONS</action>
     </button>
     <button space-expand=\"false\" space-fill=\"true\" height-request=\"32\" width-request=\"100\">
      <label>$(gettext 'Close')</label>
      <input file stock=\"gtk-close\"></input>
      <action type=\"exit\">quit_now</action>
     </button>
    </hbox>
  </vbox>
 $SPLASH_SIGNAL
</window>"

$GTKDIALOG -p MRUF_GUI > /dev/null 2>&1 </dev/null
unset MRUF_GUI
exit 0
