A long time ago, I had the idea of improving the interface between
shell completion and the programs being completed. The result of
this was the bzr shell-complete command (or bzr s-c for short),
which was never fully fleshed out, and has since fallen into disrepair.
The principles behind this are + the program is the best place to store up-to-date and accurate information + the program already knows all these things (albeit usually in unparseable forms) + duplicating information and effort is annoying
Here is an excerpt from bzr s-c, which was intended to give a comprehensive
list of subcommands, paired with short descriptions:
diff:show differences in the working tree, between revisions or branches
export:export current or past revision to a destination directory or archive
get:create a new copy of a branch
help:show help on a command or other topic
ignore:ignore specified files or patterns
ignored:list ignored files and the patterns that matched them
info:show information about a working tree, branch or repository
init:make a directory into a versioned branch
There is one subcommand per line, separated from its description by a colon.
Next you can invoke something like bzr s-c diff to get the possible options
and arguments for the diff subcommand, although the output you would see today
is broken and nearly useless.
Since I've lost faith in bzr, I'll illustrate what the output might be
corresponding to topgit's tg remote if topgit supported this kind of thing:
--populate
REMOTE
This would mean that tg remote can understand the option --populate, which
takes no argument, and that the first non-option argument should be a
REMOTE.
REMOTE would then be defined, for example, in zsh's _topgit function as
some kind of git remote which is completed in the same way you might complete
a git remote for git.
The exciting part then, is that if tg remote starts taking a --decimate
option, the topgit completion helper subsystem will start outputting it
and _topgit will do the right thing without having to be altered.
For tg export, things are a bit more complicated, so let's have it be
described in the style of the zsh completion system:
'(--collapse)--quilt:directory:_directories'
'(--collapse -b --branch)'{-b,--branch=}':branches:BRANCHES'
'(--quilt)--collapse:branch:BRANCH'
This means that --collapse and --quilt are exclusive, that -b
and --branch cannot be used with --collapse, that -b and
--branch are equivalent, that -b and --branch take an argument
in the form of BRANCHES, that --collapse takes an argument in the
form of BRANCH, and that --quilt takes an argument that's a
real directory in the filesystem.
Then _topgit would have logic to interpret BRANCH as a branch, and
BRANCHES as a comma-separated list of branches.
A similar idea is the one used by axp. If you invoke axp self completion zsh,
it will output zsh completion functions for you. To me this seems more onerous
on both the developers and the end users, but I suppose it gives you immediate
flexibility that a more generic interface would lack.
For a while, lots
of
people
have been using their zsh prompts to display information
about their current VCS (git in particular) working directories. I am no
exception, though I was just doing a simple git rev-parse and
git symbolic-ref in my precmd().
Starting with zsh-beta 4.3.6-dev-0+20080921-1, I am now using the vcs_info subsystem developed by Frank Terbeck. It has backends for bzr, cdv, cvs, darcs, git, hg, mtn, p4, svk, svn, and tla. These backends can be enabled or disabled via configuration.
To get it working quickly, do something like
autoload -Uz vcs_info
precmd() {
psvar=()
vcs_info
[[ -n $vcs_info_msg_0_ ]] && psvar[1]="$vcs_info_msg_0_"
}
PS1="%m%(1v.%F{red}%1v%f.)%# "
Posted Sun 21 Sep 2008 11:52:25 AM EDT
Freshly stolen from Europe:
b() {
setopt localoptions extendedglob
if [[ $# -eq 1 ]]; then
case "$1" in
([0-9]##)
links "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
;;
(*@*)
links "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
;;
(*)
links "http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=${1%%_*}"
;;
esac
else
print "$0 needs one argument"
fi
}
Posted Sun 09 Dec 2007 12:31:47 PM EST
I needed to quickly stuff a bunch of random music onto a ridiculously small vfat medium. I used this:
#!/bin/zsh
# also released under the gnocchi-ng license
zmodload -i zsh/datetime
zomg_shuffle() {
declare -A h
local +h -Z 5 RANDOM=$EPOCHSECONDS
integer i
for ((i=1; i <= $#; ++i)) { h[$i.$RANDOM]=$argv[i] }
reply=( $h )
}
zug=( /pathtomusic/ogg/**/*.ogg )
zomg_shuffle $zug
for i in "$reply[@]"
do
cp -v "$i" /media/tinyflashdrive/"${${i:t}//[:?\"*]/_}" || { rm -v /media/tinyflashdrive/"${${i:t}//[:?\"*]/_}" ; exit 1}
done
Posted Wed 05 Dec 2007 07:49:14 PM EST
Someone gave me an MP3 player. He did so for somewhat devious reasons, but that's outside the scope of this post. It is a SanDisk Sansa—stop thinking of pulp fantasy—and it has roughly 500 gigs too little storage space. The FAQ says such cute things as “The original firmware is recommended for charging at this time,” and “Rockbox does not currently provide either functionality so you will need to continue using the original firmware (for now) in MSC (UMS) mode to add music to the Sansa.”
Please don't tell my Sansa about this FAQ because it thinks that both of those claims are false.
I want my newfangled device to participate in the spyware fiesta known as last.fm, and Rockbox has an option for supporting that; if you turn it on, it fills a /.scrobbler.log file with tab-delimited lines for your parsing pleasure.
Rather than download additional software to cope with my new lifestyle, I whipped up the following script (released under the gnocchi-ng license) which “converts” the log to something you can just stuff into your \~/.zomg/cache file and send up to the submission server at your next appropriate invocation of zomg. I'm afraid you'll have to handle any timestamp sorting by hand, but if you script it, be a dear and implement some kind of cache file locking.
#!/bin/zsh
# Copyright (C) 2007 Clint Adams. All rights reserved.
# This program has no name and is released under the terms of
# the gnocchi-ng license.
audioscrobbler_urlencode() {
if (( $+options[multibyte] )); then
setopt localoptions extendedglob nomultibyte
else
setopt localoptions extendedglob
fi
input=( ${(s::)1} )
print -- ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%$(([##16]#match))}
}
audioscrobbler_constructquery() {
local sid="$1"
local artist=$(audioscrobbler_urlencode "$2")
local track=$(audioscrobbler_urlencode "$3")
local album=$(audioscrobbler_urlencode "$4")
local mbid=$(audioscrobbler_urlencode "$5")
local length=$(audioscrobbler_urlencode "$6")
local ttime=$(audioscrobbler_urlencode "$7")
local source="$8"
local tracknum="$9"
reply=("&s=${sid}" "&a[0]=${artist}&t[0]=${track}&i[0]=${ttime}&o[0]=${source}&r[0]=&l[0]=${length}&b[0]=${album}&n[0]=${tracknum}&m[0]=${mbid}"$'\0')
}
while read -r line
do
local -a field
field=("${(@ps:\t:)${line}}")
if [[ $field[6] == L ]]; then
audioscrobbler_constructquery "" "$field[1]" "$field[3]" "$field[2]" "" "$field[5]" "$field[7]" P "$field[4]"
print "$reply[2]"
fi
done <<(grep -v '^#' .scrobbler.log)
Posted Thu 25 Oct 2007 11:11:25 PM EDT
The zsh-lovers man page contains the following example.
# Show me all the .c files for which there doesn't exist a .o file. $ c=(*.c) o=(*.o(N)) eval 'ls ${${c:#(${~${(j:|:)${o:r}}}).c}:?done}'
What's with the ugly dollar-sign prompt? I'd do it this way instead.
print *.c(e_' ! -e $REPLY:r.o '_)
Posted Sat 06 Oct 2007 05:16:51 PM EDT
Let's say you're a French person who has EXTENDED_GLOB on and
types HEAD^ all the time, but can't be bothered to type a
backslash before the caret. Personally, I have no problem typing
HEAD\^, but I probably only do that twice a day.
Here are a few/several/many (depending on how you count) “solutions”. They all have their downsides. Finding out their side effects is an exercise for the reader.
Number one: setopt noextendedglob
Number two: setopt nonomatch
Number three: alias git='noglob git'
Number four: custom ZLE widget:
accept_line_with_headcaret () {
if ${BUFFER} = git*HEAD\^* ; then
BUFFER="${BUFFER//HEAD\^/HEAD\\^}"
fi
zle .accept-line
}
zle -N accept-line accept_line_with_headcaret
I'll just keep hitting the backslash key.
Posted Thu 04 Oct 2007 03:17:15 PM EDTZOMG has now been updated for Audioscrobbler 1.2, and is now in a Mercurial repo.
Users should be aware that the caching of credentials and the caching of unsubmitted tracks have both changed in incompatible ways, so be sure to flush or remove your old data before upgrading.
Probably the only exciting user-visible change is that currently-playing tracks will now show up on last.fm as “now listening”.
Posted Sun 12 Aug 2007 02:02:32 PM EDTWith these shells as sh, results from the current posh testsuite:
| Shell | Failed | Passed |
| bash | 25 (22 unexpected) | 140 (1 unexpected) |
| dash | 47 (45 unexpected) | 118 (2 unexpected) |
| ksh | 36 (32 unexpected) | 129 |
| pdksh | 16 (12 unexpected) | 149 |
| posh | 4 (as expected) | 161 |
This may reflect more on the unsuitability of the posh testsuite for other shells than the failure of those shells to conform to the expectations set by Debian policy. Patches welcome.
Posted Fri 17 Nov 2006 10:10:20 PM ESTFar too late after #394749 got fixed, ZOMG switched from mpg321 to mpg123.
The reason that this is so exciting is that mpg123 supports output buffering, whereas mpg321 has been sucking ass for over five years.
Posted Tue 14 Nov 2006 10:02:35 PM EST