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

gudeman@cs.arizona.edu (David Gudeman) (04/28/91)

In article  <419@smds.UUCP> Richard Harter writes:

]Actually I think this is an excellent idea; however there are some
]issues to be resolved.  I am going to use Lakota as a reference point
]since it was designed with this kind of usage in mind; however other
]languages such as TCL, Python, and Icon are relevant.

Just to clarify my terms: I would call sh a command language and csh a
combination of command language and interactive shell.  I wasn't
suggesting a completely different type of command language like those
mentioned above (although I think it is a good idea).  My suggestion
was just to separate the interactive part of the unix shell from the
command part.  You would run the interactive shell of your choice with
the interactive command language of your choice; for example you could
run an interactive shell that implements the csh history mechanism
with sh as your command language.

(In the following, an interactive shell is an ish and a command
language is a clang.)

]...what one
]really needs is a solid protocol for the interface between the shell
]and the command language.  Here are some of the issues that occur to
]me:
]
](a)	History recording
]Presumably the shell is responsible for history editing.  Who has the
]responsibility for capturing history?  If multiple programs (processes,
]pseudo-processes) are sharing the interpreter, can command history
]information be passed from one to another?

Features that are only useful interactively belong in the ish, and
those that are only useful in programs belong in the clang, those that
are useful in both applications are problematic.  I'd say that history
recording belongs in the ish because it is only useful interactively.
Sharing of history among different programs is entirely controlled by
the ish.  Different ishs can do different things.

](b)	Command completion
]A popular feature of some shells is command and/or file completion.
]Does this extend to commands in the shell language?  If so, how does
]the interpreter pass to the shell the list of commands to search?
](This isn't hard, but one needs a spec.)

There are a lot of things that the ish and clang might want to
communicate to each other -- this could be an argument for not
separating them.  However, I prefer to look for a way to have them
communicate without affecting other programs that aren't in on the
scheme.  Here are some skeletal ideas:

First, this assumes a line-based program.  (Programs that take over
the screen probably will not have much use for the ish).  There is an
environment variable 'ISH' that is set to the name of the interactive
shell currently controlling the terminal.  This variable is only set
by an ish that understands the protocol outlined below.  A program
that is prepared to interact with an ish will will communicate with
the ish using the protocol if ISH is set and if the output of the
program is being piped to the ish (I haven't figured out how the
program determines that).

Since all stdout of the process is being piped to the ish (so the ish
can do interactive things with it) the program can communicate with
the ish by special output lines.  Since the i/o is line-based, the
program and ish can use non-printable characters to communicate.  So
say that any text bracketed by ^A and ^B is treated as communication.
When an ish-ready program starts up, it begins by sending to stdout a
communication that specifies any relevant information.  When a program
exits or turns the ish pseudo-tty over to another program it send
relevant information to the ish.  When an ish needs filename or
command completion, it sends communication to the program.

Of course an alternative to the ^A^B hack is to have a separate pipe
between the programs and the ish for communication (stdish?), but this
means a program that is not ish-ready gets started up with an extra
file descriptor that it doesn't know what to do with.  Is that a
problem?

](c)	Processes and pseudo-processes
]A Lakota pseudo-process is implemented as part of the parent process.
]The issue here is whether the command language interpreter executes as
]part of the shell process or as a separate (cooperating process).

I don't have a preference as long as neither one actually needs the
other to operate effectively.

](d)	Environment variables
]Does the shell or the command interpreter have the responsibility for
]managing process environment variables?  What are the rules?

Hmm.  Environment variables definitely have to be part of the clang
since you need them in programs.  But the ish needs environment
variables too.  How about this: environment variables are part of the
clang.  The ish is started originally by some other program (like the
clang that reads the .login file) and inherits the environment from
that program as usual.

Since the ish doesn't spawn other processes (the clang does that) you
don't really need the ability to change general environment variables,
you only need to change things like 'history' that change the
behavior of the ish.  But I'd say that the ability to change the
behavior of the ish is part of the ish program.  Each one can provide
its own ways to effect this behavior -- and that may or may not look
like setting environment variables.
--
					David Gudeman
gudeman@cs.arizona.edu
noao!arizona!gudeman

rh@smds.UUCP (Richard Harter) (04/28/91)

In article <2509@optima.cs.arizona.edu>, gudeman@cs.arizona.edu (David Gudeman) writes:

... A number of comments on my comment which I am going to draw on
but now quote directly.  First of all, some terms:

> Just to clarify my terms: I would call sh a command language and csh a
> combination of command language and interactive shell...

David introduces the terms ish for interactive shell and clang for the
command language.  He wasn't thinking in terms of anything radically
different from sh as the clang; in my view one should keep this possibility
carefully in mind from the beginning.  David's dividing line is a little
loose but the general notion is that the interactive features belong
in the ish and command execution belongs in the clang.  He remarks that
there is assumption of a line oriented interface involved here.

On this matter it seems reasonable that (a) the clang is line oriented
and that (b) it can either operate standalone or take its input from the
ish.  There is an implication here that the clang is a servant of the
ish; i.e. an ish can select a clang but a clang cannot select an ish.
(Except as a subprocess.)

Howabout stdout?  One gets the feeling that stdout should go through
the ish, i.e. all output of the clang and its subprocesses are piped
back to the ish.  This all implies (I think) that the ish and the clang
are separate processes with the clang being started by the ish.  Since
the clang is a child that should resolve environment variable issues
shouldn't it?  Following this line we have three units

The ish:  It talks to the terminal and, as far as interactive action
goes, can be whatever you like.  It doesn't execute OS commands; its
command syntax or window widgets or whatever are its responsibility.
All terminal IO ends up going through it.

The clang:  It executes as a standalone command processor.  Its input
comes from stdin and goes to stdout and stderr; what happens to them
is none of its business.

The interface:  It is encapsulated in the ish.  It starts the clang
process and handles passing I/O back and forth.  David suggests using
control characters for communication of special commands.  Offhand I
don't like this kind of notion; it's probably better not to build in
assumptions like that.  Wouldn't it be better to have a separate
communications path.

Oddly enough the ish process never goes anywhere; i.e. cd and pwd
are executed by the clang.  Another point is that the ish will need
some special commands to set its own environment variables and to do
clang selection.  Also one has to take care of interrupts, i.e. if 
one issues an interrupt to the ish it has to trap it and pass it to
the clang with the requirement that (a) if the clang is executing
it accept the interrupt or (b) if it is executing a subprocess the
interrupt be passed to the subprocess.

All of this implies in turn that the clang must also have its own
encapsulated interface.
-- 
Richard Harter, Software Maintenance and Development Systems, Inc.
Net address: jjmhome!smds!rh Phone: 508-369-7398 
US Mail: SMDS Inc., PO Box 555, Concord MA 01742
This sentence no verb.  This sentence short.  This signature done.

hansm@cs.kun.nl (Hans Mulder) (05/02/91)

In <2509@optima.cs.arizona.edu> gudeman@cs.arizona.edu (David Gudeman) writes:

>Just to clarify my terms: I would call sh a command language and csh a
>combination of command language and interactive shell.  I wasn't
>suggesting a completely different type of command language like those
>mentioned above (although I think it is a good idea).  My suggestion
>was just to separate the interactive part of the unix shell from the
>command part.  You would run the interactive shell of your choice with
>the interactive command language of your choice; for example you could
>run an interactive shell that implements the csh history mechanism
>with sh as your command language.

>(In the following, an interactive shell is an ish and a command
>language is a clang.)

Sorry for injection some facts into an otherwise useful theoretical
discussion, but in 1987 (according to the copyright notice) Kazumasa
Utashiro of Software Research Associates, Inc. wrote a nice "ish"
called "fep" (for Front End Processor).  It's invocation is

fep [-emacs|-vi] clang

The option indicates which flavor of key bindings you want to use for
editing the history.  As you would expect, "fep sh" gives you a Korn
shell emulation, of sorts.

Conclusions:
1. It Can Be Done.
2. The clang doesn't have to know about the ish.

--
Have a nice day,

Hans Mulder	hansm@cs.kun.nl

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

|Sorry for injection some facts into an otherwise useful theoretical
|discussion, but in 1987 (according to the copyright notice) Kazumasa
|Utashiro of Software Research Associates, Inc. wrote a nice "ish"
|called "fep" (for Front End Processor).  It's invocation is
|
| [...]
|
|Conclusions:
|1. It Can Be Done.
|2. The clang doesn't have to know about the ish.

The problem is that ideally, there are some ish-y functions which
require information that the clang has.  Completion is an example.  In
an ish that wants to do file name completion, it must know clang's
current directory.  Most of the fep-like programs I've seen do this in
some really ugly manner.

IMHO, what is needed is a good widely portable ish with a well-defined
protocol so that cooperative clangs can work well with them.

I envision something like the following:  user starts "ish -emacs fsh".
Ish advertises a communications channel, and starts a friendly sh,
which notices the communications channel.  User types "cdb
pro<ESC><ESC>", and ish passes "cdb pro" down the communication
channel (probably with some other info).  Fsh completes to "cdb
program", gives it back to ish.  User hits return, and fsh starts the
cooperating debugger, which notices the communications channel.  User
types "break fun<ESC><ESC>", down the channel it goes, fsh isn't
listening because it's waiting for cdb, but cdb completes it to "break
function", and passes it back.

Obviously, there are other details, but that's basically what I'd like
to see.  So many projects, so little time...

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

In article  <1991May02.171036.23843@sco.COM> John R. MacMillan writes:
]
]I envision something like the following:  user starts "ish -emacs fsh".
]Ish advertises a communications channel, and starts a friendly sh,
]which notices the communications channel.  User types "cdb
]pro<ESC><ESC>", and ish passes "cdb pro" down the communication
]channel (probably with some other info).  Fsh completes to "cdb
]program", gives it back to ish...

That is more-or-less what I had in mind.  Taking completion as an
example: each ish-ready program has a set of named things.  The user
wants to be able to type part of the name followed by some signal that
means "complete the previous name".  However, there might be several
classes of name things, and you only want to complete within the
correct class.  For example in a clang, you want seperate completion
for commands, filenames, and environment variables.

Part of this can be communicated by command-line description such as

  <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"

Each ish-ready program would have such a specification plus a set of
commands, (in this case just "variable-completion") that print out a
list of possible completions.  This eliminates the need for a
communication channel.

Type "set TE<ESC><ESC>" at the prompt.  The ish gathers characters
until the control sequence.  Then it looks at the specification for
this command and finds that it must use the "variable-completion" to
find the completions of this name.  It sends the string

  variable-completion TE

to the stdin of the clang which responds with

  TERM
  TERMCAP
  (prompt)

on its stdout.  The ish doesn't display this output since it is
internal communication.  Rather the ish parses it and completes
the name as far as possible, extending the user's command line to

  set TERM

The nice thing about this is that "variable-completion" is a normal
command that anyone can type, it doesn't require any special
communication apparatus.

The ish has pathname completion built in, so for command and filename
completion it would only ask the clang for its exec-path or current
directory and do its own completion.  Type "ico<ESC><ESC>".  The ish
sends the command "echo $path" to the clang which responds with the
path.  Then the ish completes the command according to the path.

These command-line descriptions can be fixed files that the ish
accesses.  The only other information the ish needs is what command is
executing, and it can get that from startup messages.  I'm beginning
to think again that a special communication channel is not needed.  If
you can get by without one then you should, since the writer of
ish-ready application shouldn't have to worry about that sort of
thing.  Is there any sort of communication that couldn't be handled by
this scheme?
--
					David Gudeman
gudeman@cs.arizona.edu
noao!arizona!gudeman

flee@cs.psu.edu (Felix Lee) (05/05/91)

>  <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.

How about completing filenames with variables embedded: "$HOME/$a/a".

How about history completion: expand things like "!$" and "!vi".

How about glob completion: expand things like "*" and "f*".

A more serious problem: the shell isn't the only thing that
wants/needs completion.  gdb, for example, wants to do completion.

Teaching the front-end about all this gets ugly.

The simplest way to handle completion is to have a communication
channel between the front-end and the current interactive process.
(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?))
--
Felix Lee	flee@cs.psu.edu

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

|Teaching the front-end about all this gets ugly.

I agree.

|The simplest way to handle completion is to have a communication
|channel between the front-end and the current interactive process.
|(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?))

Again, agreed.  I think your two questions are interrelated.

If we use stdin/stdout as the communications medium, it's easy,
portable, and the current interactive process is the one that is
reading the other end.  Eg. ish starts sh, sh is current.  Sh starts
gdb, so is waiting, gdb is reading, so it is current.

The big drawbacks to this mechanism are that a non-cooperative program
may just happen to look like a cooperative one on stdout, and that the
communication is either visible to the user, or must be hidden by the
programs (and again, you could accidentally hide something that just
happened to look like communication).

If this method is not acceptable, some other IPC mechanism must be
used.  Sockets on BSDish systems, and one or two of the too-numerous
SysV IPC mechanisms would seem the obvious choices.  In this case, the
cooperating processes could negotiate who the current interactive one
is over the IPC mechanism (sh relinquishes its status when starting
gdb, and gdb asserts itself as the current interactive process).