Topic: Recently Opened Files pipe menu
Sometimes you want to re-open a file you've just been working on and it would be handy not to have to dive into a "places" menu to dig it out. There's a file in your user directory called .recently-used.xbel which is updated by gtk apps in particular and holds the file paths and what application was used to open them, along with other data like mime-types. It's a bit odd sometimes ( doesn't always update right away ), and not all apps use it, but seems reasonably usable. This script was inspired by http://openbox.org/wiki/Openbox:Pipemen tfilesxbel but changed quite a bit while I was playing with it. Stuff being done by grep, read and sed seemed all doable by awk, so calling up one utility instead of three, and giving me an excuse to get down and learn some awk... The end result is quite fast I think, and instead of using something like xdg-open to open files it gets the previously used application. Another small improvement is that unusual characters ( even quotes and backslashes, and multi-byte characters like Japanese ) in filenames are displayed correctly, and don't break the "open" command, so you can have files called \_<"">_ if you want...
To use, copy the code into a file called (e.g.) recently_opened_menu.sh, make it executable, then add this:
<menu id="recent" label="Recent Files" execute="/path/to/recently_opened_menu.sh" />to your ~/.config/openbox/menu.xml file.
Anyway, check it out if you're interested, and please let me know if you find any problems:
#!/bin/sh
# recently_opened_menu.sh - a script to parse .recently-used.xbel
# and generate openbox pipe menu
# Copyright (C) 2010 John Crawley
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# version 2011/06/02
# Usage: add
# <menu id="recent" label="Recent Files" execute="/path/to/recently_opened_menu.sh" />
# to your .config/openbox/menu.xml, or use with dash_places_menu.sh (see comments there)
maximum_entries=15 # max. number of entries in menu
#######################################################################
# look for recently-used.xbel
if [ $XDG_DATA_HOME ] && [ -r "${XDG_DATA_HOME}/recently-used.xbel" ]
then
file_path="${XDG_DATA_HOME}/recently-used.xbel"
elif [ -r "${HOME}/.local/share/recently-used.xbel" ]
then
file_path="${HOME}/.local/share/recently-used.xbel"
elif [ -r "${HOME}/.recently-used.xbel" ]
then
file_path="${HOME}/.recently-used.xbel"
else
echo "$0: cannot find a readable recently-used.xbel file" >&2
exit 1
fi
# if argument is --clear, empty .recently-used.xbel
[ "$1" = '--clear' ] && {
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
exit
}
maximum_entries=$((maximum_entries+2))
pre=' <item label="'
mid='">
<action name="Execute"><command>'
post='</command></action>
</item>'
files=$( tac "${file_path}" | awk -v MAX="$maximum_entries" -v PR="$pre" -v MI="$mid" -v PO="$post" '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/,"\\"",$2)
gsub(/%3C/,"\\<",$2)
gsub(/%3E/,"\\>",$2)
name=$2
sub(/^.*\//,"",name)
gsub(/\'/,"\\'\\"\\'\\"\\'",$2)
print (PR name MI $1 " '"'"'" $2 "'"'"'" PO)
}' )
# use perl to decode urlencoded characters
files=$(perl -MURI::Escape -e 'print uri_unescape($ARGV[0]);' "$files")
output='<openbox_pipe_menu>
'"$files"'
<separator />
<item label="Clear Recent Files">
<action name="Execute">
<command>
''"$0"'' --clear
</command>
</action>
</item>
</openbox_pipe_menu>
'
printf '%s' "$output" # printf because echo sometimes eats backslashesThe bit of perl voodoo came from here originally, but don't ask me to explain how it works. It does anyway, and doesn't seem too slow. If any perl or awk gurus can suggest improvements to any of this, grateful as always. ![]()
edit: Now overwrites .recently-used.xbel to clear the file list, instead of just deleting it.
edit 110209 Bugfix: entries without a reference to a local file (path starting 'file://') would break the menu. Now they're ignored. This menu is for files on your local system only.
edit 110210 Now copes with both single and double quotes for xml tag attributes in .recently-used.xbel. ( Probably unnecessary
)
edit 110520 Amended to check possible locations of recently-used.xbel and use the first one found. (The file moves to ~/.local.share if libgtk2.0-0 is upgraded from 2.20 to 2.24.)
edit 110602 Escaping modified to work with gawk as well as mawk. (Ampersands in replacement strings preceded by two backslashes instead of one.)
Last edited by johnraff (2011-06-02 04:54:42)
------------------------
( a boring Japan blog , and idle twitterings )
“There is more Unix-nature in one line of shell script than there is in ten thousand lines of C.” - Master Foo