[comp.unix.shell] separate the command language and interactive shell

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (04/29/91)

I use various shells for my ``command language'' and a souped-up line
discipline for my ``interactive shell.'' I just added some of the new
interactive features to my poor man's line discipline. From pmlined's
latest README:

  You edit the current line on the status line (through stderr). Long
  lines scroll horizontally. When you press return, pmlined sends the
  line to stdout. All the usual editing characters, including ^U, ^W,
  backspace, delete, and ^V, work normally. ^A switches between this
  editing mode and the usual tty mode. In version 1.5, you also get ^H
  and ^L to move the cursor back and forth within the line, and a
  20-line editable history with ^B and ^F. In this version, ^P sets the
  prompt to whatever you've typed on the current line. Note that the
  prompt will be reset if you use a command from the history that had a
  different prompt. ^O<char> stores the current line in a macro labelled
  <char>; you invoke the program with <tab><char>. (Use ^V to enter
  special characters into the macro.) The arrow keys now work for up (^B),
  down (^F), left (^H), and right (^L).

At 400-odd lines pmlined is hardly a bloated piece of code. It doesn't
bother with multiplexing or tty handling or any system stuff; it just
reads its input, gives you an interactive display on stderr, and feeds
completed lines to your shell (typically ``pty csh'') through stdout.
It's hard to get much simpler than that!

---Dan

john@sco.COM (John R. MacMillan) (05/08/91)

|In article  <-#8Gd-e*1@cs.psu.edu> Felix Lee writes without
|understanding anything that he is replying to:

Please try and keep this civil.  I think that Felix understood what he
was replying to.

|]>  <command-line> ::= <command> <arg>* | "set" <var> = <arg>
|]>  <arg> ::= "-"<char>* | "$"<var> | <file>
|]>  path-complete <command> with "echo $path"
|]>  path-complete <file> with "pwd"
|]>  list-complete <var> with "variable-completion %s"
|]
|]Let's see.  The syntax is naive: it doesn't do quoting of any sort, so
|]you can't do file completion on files with special characters in it.
|
|I can make the syntax as complex as needed and do file completion with
|any characters.

No you can't.  You don't know what the characters mean, and every
clang might be different.  ~john means john's home to [ck]sh, nothing
special to sh, and ``not john'' to a debugger.  How do you propose to
complete it in ish?

|]How about completing filenames with variables embedded: "$HOME/$a/a".
|
|This is a non-problem.  The ish gets the value of the environment
|variable and completes however the ish-writer thought it should be
|done.

It might not be an environment variable.  How can the ish writer know
what the clang writer thought a file should be?

I'm running a cooperating sh clone under ish:

$ foo=bar
$ ls -l ~/${foo}bar/pr<ESC><ESC>

How can ish complete that?  Now change "sh" above to "ksh" and try
again.  They have to complete differently, how can ish know that?

How can ish complete:

$ ls -l ${foo%a*}ogus.<ESC><ESC>

And what about:

$ IFS=': '
$ ls:-l:$foo/prog<ESC><ESC>

I don't want my clang to be restricted to your ish syntax.  Keep the
ish simple, let it do what it reasonably can (history, line editing)
and let the clang do what it does (interpret the command line).

|]How about glob completion: expand things like "*" and "f*".
|
|If the ish writer wants to expand wildcards, the ish can do so.

Again, what wild cards?  Csh-like, sh-like, ksh-like?  I don't want
the ish to force this on all my clangs.

|]A more serious problem: the shell isn't the only thing that
|]wants/needs completion.  gdb, for example, wants to do completion.
|
|That was one of the considerations that lead to my suggestion in the
|first place.  Write a command line description for gdb just like for
|the clang.

And another for sh, ksh, csh, rc, ed, sdb, dbx, and roll all these
into ish?  Leave the command line parsing in the command, where it's
already being done.

|]Teaching the front-end about all this gets ugly.
|
|All of this is part of the front end, there is no "teaching" about it.

Sure there is.  You just said ``Write a ... description for gdb''.
That's teaching ish about gdb syntax, whether at compile time or run
time (I'm not sure which you're advocating).  Every time you expand ish
this way, I'll add a new clang with a conflicting syntax.

|]The simplest way to handle completion is to have a communication
|]channel between the front-end and the current interactive process.
|
|It might make life a little easier for the ish writer, but it makes
|life harder for the clang writer.  Since completion is an ish feature,
|the clang writer should not have to worry about it.

I disagree.  Completion is context-dependent on how the clang is going
to interpret the command-line, so it belongs with the clang.  And it
doesn't really make the clang harder.  In both your mechanism, and the
one Felix and I seem to like, the clang must do completion.  In yours,
you make ish parse the line and send a succinct completion request to
the clang, which does the completion.  I make the clang parse the line
_because it has to be able to parse lines anyway_ and then do the
completion.

|](Which immediately has two problems in Unix: What's the "current
|]interactive process"?  How do I talk to it?  (So how do we fix Unix?))
|
|My supposedly more complex scheme doesn't have either problem.

Actually it still has the problem of hiding the communication with the
clang if you want to do that.

Your scheme is complex in that it requires a command line parser be
built into ish, and further, that it either be able to parse the
conflicting syntax of every clang it is to run, or the clang user
loses ish-functionality (eg. completion) on things that ish cannot
parse.

gudeman@cs.arizona.edu (David Gudeman) (05/09/91)

In article  <1991May08.162448.13778@sco.COM> John R. MacMillan writes:
]|In article  <-#8Gd-e*1@cs.psu.edu> Felix Lee writes without
]|understanding anything that he is replying to:
]
]Please try and keep this civil.  I think that Felix understood what he
]was replying to.

Sorry, that was ill-considered.  But I was rather impressed by the
fact that not one of the 5 or 6 criticisms seemed valid.  One of us is
certainly not understanding the other.

]|I can make the syntax as complex as needed and do file completion with
]|any characters.
]
]No you can't.  You don't know what the characters mean, and every
]clang might be different.  ~john means john's home to [ck]sh, nothing
]special to sh, and ``not john'' to a debugger.  How do you propose to
]complete it in ish?

There are two possible answers to this.  First, the input of almost
every interactive line-oriented program can be described with a CFG.
CFG's are well-understood, easy to write, and easy to use, so you
_can_ describe the full language if necessary.  Alternatively, _I_
would prefer an ish that more or less ignored vagaries in file syntax
-- giving a uniform way to reference files across programs.  For
example ~ and ~<name> get expanded by the ish.  Clangs don't have to
understand them at all.  And those clangs that are already writen that
don't understand these get added functionality just by running under
the ish.

]It might not be an environment variable.  How can the ish writer know
]what the clang writer thought a file should be?

By the command-line description.

]I'm running a cooperating sh clone under ish:
]
]$ foo=bar
]$ ls -l ~/${foo}bar/pr<ESC><ESC>
]
]How can ish complete that?  Now change "sh" above to "ksh" and try
]again.  They have to complete differently, how can ish know that?

That is a trivial generalization from the examples I gave in the first
post.  There is nothing difficult about it.  The ish knows the
difference between "sh" and "ksh" because they have different
command-line descriptions.

]$ ls -l ${foo%a*}ogus.<ESC><ESC>

I don't see anything difficult here either.

]$ IFS=': '
]$ ls:-l:$foo/prog<ESC><ESC>

Changing the syntax of a clang is a problem.  It can be handled, but
as an ish writer I wouldn't bother.

]I don't want my clang to be restricted to your ish syntax.  Keep the
]ish simple, let it do what it reasonably can (history, line editing)
]and let the clang do what it does (interpret the command line).

Completion is something that is completely worthless in a batch job.
That implies to me that it is an interactive function that belongs in
the interactive shell.

]Again, what wild cards?  Csh-like, sh-like, ksh-like?  I don't want
]the ish to force this on all my clangs.

I do.  I want wild-card interpretation to be consistent across all
programs that I use under the ish -- just like all the other
interactive conviences.  But if the clang writer is serious about it,
these syntactic peculiarities can be included in the command-line
description.  The clang can still do all of the completion if the
writer wants to.

]|That was one of the considerations that lead to my suggestion in the
]|first place.  Write a command line description for gdb just like for
]|the clang.
]
]And another for sh, ksh, csh, rc, ed, sdb, dbx, and roll all these
]into ish?  Leave the command line parsing in the command, where it's
]already being done.

No, you don't roll them into the ish.  You write them seperately and
every ish reads the same descriptions.  Yes, you write one for each
program that you want to get special help from the ish.  Programs that
don't have these descriptions can still get the advantages of file
name completion -- with no extra work at all.  This is easier than
writing a command completion system for each package.

And for that matter, you could use the same BNF description in the
bash implementation -- reducing the extra work to almost nothing.

]|]Teaching the front-end about all this gets ugly.
]|All of this is part of the front end, there is no "teaching" about it.
]Sure there is.  You just said ``Write a ... description for gdb''.

Lets not exaggerate the difficulty of writing a BNF description.  It
is certainly not as "ugly" as writing interactive features into all
line-oriented programs.

]That's teaching ish about gdb syntax, whether at compile time or run
]time (I'm not sure which you're advocating). Every time you expand ish
]this way, I'll add a new clang with a conflicting syntax.

There a seperate description files for each ish-ready program.  The
ish writer can decide whether to compile these descriptions into the
ish or load them interactively.  Presumably if the ish writer decides
to compile them in, he thinks there is some great advantage to this
that overcomes the inconvience.  I'd probably write the ish to read
them interactively, so adding a new clang with a new syntax is
completely transparent.  (I don't know what you mean by "conflicting"
syntax.  Conflicting with what?)

]I disagree.  Completion is context-dependent on how the clang is going
]to interpret the command-line

That depends on your model of completion.  Some ish's may only have
filename completion -- and only on files with ish syntax.

]doesn't really make the clang harder

Then how come so few programs have it?

]...  In both your mechanism, and the
]one Felix and I seem to like, the clang must do completion.  In yours,
]you make ish parse the line and send a succinct completion request to
]the clang, which does the completion.

In my system only one program --the ish-- has to do file completion.
And file completion is the hardest kind to to.  In your scheme,
practically every program has to include the fairly substantial amount
of code necessary to complete file names (or have no completion at
all) and that code is only useful in interactive situation.  For
programs that are fequently run in batch mode the file completion code
is dead weight.

]  I make the clang parse the line
]_because it has to be able to parse lines anyway_ and then do the
]completion.

If the clang writer wants to all do his own completion, there is
nothing in my description to prevent this.  Just give a trivial
command-line decription that tells the ish to send any partial line to
the clang for completion.  But with my scheme, the clang writer has
that choice.  With your scheme the clang writer has the choice to
write his own completion package or have no completion.

My scheme has the advantage that it is completely upward compatible
and transparent to existing programs.  And programs can be made to
work better with the ish without changing the program at all.  A user
that has a program that he wants to work better with the ish can just
write a description file that handles the features that user wants.

]Actually it still has the problem of hiding the communication with the
]clang if you want to do that.

I don't understand what you mean.

]Your scheme is complex in that it requires a command line parser be
]built into ish,...

It gives the ish writer the option of implementing a generalized
parser to give added functionality to the user.  The ish writer
doesn't _have_ to write one.  I'm using a perfectly useful ish right
now that doesn't parse command lines.  It only completes file names
and only understands shell variables and ~, but it is a lot nicer than
any Unix shell I know of.  And I didn't have to do anything to the csh
that runs under it.  It's called cmushell and runs under GNU Emacs.
--
					David Gudeman
gudeman@cs.arizona.edu
noao!arizona!gudeman

john@sco.COM (John R. MacMillan) (05/11/91)

I think we're probably going to have to end up calling this a
religious issue, and agreeing to disagree, but I'll try to address
your points.

David Gudeman <gudeman@cs.arizona.edu> writes:
|]|I can make the syntax as complex as needed and do file completion with
|]|any characters.
|]
|]No you can't.  You don't know what the characters mean, and every
|]clang might be different.  ~john means john's home to [ck]sh, nothing
|]special to sh, and ``not john'' to a debugger.  How do you propose to
|]complete it in ish?
|
|There are two possible answers to this.  First, the input of almost
|every interactive line-oriented program can be described with a CFG.
|CFG's are well-understood, easy to write, and easy to use, so you
|_can_ describe the full language if necessary.

I think what you're saying requires the ish to recognize which clang
is running (hence which CFG to use), either by trying to have the ish
recognize them, or by explicitly telling the ish.  In many ways, this
issue is like Felix's concern about how to tell which is the current
interactive process; in our method, in order to communicate with it,
and in your method to determine which CFG to use.

|Alternatively, _I_
|would prefer an ish that more or less ignored vagaries in file syntax
|-- giving a uniform way to reference files across programs.  For
|example ~ and ~<name> get expanded by the ish.  Clangs don't have to
|understand them at all.  And those clangs that are already writen that
|don't understand these get added functionality just by running under
|the ish.

That's certainly a big advantage in your scheme, although clangs that
don't have the ``echo $pwd'' capability still have to use the ish
current working directory for completion, so it's not as big a win in
those cases.

|]$ ls -l ${foo%a*}ogus.<ESC><ESC>
|
|I don't see anything difficult here either.

What I was getting at was that ${foo%a*} is a powerful ksh construct
that I want access to when completing.  And I want ${foo:t} when using
csh.  And I want $foo(3 5) when using rc.  I don't think it's
reasonable to have ish support all these.

That, I think, is where we differ.  You would prefer a consistent
interface to the clangs, and I would prefer to have all the clang
features available to me.  My way does require more clang cooperation
than yours, so is less suitable as a short term solution.

|]I don't want my clang to be restricted to your ish syntax.  Keep the
|]ish simple, let it do what it reasonably can (history, line editing)
|]and let the clang do what it does (interpret the command line).
|
|Completion is something that is completely worthless in a batch job.
|That implies to me that it is an interactive function that belongs in
|the interactive shell.

But all the clangs are already interactive, or you wouldn't be running
them under ish; they may be suitable for batch jobs as well, and in
those cases, the completion support is extra bulk, but so is putting
out prompts, etc.

|]Again, what wild cards?  Csh-like, sh-like, ksh-like?  I don't want
|]the ish to force this on all my clangs.
|
|I do.  I want wild-card interpretation to be consistent across all
|programs that I use under the ish -- just like all the other
|interactive conviences.  But if the clang writer is serious about it,
|these syntactic peculiarities can be included in the command-line
|description.  The clang can still do all of the completion if the
|writer wants to.

Again we differ in the same way; you want consistency, and I want the
full power of each clang.

|Lets not exaggerate the difficulty of writing a BNF description.  It
|is certainly not as "ugly" as writing interactive features into all
|line-oriented programs.

A matter of where you want your ugly. :-) I'd rather have the clangs
do completion to get their full expressive power.  I think trying to
put that power, even for something as ``simple'' as variable expansion,
into the ish is ugly.

|...  (I don't know what you mean by "conflicting"
|syntax.  Conflicting with what?)

With other clangs.  At that time I had not realized that you wanted
the ish to recognize which clang was running and use the appropriate
CFG.

|]I disagree.  Completion is context-dependent on how the clang is going
|]to interpret the command-line
|
|That depends on your model of completion.  Some ish's may only have
|filename completion -- and only on files with ish syntax.

Right, and I think we have different models of completion.

|]doesn't really make the clang harder
|
|Then how come so few programs have it?

Because it's of no value without a cooperating raw mode interface.  A
completion command is not really any use if it's not convenient, and
without an ish, it simply wouldn't be convenient.

|]...  In both your mechanism, and the
|]one Felix and I seem to like, the clang must do completion.  In yours,
|]you make ish parse the line and send a succinct completion request to
|]the clang, which does the completion.
|
|In my system only one program --the ish-- has to do file completion.
|And file completion is the hardest kind to to.  In your scheme,
|practically every program has to include the fairly substantial amount
|of code necessary to complete file names (or have no completion at
|all) and that code is only useful in interactive situation.  For
|programs that are fequently run in batch mode the file completion code
|is dead weight.

I think the notion of completion is clang-dependent.  Filename
completion is a very common instance, and it seems tempting to try and
move it into the ish, because so many programs want to do it.  However
doing it that way sacrifices clang-power that can express filenames
unless you duplicate the clang functionality in the ish, which means
dead weight that way.

Ideally, the ``dead weight'' completion code that is indeed common
(scanning the directory and matching) never gets paged in when the
program is running in batch mode.  And if you put it in a shared
library, it doesn't even take up disk space.

|My scheme has the advantage that it is completely upward compatible
|and transparent to existing programs.  And programs can be made to
|work better with the ish without changing the program at all.  A user
|that has a program that he wants to work better with the ish can just
|write a description file that handles the features that user wants.

Yes, this is true.  In fact I would probably put very rudimentary
filename completion in my ish, so that when the clang was non-
cooperating, at least _something_ would be available to the user.

|]Actually it still has the problem of hiding the communication with the
|]clang if you want to do that.
|
|I don't understand what you mean.

Your CFG tells you the user is trying to complete a filename, so you
do an ``echo $pwd'' (in the defined per-clang way, if there is one)
and read the result, to get the clang's notion of the current
directory.  I'd rather not see that transaction, and hiding it can get
rather messy.  (This same problem makes me lean toward having a
completely separate communication channel for my method.)

|...  I'm using a perfectly useful ish right
|now that doesn't parse command lines.  It only completes file names
|and only understands shell variables and ~, but it is a lot nicer than
|any Unix shell I know of.  And I didn't have to do anything to the csh
|that runs under it.  It's called cmushell and runs under GNU Emacs.

Part of what has gotten me thinking about this is that cmushell/emacs
is exactly what I don't want. :-) In deciding why that was the case,
I felt that it was because the ish was trying to do too much.

As I said at the start, I guess we'll just have to agree to disagree.
You go your ish, and I'll go mine. :-)

cks@hawkwind.utcs.toronto.edu (Chris Siebenmann) (05/14/91)

john@sco.COM (John R. MacMillan) writes:
| Ideally, the ``dead weight'' completion code that is indeed common
| (scanning the directory and matching) never gets paged in when the
| program is running in batch mode.  And if you put it in a shared
| library, it doesn't even take up disk space.

 There are a surprising amount of use of completion/shell filename
expansion used in 'batch' shell scripts, at least in the shell scripts
I tend to write. Most of the nominally interactive features in my
(sh-like) shell tend to get used in shell scripts, and most of the
nominally shell-script oriented ones have gotten used for interactive
stuff.

--
	"This Vi mode "feels" like Vi to me; it drives me nuts in the
	 ways that I am used to Vi driving me nuts." 
		- Brian Fox
cks@hawkwind.utcs.toronto.edu	           ...!{utgpu,utzoo,watmath}!utgpu!cks