%   Hacked for the apm, FDC, 4.6.85

%   File   : /usr/lib/prolog/edit
%   Author : Lawrence Byrd, Peter Ross, and Richard A. O'Keefe.
%   Updated: Friday May 26th, 1984
%   Purpose: Definitions of some useful commands for use
%	     when editing files from within Prolog.
/*
    These commands use the Prolog evaluable predicate  shell/1  to  call
    various  UNIX commands.  Thus you can "more" files or edit them just
    by calling a Prolog predicate.  These UNIX commands run as  separate
    processes,  and  Prolog  waits for them to finish.  So the effect is
    just like a procedure call.  When they finish you  are  returned  to
    Prolog.   Since  the shell/1 predicate FAILS if the UNIX command you
    invoke with it returns a non-zero status, so do these commands fail.
    If for example you get out of "top" with ^C, the edit  command  will
    fail.  This is used to avoid reconsulting a file when you decide not
    to change it after all.

    All of the commands which take a single argument have  been  defined
    as  prefix operators.  This means that Prolog can accept commands in
    a format resembling UNIX commands.  For example,  "more changes"  is
    alternative syntax for  "more(changes)".  But you mustn't forget the
    full stop which has to end EVERY input to Prolog.  Don't forget that
    the file name is a Prolog atom, so that if it has a solidus (/) or a
    full stop (.) in it you will have to quote it.   For example, saying
    "edit fred.pl." won't work.  You have to quote the file name, saying
    "edit 'fred.pl'.".

    The following commands are provided.

	l Predicate.		Same as listing(Predicate) only shorter.
	l.			Same as listing only shorter.

	r Key.			List everything recorded under Key.
	r.			List the entire recorded data base.

	cd Directory.		Make Directory the current directory.
	cd.			cd to your login directory.

	ls Directory.		List Directory using "ls -lf".
	ls.			List the current directory using "ls -lf".

	sh Command.		Execute the Unix command Command.
	sh.			Start up an subordinate shell.

	more File.		Display the File on your terminal
				using the "more" program.
	more.			Display the last mentioned file using "more".

	edit File.		Edit the File using $EDITOR.
	edit.			Edit the last file mentioned.

	redo File.		Edit the File using $EDITOR,
				then reconsult the File.
	redo.			Redo the last file mentioned.

	wc File.		Find out how big File is using "wc".

	con File.		Consult the File.
	con.			Consult the last file mentioned.

	rec File.		Reconsult the File.
	rec.			Reconsult the last file mentioned.

    The commands "more File", "edit File", "redo File", "con File", and
    "rec File" all "notice" the File name.  In other words, they record
    the file name so that you can give other commands pertaining to the
    same file without repeating the name.   This is the only real point
    in the "con" and "rec" commands; [File] does the same as con(File),
    and [-File] does the same as rec(File), *except* that the bracketed
    forms don't remember the file name.  If you say "con 'fred.pl', and
    that file turns out to have a syntax error, you can immediately say
    "redo" or "edit" if you prefer, without having to retype what might
    be a long file name.

    The shell/1 predicate expects a string as its argument.  cd/1 wants
    an atom.  These predicates are built into C Prolog so we can't make
    them act differently here.  But all the other one-argument commands
    will take either a string or an atom.  It would be possible to make
    them take terms using (/)/2 as well, but I haven't done that.

    The question arises, what editor should be used?  Fortunately, UNIX
    has a way of letting you specify things like this.   In the C shell
    (csh, newcsh, or tcsh) you say
	setenv EDITOR "the name of your favourite editor"
    In the standard (Bourne) shell (sh) you say
	export EDITOR; EDITOR="the name of your favourite editor"
    Most UNIX programs that offer an editor escape (such as the mailer)
    already look at this variable, so you have probably set it already.
    If you give an edit or redo command without this variable being set
    the default editor is /usr/local/emacs.

    Why emacs?  Once upon a time this package was based on VILE.  (It's
    been based on other editors in previous incarnations.)  But VILE is
    a memory hog, and isn't really practical on system as heavily over-
    loaded as ours.  If you don't give a damn about other users, you've
    only to "setenv EDITOR vi" in your .login or .profile.   Emacs is a
    fair bit smaller than VILE, and is also available under VMS.  There
    are similar editors on many different machines,  such as the Dec-10
    and the Perq.  You might like to try another editor called "top", a
    very much smaller (and faster) editor than emacs or VILE, but which
    resembles emacs, has commands useful for Prolog  (such as a command
    for checking a clause for syntax errors), and is given away free to
    C Prolog customers.  Emacs is a good all-round choice.

    The original idea of this collection was Lawrence Byrd's.  The code
    for C Prolog was done by Peter Ross, then rewritten by R.A.O'Keefe.
*/

:- op(600, fy, [		%   Has to be fy so can "edit edit".
	l, r,			%   list clauses, records
	cd, ls, sh,		%   UNIX commands
	more, edit, redo,
	con, rec, wc	]).


/*  Commands pertaining to the Prolog data base  */


l(Predicate) :-			%   List a predicate.
	listing(Predicate).


l :-				%   List the entire data base.
	listing.


r(Key) :-			%   List all terms recorded under a given key.
	'$functorspec'(Key, Name, Arity),
	functor(MGT, Name, Arity),
	recorded(MGT, Term, Ref),
	writeq(Name/Arity), write(' -> '),
	write(Ref), write(' = '),
	numbervars(Term, 0, _),
	print(Term), write(.), nl,
	fail ; true.



r :-				%  List the entire recorded data base.
	current_functor(_, MGT),
	r(MGT),
	fail ; true.



/*  UNIX commands which don't relate to single source files  */


%   cd(Directory) is built in and demands an ATOM for its argument.


cd :-				%   Change to the user's login directory.
	cd('~').


ls(Directory) :-		%   List the contents of a directory.
	atom(Directory), !,
	name(Directory, DirectoryString),
	'append colon'(DirectoryString, String),
	shell("f", String).
ls(Directory) :-
	'append colon'(Directory, String),
	shell("f", String).


ls :-				%   List the contents of the current directory.
	shell("f").


sh(Command) :-			%   Execute a shell command.  (sh/0 is built in.)
	atom(Command), !,
	name(Command, String),
	shell(String).
sh(Command) :-
	shell(Command).

cli :-
	shell("shell").


/*  UNIX or Prolog commands pertaining to a source file  */


%   Well written editors like emacs and top can remember for themselves 
%   what file you edited last.  Because VILE and ed cannot, and because
%   redo needs to know what file anyway, these commands rely on $notice
%   to keep track of the "last mentioned" file.   If the first of these
%   commands you give is 'edit',  the editor will be called without any
%   arguments.


more(File) :-			%   Display a file using "more".
	'$notice'(File),
	shell("t", File).


more :-				%   Display the last mentioned file.
	'$noticed'(more, File),
	shell("t", File).


edit(File) :-			%   Edit a new file.
	'$notice'(File),
	editor(Editor),
	shell(Editor, File).

edit :-				%   Edit the last mentioned file
	'$noticed'(File), !,	%   we have edited before
	editor(Editor),
	shell(Editor, File).	%   re-edit that file.
edit :-				%   no previous edit
	editor(Editor),
	shell(Editor).		%   call editor with no argument.


vi(File) :-			%   obsolete form for VILE
	write('Obsolete command.  Use edit with $EDITOR=vi'), nl,
	'$notice'(File),
	shell("vi", File).


redo(File) :-			%   Edit and reconsult a file.
	'$notice'(File),
	editor(Editor),
	shell(Editor, File),
	reconsult(File).

redo :-
	'$noticed'(redo, File),
	editor(Editor),
	shell(Editor, File),
	reconsult(File).


wc(File) :-			%   Get some idea of how big File is
	'$notice'(File),
	shell("wc", File).


con(File) :-			%   Consult a file and remember it.
	(  atom(File), F = File
	;  name(F, File)
	), !,
	'$notice'(F),
	consult(F).

con :-				%   Consult the last mentioned file.
	'$noticed'(con, File),
	consult(File).


rec(File) :-			%   Reconsult a file and remember it.
	(  atom(File), F = File
	;  name(F, File)
	), !,
	'$notice'(F),
	reconsult(F).

rec :-				%   Reconsult the last mentioned file.
	'$noticed'(rec, File),
	reconsult(File).


/*  Support routines for the user-oriented predicates above  */


'$notice'(File) :-		%   remember which file was last mentioned
	abolish('$noticed', 1),
	assert('$noticed'(File)).


'$noticed'(_, File) :-		%   Command wants to know what File
	'$noticed'(File), !.	%   was last mentioned, and will complain
'$noticed'(Command, _) :-	%   if there wasn't one, e.g.
	write(Command),		%   redo WhatFile?
	write(' WhatFile'),
	write(?), nl,
	fail.


%   We get the editor name from the environment variable $EDITOR.
%   If that isn't defined, we default to /usr/local/emacs.  If you
%   want a different editor, and don't want to set $EDITOR, or are
%   using an operating system where you can't, reconsult a Prolog
%   file which says editor("yaloe") or whatever.  Note that a string
%   is needed, not an atom.

/*
editor(String) :-
	expand_file_name('$EDITOR', Editor), !,
	name(Editor, String).
*/
editor("ie").



%   shell(Command, Argument) appends a space and the argument (or
%   the name of the argument) to the command and calls the result.

shell(Command, Argument) :-
	atom(Command), !,
	name(Command, CommandString),
	'finish command'(CommandString, Argument, String),
	shell(String).
shell(Command, Argument) :-
	'finish command'(Command, Argument, String),
	shell(String).

'finish command'([C|Cs], Argument, [C|Ss]) :- !,
	'finish command'(Cs, Argument, Ss).
'finish command'([], [A|As], [0' ,A|As]) :- !.
'finish command'([], Argument, [0' |Name]) :-
	name(Argument, Name).

'append colon'([C|Cs], [C|Ss]) :- !,
	'append colon'(Cs, Ss).
'append colon'([], [0':]) :- !.
