
% Editor for TOY Prolog
% (c) 1983 Kluzniak/Szpakowicz, IIUW Warszawa

edit( Name/Arity ) :- not ( atom( Name ), integer( Arity ) ), !,
      write( 'Bad parameters : ' ),
      write( edit( Name/Arity ) ), nl, fail.
edit( Name/Arity ) :- predefined( Name, Arity ), !,
      write( 'Can''t edit system routine : ' ),
      write( Name/Arity ), nl, fail.
edit( NameArity ) :- tag( ed( NameArity, 0 ) ).

ed( NameArity, Cursor ) :- show( NameArity, Cursor ), !,
      docmd( NameArity, Cursor, NewCursor ),
      ed( NameArity, NewCursor ).
ed( NameArity, Cursor ) :- display( 'Cursor out of range : ' ),
      display( Cursor ), nl, ed( NameArity, 0 ).

docmd( NameArity, Cursor, NewCursor ) :-
      repeat,
         getline( Line ), cmd( Line, NameArity, Cursor, NewCursor ),
      !.

getline( [] ) :- rch, lastch( C ), iseoln( C ), !.
getline( [C | L] ) :- lastch( C ), getline( L ).

cmd( [], NmAr, Cur, NCur ) :- next_cursor( NmAr, Cur, NCur ).
cmd( ['+'], NmAr, Cur, NCur ) :- next_cursor( NmAr, Cur, NCur ).
cmd( ['-'], _, Cur, NCur ) :- prev_cursor( Cur, NCur ).
cmd( [t], NmAr, _, 0 ).
cmd( [b], NmAr, Cur, NCur ) :- bottom_cursor( NmAr, Cur, NCur ).
cmd( [l], NmAr, Cur, Cur ) :- listing( NmAr ).
cmd( [d], NmAr, Cur, NCur ) :- delete( NmAr, Cur, NCur ).
cmd( [i], NmAr, Cur, NCur ) :- insert( NmAr, Cur, NCur ).
cmd( [f, ' ' | NameString], NmAr, Cur, NCur ) :-
      file_insert( NameString, NmAr, Cur, NCur ).
cmd( [e, ' ' | Args], NmAr, Cur, NCur ) :-
      append( NameString, ['/' | ArityString], Args ),
      call_edit( NameString, ArityString ).
cmd( [x], _, _, _ ) :- tagexit( ed( _, _ ) ).
cmd( [p], NmAr, Cur, Cur ) :- invoke_Prolog.
cmd( String, _, _, _ ) :- display( '--- incorrect command : ' ),
      writetext( String ), nl, fail.

next_cursor( Name/Arity, Cursor, Next ) :-
      Next is Cursor + 1, check( clause( Name, Arity, Next, _, _ ) ), !.
next_cursor( _, Cursor, Cursor ).

prev_cursor( 0, 0 ).
prev_cursor( Cursor, Prev ) :- Cursor > 0, Prev is Cursor - 1.

bottom_cursor( Name/Arity, Cursor, Bottom ) :-
      Next is Cursor + 1, check( clause( Name, Arity, Next, _, _ ) ), !,
      bottom_cursor( Name/Arity, Next, Bottom ).
bottom_cursor( _, Cursor, Cursor ).

delete( _, 0, 0 ) :- !, display( 'Can''t delete clause 0' ), nl.
delete( Name/Arity, Cursor, NewCursor ) :-
      retract( Name, Arity, Cursor ),
      cursor_in_range( Name, Arity, Cursor, NewCursor ).

cursor_in_range( Nm, Ar, Cur, Cur ) :- check( clause( Nm, Ar, Cur, _, _ ) ), !.
cursor_in_range( _, _, Cur, Prev ) :- Prev is Cur - 1.

insert( NameArity, Cursor, NewCursor ) :-
      repeat,
         read( Clause ), convert( Clause, Head, Body ),
         accept( Head, NameArity, Clause ),
      !,
      end_or_proceed( Head, Body, NameArity, Cursor, NewCursor ).

end_or_proceed( end, [], _, Cursor, Cursor ) :- !.
end_or_proceed( Head, Body, NameArity, Cursor, NewCursor ) :-
      Next is Cursor + 1, assert( Head, Body, Cursor ),
      insert( NameArity, Next, NewCursor ).

accept( _, _, end ).
accept( Head, Name/Arity, _ ) :- functor( Head, Name, Arity ).
accept( _, _, Clause ) :-
      display( '--- clause not in edited procedure - ignored' ),
      nl, write( Clause ), fail.

file_insert( FNameString, NameArity, Cursor, NewCursor ) :-
      pname( FileName, FNameString ),
      see( FileName ), insert( NameArity, Cursor, NewCursor ),
      seen, see( user ).

call_edit( NameString, ArityString ) :-
      pname( Name, NameString ), pnamei( Arity, ArityString ),
      edit( Name/Arity ).

invoke_Prolog :- tag( loop ).
invoke_Prolog.

show( NameArity, 0 ) :- !, write( '[0] ( ' ), write( NameArity ),
      write( ' )' ), nl.
show( Name/Arity, Cursor ) :-
      side_effects(  ( clause( Name, Arity, Cursor, Head, Body ),
                     conv_body( NiceBody, Body ),
                     display( '[' ), display( Cursor ), display( '] ' ),
                     writeclause( Head, NiceBody ),
                     display( '.' ), nl )  ).

append( [], L, L ).
append( [E | L], L2, [E | LL2] ) :- append( L, L2, LL2 ).

end.

