Hi all,

For those not acquainted with zsh: extended globbing is one of the
many features of zsh that allows you to match files satisfying a given
criteria in a inline manner (instead of going through a loop). For
example, "echo abc*(/)" gives you all directories with names starting
with "abc" in current directory, while "rm .*(@)" removes all symlinks
with names starting with ".", etc. It is a useful feature, but I don't
really like the arcane syntax.

Fish doesn't have extended globbing (which is good actually :-), so
I'm tempted to write this:

function filter
    set predicate $argv[1]
    for i in (seq 2 (count $argv))
        test $predicate $argv[$i]; and echo $argv[$i]
    end
end

So now I write "echo (filter -d abc*)" and "rm (filter -L .*)" to
achieve the same effect as "echo abc*(/)" and "rm .*(@)" in zsh. It is
more verbose, but the readability is considerably better; it also
allows you to reuse the knowledge of the "test" builtin.

This works fine until, of course, you start to encounter file names
containing newlines. Try this:

cd (mktemp -d)
mkdir 'a
b'
count *
count (filter -d *)

Clearly, The problem stems from the fact that when fish expands the
command substitution (filter -d *), filenames echo'ed by "filter" run
together before being split on newlines to render the substituted
words. A newline in one of the filenames is then indistinguishable
with two filenames.

So this leads to my proposal:

* When evaluating a fish function, maintain an alternative output
buffer besides stdout. The buffer is actually a dynamic-sized list
(std::vector for C++ programmers) of strings. Introduce a new builtin
(say "put") to write to that buffer.

* Exactly one of the two output buffers (let's call them stdout and
altout) should be active within a function.

* Within functions, calling "put" activates the altout and closes
stdout. Each invocation of "put" with k arguments appends k new
elements to altout. (The relationship between altout and stdout still
needs some thoughts though.)

* When command substitution is performed, it is checked which of
stdout and altout is active (the latter is only possible for fish
functions; external commands always have only stdout active). If
altout is active, the elements in altout are substituted directly. If
stdout is active, the content in stdout is split on newlines before
being substituted (as is currently done).

* When altout is written to when there is no enclosing command
substitution (eg. calling "put" on the prompt), anything written to it
is directed to stdout plus a newline.

With altout I can write my "filter" by replacing "echo" with "put" and
it's now newline-safe.

Being able to output arrays of strings can be of many other uses -
actually it enables you to write any array manipulating functions in
an easy way.

If the newline-in-filenames stuff sounds too invented and unlikely,
consider why shells need real arrays instead of strings joined by
delimiters (be it whitespace or newlines) at all. Actually, one of the
favorite things about fish is its clean array syntax, it is a really
nice thing. I think fish deserves the added expressive power. :)


--
Regards,
Cheer Xiao

------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
_______________________________________________
Fish-users mailing list
Fish-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/fish-users

Reply via email to