You are not logged in.
Since I could not find any type of text snippet expander for Linux/Arch, I've hacked together a few tools already available. The goal: having quick access to commonly used text snippets, like email signatures, email addresses, canned responses, etc.
Meet snippy
With this small script, you can type an abbreviation for the snippet, invoke snippy with a hotkey and have the required text expanded/replaced. It only works in X applications that understands control+x for cut and control+v for paste. The good thing is that it will work for (almost) all your apps, in OpenOffice, Firefox, Thunderbird, etc. No need to rely on the app-specific solution.
Install
1) Snippy needs xsel and xdotool, so get them via
pacman -Sy xsel xdotool
2) Create a test snippet in the snippets directory (.snippy), like
mkdir ~/.snippy
echo "Hello World!" > ~/.snippy/hw
Save this code to a file in your $path (than chmod +x):
#!/bin/bash
# read the abbreviation
xdotool key ctrl+shift+Left
xdotool key ctrl+x
sleep 0.2s # to work reliably in Firefox
SELECTION=`xsel -b`
# read snippet file
xsel -b -i < ~/.snippy/${SELECTION}
# paste snippet
xdotool key ctrl+v
xdotool key BackSpace # delete the last blank line, so we stay inline
Assign a keyboard shortcut to the script, or use alt+f2 for testing...
Open a text editor (like kedit, mousepad, gedit, but not gvim, vim, etc.), type hw and push the hotkey (or run snippy with alt+f2).
Hello World! should appear.
Thats's it I hope some will find it useful.
Remark: the main source of inspiration was snippits. It seems to be abandoned.
EDIT small change from cat to echo by Mr Green
Offline
Excellent stuff, can't believe noone has responded yet.
Offline
Thanks, good to hear someone likes it!
Offline
I'm trying it, but all that happens is that the last letter is being backspaced, no replacement whatsoever o.O am I doing something wrong?
EDIT:
Nevermind, I changed the keybinding in openbox's rc.xml and now it works... for some reason using Alt-F3 made it act weird on me o.O now I'm using Shift-F2
Last edited by zandaa (2009-06-30 08:58:16)
With my army of penguins, I shall overthrow governments and free those who have been waiting for liberty.
Offline
Nice tool... The problem with xdotool is that any modifiers pressed by the user while it runs will be mixed in to the key send, so in zandaa's case the ctrl+x might really have been ctrl+alt+x since he was still holding down alt.
I've reported this issue to the author of xdotool and he said he'll provide a way of reliably sending only the requested keyseq in the future, regardless of current modifier state.
As a workaround you might sleep a little before sending the key, giving the user time to release any modifiers. Not a solution, but less likely to fail.
Offline
Nice tool, I use the compose key for this - but I see how it'd be useful for text which isn't always the same.
Offline
Nice tool... The problem with xdotool is that any modifiers pressed by the user while it runs will be mixed in to the key send, so in zandaa's case the ctrl+x might really have been ctrl+alt+x since he was still holding down alt.
I've reported this issue to the author of xdotool and he said he'll provide a way of reliably sending only the requested keyseq in the future, regardless of current modifier state.
As a workaround you might sleep a little before sending the key, giving the user time to release any modifiers. Not a solution, but less likely to fail.
Seems to be fixed in the latest release: http://semicomplete.googlecode.com/file … 710.tar.gz
Offline
Hi,
1)Why use cut/paste? since you already use xdotool can't you just backspace until you find the space and then "type" with xdotool the string (instead of pasting it) ?
2)I would expand on this idea and check if the file inside ~/.snippy/ is executable. if it is you can do this:
~/.snippy/${SELECTION} | xsel -b -i
so the script could generate dynamic output depending on some context ( eg it could echo "good evening" , "good morning" etc depending on current time)
Also, this way the user could program some arbitrary actions with xdotool himself, such as what was possible with snippits (but snippits reinvented the wheel ;-))
3) Instead of letting the user type a string that he has to know by heart and then erasing it anyway, wouldn't a procedure like this be better:
- user types his normal (not to be expanded) text
- user presses keybind to start snippy
- snippy lists all files in ~/.snippy/ and presents them in dmenu
- user can then navigate or search in dmenu to find the shortcut he wants, and selects it
- all you need to do now is insert the contents of the file
I think this would be easier, especially if the user has a lot of snippy items
Last edited by Dieter@be (2009-07-12 09:26:11)
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Good ideas, thanks! I really like the idea about dmenu, will give it a try when I have the time.
Offline
3) Instead of letting the user type a string that he has to know by heart and then erasing it anyway, wouldn't a procedure like this be better:
- user types his normal (not to be expanded) text
- user presses keybind to start snippy
- snippy lists all files in ~/.snippy/ and presents them in dmenu
- user can then navigate or search in dmenu to find the shortcut he wants, and selects it
- all you need to do now is insert the contents of the fileI think this would be easier, especially if the user has a lot of snippy items
#!/bin/bash
DIR=${XDG_CONFIG_HOME}/snippy
DMENU_ARGS="-b"
FILE=`/bin/ls $DIR | /usr/bin/dmenu ${DMENU_ARGS}`
sleep 0.2
TEXT="`cat ${DIR}/${FILE}`"
for WORD in ${TEXT};
do
xdotool type --delay 0 --clearmodifiers ${WORD}
xdotool type --delay 0 --clearmodifiers ' '
done
xdotool key --clearmodifiers BackSpace
☃ Snowman ☃
Offline
Is it true that xdotool can't type non-ascii chars?
I've tried helloöüóőúéáűbello and the result is: hellobello.
Got the same result with latin2 and utf8.
Dieter@be wrote:3) Instead of letting the user type a string that he has to know by heart and then erasing it anyway, wouldn't a procedure like this be better:
- user types his normal (not to be expanded) text
- user presses keybind to start snippy
- snippy lists all files in ~/.snippy/ and presents them in dmenu
- user can then navigate or search in dmenu to find the shortcut he wants, and selects it
- all you need to do now is insert the contents of the fileI think this would be easier, especially if the user has a lot of snippy items
#!/bin/bash DIR=${XDG_CONFIG_HOME}/snippy DMENU_ARGS="-b" FILE=`/bin/ls $DIR | /usr/bin/dmenu ${DMENU_ARGS}` sleep 0.2 TEXT="`cat ${DIR}/${FILE}`" for WORD in ${TEXT}; do xdotool type --delay 0 --clearmodifiers ${WORD} xdotool type --delay 0 --clearmodifiers ' ' done xdotool key --clearmodifiers BackSpace
Offline
Dmenu really makes this experience cleaner. Having a list of choices is always good, plus it permitts to give the snippets some "human friendly" names, instead of short ones like es1 (email signature 1). Since xdotool seems to skip non-ascii chars, I have come up with this mule:
#!/bin/bash
DIR=${HOME}/.snippits
DMENU_ARGS="-b"
FILE=`/bin/ls $DIR | /usr/bin/dmenu ${DMENU_ARGS}`
xsel -b -i < ${DIR}/${FILE}
xdotool key ctrl+v
Offline
Hitting ESC in dmenu will result in no output:
#!/bin/bash
DIR=${HOME}/.snippits
DMENU_ARGS="-b"
FILE=`/bin/ls $DIR | /usr/bin/dmenu ${DMENU_ARGS}`
if [ -f ${DIR}/${FILE} ]; then
xsel -b -i < ${DIR}/${FILE}
xdotool key ctrl+v
fi
Offline
Is it true that xdotool can't type non-ascii chars?
Seems true to me, what a shame...
This silver ladybug at line 28...
Offline
So i wrote a tool, insipred by this script but with my own ideas in it (eg dynamic and static snippets, dmenu selection, xdotool type, xdg spec, zenity for storing new ones, ..)
I also want to integrate clipboard management into it ('volatile snips').
package:
http://aur.archlinux.org/packages.php?ID=30071
code:
http://github.com/Dieterbe/snip/tree/master
sessy: if you let me know your real name i can give you credit
Last edited by Dieter@be (2009-09-12 18:44:00)
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
@Dieter@be -- awesome! works great so far. I'm gonna integrate the little caching script that brisbin33 wrote for dmenu, so the most commonly used snips appear first.
Scott
Offline
With regard to original post:
cat "Hello World!" > ~/.snippy/hw
Shouldn't this be `echo`?
Offline
With regard to original post:
cat "Hello World!" > ~/.snippy/hw
Shouldn't this be `echo`?
indeed
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
@Dieter@be -- awesome! works great so far. I'm gonna integrate the little caching script that brisbin33 wrote for dmenu, so the most commonly used snips appear first.
Scott
what about `ls -tu` ? this sorts files by access time. no need for extra caching scripts or files.
that said, I think the default behavior of ls (sort by name) is also fine. maybe i should introduce a config file for snip where you can set DMENU_ARGS and LS_ARGS
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
It's really sad that xdotool can't handle special characters. I took the script from the AUR and changed it to avoid this problem. For me it uses now xclip to copy the string to the clipboard and pasts it with xdotool. The original clipboard is saved and restored afterwards. It's a bit clumsy but works for me. Oh, and I've removed the check for executability because I thought it wouldn't be necessary this way. Maybe I broke something...
#!/bin/sh
if [ x"$XDG_DATA_HOME" != "x" ]
then
snips=$XDG_DATA_HOME/snip/snips
else
snips=$HOME/.local/share/snip/snips
fi
[ -d $snips ] || mkdir -p $snips
if [ x"$DMENU_ARGS" == "x" ]
then
DMENU_ARGS='-p snip: '
fi
if [ "$1" == 'load' ]
then
#if [ "$2" == 'name' ]
snip="$snips/$(ls $snips | dmenu $DMENU_ARGS)"
if [ -f $snip ]
then
cb=`xclip -o -selection clipboard`
xclip -i -selection clipboard $snip
xdotool key ctrl+v
xdotool key BackSpace
printf $cb | xclip -selection clipboard
fi
# this only works for (and is only useful for) static snips
# make dynamic snips manually
elif [ "$1" == 'save' ]
then
txt=$(xsel)
if [ x"$txt" == 'x' ]
then
txt=$(zenity --title "Save snip" --entry --text "Text to put in snip")
fi
name=$(zenity --title "Save snip" --entry --text "Filename to save snip as")
echo "$txt" > $snips/$name
else
echo "No valid arguments passed" >&2
exit 2
fi
YES WE CAN
(but that doesn't necessarily mean we're going to)
Offline
Oh, and I've removed the check for executability because I thought it wouldn't be necessary this way. Maybe I broke something...
well, it was there for a reason. see http://github.com/Dieterbe/snip/blob/master/README for more info
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Oh, right, so I have kind of crippled it. Second try.
#!/bin/sh
if [ x"$XDG_DATA_HOME" != "x" ]
then
snips=$XDG_DATA_HOME/snip/snips
else
snips=$HOME/.local/share/snip/snips
fi
[ -d $snips ] || mkdir -p $snips
if [ x"$DMENU_ARGS" == "x" ]
then
DMENU_ARGS='-p snip: '
fi
if [ "$1" == 'load' ]
then
#if [ "$2" == 'name' ]
snip="$snips/$(ls $snips | dmenu $DMENU_ARGS)"
if [ -f $snip ]
then
if [ -x $snip ]
then
cb=`xclip -o -selection clipboard`
printf `"$snip"` | xsel -b -i
xdotool key ctrl+v
printf $cb | xsel -b -i
else
cb=`xclip -o -selection clipboard`
printf `cat "$snip"` | xsel -b -i
xdotool key ctrl+v
printf $cb | xsel -b -i
fi
fi
# this only works for (and is only useful for) static snips
# make dynamic snips manually
elif [ "$1" == 'save' ]
then
txt=$(xsel)
if [ x"$txt" == 'x' ]
then
txt=$(zenity --title "Save snip" --entry --text "Text to put in snip")
fi
name=$(zenity --title "Save snip" --entry --text "Filename to save snip as")
echo "$txt" > $snips/$name
else
echo "No valid arguments passed" >&2
exit 2
fi
edit01: Um, well, it seems to be broken in some cases anyway, please ignore everything I've posted...
edit02: Ok, it kinda works, but the snippet files have to end with a linebreak and it doesn't perform in a shell.
edit03: update - now can't handle multiple lines. but works better
Last edited by V for Vivian (2009-09-19 22:16:05)
YES WE CAN
(but that doesn't necessarily mean we're going to)
Offline
what about `ls -tu` ? this sorts files by access time. no need for extra caching scripts or files.
Well, that would work, except it wouldn't sort by frequency which is what brisbin33 solved w/ his caching script. I like having my regular dmenu pop up with my most used programs first, instead of alphabetical or most recently accessed (which is not necessarily most used). I don't think that would necessarily be important to other people, but it certainly could be an option.
Here's the code for launching dmenu with the caching feature (.dmenurc is sort of like your $DMENU_ARGS)
#!/bin/bash
if [ -f $HOME/.dmenurc ]; then
. $HOME/.dmenurc
else
DMENU='dmenu -i'
fi
TERMI='urxvt -e bash -lic'
CACHE="$HOME/.dmenu_cache_recent"
touch $CACHE
MOST_USED=$(LC_ALL="C"; sort $CACHE | uniq -c | sort -r | colrm 1 8)
RUN=$( (echo "$MOST_USED"; dmenu_path | grep -vxF "$MOST_USED") | $DMENU) && \n(echo $RUN; head -n99 $CACHE) > $CACHE.$$ && \nmv $CACHE.$$ $CACHE
case $RUN in
*\;) $TERMI ${RUN/;/} & ;;
*) $RUN & ;;
esac
exit 0
.dmenurc:
# makes dmenu identical across all scripts by sourcing this file
# aur/dmenu-vertical-xft required for xft fonts
DMENU='dmenu -i -fn xft:Inconsolata-10 -r -x 0 -y 17 -nb #303030 -nf #909090 -sb #909090 -sf #303030'
Again I take NO credit for this code!! I'm just passing it on because I like it Thanks brisbin33! What would be really cool is generalizing the caching script so any use of dmenu could use it (have different caches) -- for example -- normal dmenu, snippy, mpc playlist launcher.
Scott
Last edited by firecat53 (2009-09-13 20:17:06)
Offline
What would be really cool is generalizing the caching script so any use of dmenu could use it (have different caches) -- for example -- normal dmenu, snippy, mpc playlist launcher.
Scott
I think I saw a patch in C for dmenu sometime that allowed a commandline arg to use a specific cache file. So that's probably exactly what you're looking for.
Personally I've never felt a need for it though
Oh btw, for those guys who use uzbl, I wrote snips which let you pick url's from your uzbl history/bookmarks. see http://github.com/Dieterbe/snip/tree/ma … les/snips/
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline