(*----------------------------------------------------------------------*)

IMPLEMENTATION MODULE Movements;

(*----------------------------------------------------------------------*)

FROM Universe IMPORT BYTE, EndOfLineCh, TabCh, Debugging, DebugFlags;
FROM List IMPORT ListP, True, False, Self;
FROM Actions IMPORT BuiltInAction, BuiltInActionWithParams, Bind;
FROM Buffers IMPORT BufferP, AreaR, ScanMarkers, ScanAreaForMarkers,
		    MarkerP, MoveMarker, UnHoleMarker, MarkerAt;
IMPORT Windows, Fast, Screen, Errors, Commands, Buffers, List,
       DisplayPosition;
IMPORT Convert;

IMPORT Debug;

(*----------------------------------------------------------------------*)

PROCEDURE NumberRequired( Arg : ListP ) : CARDINAL ;

   BEGIN
      IF Arg = NIL THEN RETURN 1 END;
      RETURN List.NumberOfList (List.Head (Arg))
   END NumberRequired;

(*----------------------------------------------------------------------*)

PROCEDURE RepositionAt( Buffer : BufferP ; Position : CARDINAL ) ;
VAR
   AreaLength			   : CARDINAL ;
   Area 			   : AreaR ;
BEGIN
   WITH Buffer^ DO
      IF Position > After.End THEN
	 Jump( Buffer , After.End ) ; (* Indent() is a bit stupid *)
	 RETURN ;
      END (* if *) ;
      IF Position >= After.Start THEN
	 Area.Start := After.Start ;
	 Area.End := Position ;
	 ScanAreaForMarkers( Buffer ,
			     Area ,
			     UnHoleMarker , -1 ) ;
	 AreaLength := Area.End - Area.Start ;
	 Fast.Move( Array ,
		    AreaLength ,
		    Area.Start ,
		    Before.End ) ;
	 INC( Before.End , AreaLength ) ;
	 INC( After.Start , AreaLength ) ;
      ELSE
	 Area.Start := Position ;
	 Area.End := Before.End ;
	 ScanAreaForMarkers( Buffer ,
			     Area ,
			     UnHoleMarker , +1 ) ;
	 AreaLength := Area.End - Area.Start ;
	 Fast.Move( Array ,
		    AreaLength ,
		    Area.Start ,
		    After.Start - AreaLength ) ;
	 DEC( After.Start , AreaLength ) ;
	 DEC( Before.End , AreaLength ) ;
      END (* if *) ;
   END (* with *) ;
END RepositionAt ;

(*----------------------------------------------------------------------*)

PROCEDURE Jump( Buffer : BufferP ; Position : CARDINAL ) ;
VAR
   Window			: Windows.WindowP ;
BEGIN
   Window := Windows.Find( Buffer^.Window ) ;
   IF Window = NIL THEN
      Errors.Panic( "Movements.Jump : Buffer window NIL" ) ;
   ELSE
      RepositionAt( Buffer , Position ) ;
      DisplayPosition.SetInvalidColumn( Window ) ;
   END (* if *) ;
END Jump ;

(*----------------------------------------------------------------------*)

PROCEDURE ForceOnText ;
BEGIN
   WITH Windows.Selected^ DO
      WITH Buffer^ DO
	 IF NOT Cursor.OnText THEN
	    IF Array.Data^[ After.Start ] = EndOfLineCh THEN
	       WHILE Cursor.PartialColumn > 0 DO
		  IF Before.End < After.Start THEN
		     Array.Data^[ Before.End ] := BYTE( ' ' ) ;
		     INC( Before.End ) ;
		  END (* if *) ;
		  DEC( Cursor.PartialColumn ) ;
	       END (* while *) ;
	    ELSE
	       Jump( Buffer , After.Start ) ;
	    END (* if *) ;   
	    Cursor.OnText := TRUE ;
	    Cursor.PartialColumn := 0 ;
	 END (* if *) ;   
      END (* with *) ;
   END (* with *) ;   
(* :* Looks as if this stops cursor moving after newline ...
   DisplayPosition.SetInvalidColumn( Windows.Selected ) ;
*: *)
END ForceOnText ;

(*----------------------------------------------------------------------*)

PROCEDURE JumpToLine (args: ListP): ListP;

   VAR
      activeWindow  : Windows.WindowP;
      res           : INTEGER;

   BEGIN
      activeWindow := Windows.Selected;

      IF args = NIL THEN
      
         res := Commands.Interactive1 (activeWindow,
                                       Commands.NullInit,
                                       "Jump to line: ",
                                       NIL,
                                       Commands.NullAckn,
                                       JumpProc          );
         IF res >= 0 THEN RETURN True
         ELSE RETURN False
         END (* if *);

      ELSE

         Jump (activeWindow^.Buffer, NumberRequired (args));
         RETURN True;

      END (* if *);

   END JumpToLine;

PROCEDURE JumpProc (VAR activeWindow: Windows.WindowP; lineNumber: ARRAY OF CHAR): INTEGER;

   (*-------------------------------------------------------------------*)

   PROCEDURE FindLine (TargetLineNumber: CARDINAL): CARDINAL;

      VAR
         Index			    : CARDINAL ;
         LineNumber		    : CARDINAL ;

      (*----------------------------------------------------------------*)

      PROCEDURE TargetLineWithin (Start, End: CARDINAL): BOOLEAN;

         BEGIN
	    Index := Start;
	    WITH activeWindow^.Buffer^.Array DO
	       WHILE Index < End DO
	          IF Data^ [Index] = EndOfLineCh THEN
 		     INC (LineNumber);
		     IF LineNumber >= TargetLineNumber THEN
		        RETURN TRUE;
		     END (* if *);
	          END (* if *);
	          INC (Index);
	       END (* while *);
	    END (* with *);
	    RETURN FALSE;
         END TargetLineWithin;

   (*-------------------------------------------------------------------*)

      BEGIN
         WITH activeWindow^.Buffer^ DO
   	    LineNumber := 1;
	    IF LineNumber >= TargetLineNumber THEN
	       RETURN Before.Start;
	    END (* if *);
	    IF TargetLineWithin (Before.Start, Before.End) OR TargetLineWithin (After.Start, After.End) THEN
	       RETURN Index + 1;
	    ELSE
	       RETURN After.End;
	    END (* if *);
         END (* with *);
      END FindLine;

   (*-------------------------------------------------------------------*)

   VAR
      res   : INTEGER;
      line  : CARDINAL;

   BEGIN
      res := Convert.StringToCardinal (line, lineNumber) ;
      IF res < 0 THEN
         Errors.Report (res);
         RETURN -1
      ELSE
         Jump (activeWindow^.Buffer, FindLine (line));
         RETURN 0
      END (* if *);
   END JumpProc;

(*----------------------------------------------------------------------*)

PROCEDURE ScrollWindowBy( DeltaX , DeltaY : INTEGER ) ;
BEGIN
   WITH Windows.Selected^ DO
      WHILE DeltaX > 0 DO
	 IF Edge.Right < Screen.LastColumn THEN
	    INC( Edge.Right ) ;
	    INC( Margins.Real.Right ) ;
	 ELSE
	    INC( EdgeDisplacement.Right ) ;
	 END (* if *) ;
	 IF ( EdgeDisplacement.Left = 0 ) AND
	    ( Edge.Left < Screen.LastColumn ) THEN
	    INC( Edge.Left ) ;
	    INC( Margins.Real.Left ) ;
	    INC( Indentation ) ;
	 ELSE
	    INC( EdgeDisplacement.Left ) ;
	 END (* if *) ;
	 DEC( DeltaX ) ;
      END (* while *) ;
      WHILE DeltaX < 0 DO
	 IF Edge.Left > 0 THEN
	    DEC( Edge.Left ) ;
	    DEC( Margins.Real.Left ) ;
	    IF Indentation > 0 THEN
	       DEC( Indentation ) ;
	    END (* if *) ;
	 ELSE
	    DEC( EdgeDisplacement.Left ) ;
	 END (* if *) ;
	 IF ( EdgeDisplacement.Right = 0 ) AND
	    ( Edge.Right > 0 ) THEN
	    DEC( Edge.Right ) ;
	    DEC( Margins.Real.Right ) ;
	 ELSE
	    DEC( EdgeDisplacement.Right ) ;
	 END (* if *) ;
	 INC( DeltaX ) ;
      END (* while *) ;
      WHILE DeltaY > 0 DO
	 IF Edge.Bottom < Screen.BottomRow THEN
	    INC( Edge.Bottom ) ;
	    INC( Margins.Real.Bottom ) ;
	 ELSE
	    INC( EdgeDisplacement.Bottom ) ;
	 END (* if *) ;
	 IF ( EdgeDisplacement.Top = 0 ) AND
	    ( Edge.Top < Screen.BottomRow ) THEN
	    INC( Edge.Top ) ;
	    INC( Margins.Real.Top ) ;
	    IF Cursor.Position.Y < Edge.Top THEN
	       INC( Cursor.Position.Y ) ;
	    END (* if *) ;
	 ELSE
	    INC( EdgeDisplacement.Top ) ;
	 END (* if *) ;
	 DEC( DeltaY ) ;
      END (* while *) ;
      WHILE DeltaY < 0 DO
	 IF Edge.Top > 0 THEN
	    DEC( Edge.Top ) ;
	    DEC( Margins.Real.Top ) ;
	 ELSE
	    DEC( EdgeDisplacement.Top ) ;
	 END (* if *) ;
	 IF ( EdgeDisplacement.Bottom = 0 ) AND
	    ( Edge.Bottom > 0 ) THEN
	    DEC( Edge.Bottom ) ;
	    DEC( Margins.Real.Bottom ) ;
	    IF Cursor.Position.Y > Edge.Bottom THEN
	       DEC( Cursor.Position.Y ) ;
	    END (* if *) ;
	 ELSE
	    DEC( EdgeDisplacement.Bottom ) ;
	 END (* if *) ;
	 INC( DeltaY ) ;
      END (* while *) ;
   END (* with *) ;
   Windows.Select( Windows.Selected , FALSE ) ;
END ScrollWindowBy ;

(*----------------------------------------------------------------------*)

PROCEDURE ScrollWindowLeft( Arg : ListP ) : ListP ;
BEGIN
   ScrollWindowBy( -INTEGER( NumberRequired( Arg ) ) , 0 ) ;
   RETURN True ;
END ScrollWindowLeft ;

(*----------------------------------------------------------------------*)

PROCEDURE ScrollWindowRight( Arg : ListP ) : ListP ;
BEGIN
   ScrollWindowBy( +INTEGER( NumberRequired( Arg ) ) , 0 ) ;
   RETURN True ;
END ScrollWindowRight ;

(*----------------------------------------------------------------------*)

PROCEDURE ScrollWindowUp( Arg : ListP ) : ListP ;
BEGIN
   ScrollWindowBy( 0 , -INTEGER( NumberRequired( Arg ) ) ) ;
   RETURN True ;
END ScrollWindowUp ;

(*----------------------------------------------------------------------*)

PROCEDURE ScrollWindowDown( Arg : ListP ) : ListP ;
BEGIN
   ScrollWindowBy( 0 , +INTEGER( NumberRequired( Arg ) ) ) ;
   RETURN True ;
END ScrollWindowDown ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveToEndOfBuffer( Arg : ListP ) : ListP ;
VAR
   AfterLength		     : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      Cursor.Position.Y := Edge.Bottom ;
      Jump( Buffer , Buffer^.After.End ) ;
   END (* with *) ;
   RETURN True ;
END MoveToEndOfBuffer ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveToStartOfBuffer( Arg : ListP ) : ListP ;
VAR
   BeforeLength 	     : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      Jump( Buffer , Buffer^.Before.Start ) ;
   END (* with *) ;
   RETURN True ;
END MoveToStartOfBuffer ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveLeft (Arg: ListP): ListP;

   VAR
      Marker		      : MarkerP ;
      MovedCh		      : BYTE ;
      Count		      : CARDINAL ;

   BEGIN
      FOR Count := 1 TO NumberRequired (Arg) DO
         Marker := NIL ;
         WITH Windows.Selected^ DO
   	    WITH Buffer^ DO
	       IF Cursor.OnText THEN
	          IF Before.End > Before.Start THEN
		     DEC (Before.End);
		     DEC (After.Start);
		     MovedCh := Array.Data^ [Before.End];
		     Array.Data^ [After.Start] := MovedCh ;
		     WHILE MarkerAt (Buffer, Before.End, Marker) DO
		        UnHoleMarker (Marker, +1)
		     END (* while *);
		     IF MovedCh = EndOfLineCh THEN
		        DisplayPosition.SetInvalidColumn (Windows.Selected)
                     ELSIF MovedCh = TabCh THEN
		        DisplayPosition.SetInvalidColumn (Windows.Selected)
		     ELSE
		        DisplayPosition.Move (-INTEGER (WidthDisplayCh (
                                                         MovedCh,
                                                         Cursor.Column,
                                                         After.Start
                                                         )
                                                        ), 0);
		     END (* if *)
	          END (* if *)
	       ELSE
	          IF Array.Data^ [After.Start] = EndOfLineCh THEN
		     DisplayPosition.Move (-1, 0)
	          ELSE
		     ForceOnText
	          END (* if *)
	       END (* if *)
	    END (* with *)
         END (* with *)
      END (* for *);
      RETURN True
   END MoveLeft;

(*----------------------------------------------------------------------*)

PROCEDURE MoveRight( Arg : ListP ) : ListP ;
VAR
   MovedCh			     : BYTE ;
   Marker			     : MarkerP ;
   Count			     : CARDINAL ;
BEGIN
   FOR Count := 1 TO NumberRequired( Arg ) DO
      Marker := NIL ;
      WITH Windows.Selected^ DO
	 WITH Buffer^ DO
	    IF After.Start < After.End THEN
	       IF Array.Data^[ After.Start ] = EndOfLineCh THEN
		  Cursor.OnText := FALSE ;
		  DisplayPosition.Move( +1 , 0 ) ;
	       ELSE
		  IF NOT Cursor.OnText THEN
		     ForceOnText ;
		  END (* if *) ;
		  WHILE MarkerAt( Buffer , After.Start , Marker ) DO
		     UnHoleMarker( Marker , -1 ) ;
		  END (* while *) ;
		  MovedCh := Array.Data^[ After.Start ] ;
		  Array.Data^[ Before.End ] := MovedCh ;
		  INC( Before.End ) ;
		  INC( After.Start ) ;
		  DisplayPosition.Move( WidthDisplayCh( MovedCh ,
							Cursor.Column ,
							Before.End - 1 ) , 0 ) ;
	       END (* if *) ;
	    END (* if *) ;
	 END (* with *) ;
      END (* with *) ;
   END (* for *) ;
   RETURN True ;
END MoveRight ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveLineUp( Arg : ListP ) : ListP ;
VAR
   Segment		       : Windows.DisplaySegmentR ;
   Count		       : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      IF NOT ( Windows.DisplayCursorValidF IN Status ) THEN
	 DisplayPosition.FindCursorPosition( Windows.Selected ) ;
      END (* if *) ;
      FOR Count := 1 TO NumberRequired( Arg ) DO

(* Bugfix *)

         IF Cursor.Position.Y = Edge.Top THEN
            INC (Cursor.Position.Y);
            DisplayPosition.SetInvalidRows (Windows.Selected);
  	    DisplayPosition.FindCursorPosition( Windows.Selected ) ;
         END (* if *);

	 IF Cursor.Position.Y > Edge.Top THEN
	    DisplayPosition.ValidateRow( Windows.Selected ,
					 Cursor.Position.Y - 1 ) ;
	    Segment := DisplayAreas[ Cursor.Position.Y - 1 ] ;
	    IF Cursor.Column > Indentation THEN
	       DisplayPosition.Indent( Segment ,
				       Cursor.Column - Indentation ,
				       Indentation ) ;
	       IF Segment.Pending.CountValid THEN
		  Cursor.OnText := FALSE ;
		  Cursor.PartialColumn := Segment.Pending.WidePartialCount ;
	       ELSE
		  Cursor.OnText := TRUE ;
		  Cursor.PartialColumn := 0 ;
	       END (* if *) ;
	    END (* if *) ;
	    DisplayPosition.Move( 0 , -1 ) ;
	    RepositionAt( Buffer , Segment.Area.Start ) ;
	 END (* if *) ;
      END (* for *) ;
   END (* with *) ;
   RETURN True ;
END MoveLineUp ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveLineDown( Arg : ListP ) : ListP ;
VAR
   Segment		       : Windows.DisplaySegmentR ;
   Count		       : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      FOR Count := 1 TO NumberRequired( Arg ) DO
	 Segment.Area := Buffer^.After ;
	 Segment.Pending.Fold := FALSE ;
	 Segment.Pending.CountValid := FALSE ;
	 Segment.Valid := TRUE ;
	 IF Fast.SkipUntilEndOfLineCh( Buffer^.Array , Segment.Area ) THEN
	    INC( Segment.Area.Start ) ;
	    IF NOT ( Windows.DisplayCursorValidF IN Status ) THEN
	       DisplayPosition.FindCursorPosition( Windows.Selected ) ;
	    END (* if *) ;
	    DisplayPosition.Indent( Segment , Cursor.Column , 0 ) ;
	    IF Segment.Pending.CountValid THEN

(* :*
IF DebugDisplayF IN Debugging THEN
Debug.WriteS( "MoveLineDown : CountValid*N" ) ;
END (* debugging *) ;
*: *)

	       Cursor.OnText := FALSE ;
	       Cursor.PartialColumn := Segment.Pending.WidePartialCount ;
	    ELSE
	       Cursor.OnText := TRUE ;
	       Cursor.PartialColumn := 0 ;
	    END (* if *) ;
	    RepositionAt( Buffer , Segment.Area.Start ) ;
	 ELSE
	    Jump( Buffer , Buffer^.After.End ) ;
	 END (* if *) ;
	 DisplayPosition.Move( 0 , +1 ) ;
      END (* for *) ;
   END (* with *) ;
   RETURN True ;
END MoveLineDown ;

(*----------------------------------------------------------------------*)

PROCEDURE MovePageUp( Arg : ListP ) : ListP ;
VAR
   Segment		       : Windows.DisplaySegmentR ;
   Line 		       : CARDINAL ;
   ScreenSize		       : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      ScreenSize := Margins.Real.Bottom - Margins.Real.Top ;
      IF ScreenSize < 1 THEN
	 ScreenSize := 1 ;
      END (* if *) ;
      Segment.Area := Buffer^.Before ;
      Segment.Pending.Fold := FALSE ;
      Segment.Pending.CountValid := FALSE ;
      Segment.Valid := TRUE ;
      FOR Line := 1 TO ScreenSize DO
	 IF Fast.BackUntilEndOfLineCh( Buffer^.Array , Segment.Area ) THEN
	    DEC( Segment.Area.End ) ;
(*
	 ELSE
	    (* If we cant move a complete page, dont move at all *)
	    RETURN False ;
*)
	 END (* if *) ;
      END (* for *) ;

      (* Have found end of target line, now find start of it, and indent
      cursor to correct place *)

      IF Fast.BackUntilEndOfLineCh (Buffer^.Array, Segment.Area) THEN END;
      Segment.Area.Start := Segment.Area.End;
      Segment.Area.End := Buffer^.Before.End;

      IF NOT ( Windows.DisplayCursorValidF IN Status ) THEN
	 DisplayPosition.FindCursorPosition( Windows.Selected ) ;
      END (* if *) ;
      DisplayPosition.Indent( Segment , Cursor.Column , 0 ) ;
      IF Segment.Pending.CountValid THEN

(* :*
IF DebugDisplayF IN Debugging THEN
Debug.WriteS( "MovePageUp : CountValid*N" ) ;
END (* debugging *) ;
*: *)

	 Cursor.OnText := FALSE ;
	 Cursor.PartialColumn := Segment.Pending.WidePartialCount ;
      ELSE
	 Cursor.OnText := TRUE ;
	 Cursor.PartialColumn := 0 ;
      END (* if *) ;
      RepositionAt( Buffer , Segment.Area.Start ) ;
   END (* with *) ;
   DisplayPosition.SetInvalidRows( Windows.Selected ) ;
   RETURN True ;
END MovePageUp ;

(*----------------------------------------------------------------------*)

PROCEDURE MovePageDown( Arg : ListP ) : ListP ;
VAR
   Segment		       : Windows.DisplaySegmentR ;
   Line 		       : CARDINAL ;
   ScreenSize		       : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      ScreenSize := Margins.Real.Bottom - Margins.Real.Top ;
      IF ScreenSize < 1 THEN
	 ScreenSize := 1 ;
      END (* if *) ;
      Segment.Area := Buffer^.After ;
      Segment.Pending.Fold := FALSE ;
      Segment.Pending.CountValid := FALSE ;
      Segment.Valid := TRUE ;
      FOR Line := 1 TO ScreenSize DO
	 IF Fast.SkipUntilEndOfLineCh( Buffer^.Array , Segment.Area ) THEN
	    INC( Segment.Area.Start ) ;
(*
	 ELSE
	    (* If we cant move a complete page, dont move at all *)
	    RETURN False ;
*)
	 END (* if *) ;
      END (* for *) ;
      IF NOT ( Windows.DisplayCursorValidF IN Status ) THEN
	 DisplayPosition.FindCursorPosition( Windows.Selected ) ;
      END (* if *) ;
      DisplayPosition.Indent( Segment , Cursor.Column , 0 ) ;
      IF Segment.Pending.CountValid THEN

(* :*
IF DebugDisplayF IN Debugging THEN
Debug.WriteS( "MovePageDown : CountValid*N" ) ;
END (* debugging *) ;
*: *)

	 Cursor.OnText := FALSE ;
	 Cursor.PartialColumn := Segment.Pending.WidePartialCount ;
      ELSE
	 Cursor.OnText := TRUE ;
	 Cursor.PartialColumn := 0 ;
      END (* if *) ;
      RepositionAt( Buffer , Segment.Area.Start ) ;
   END (* with *) ;
   DisplayPosition.SetInvalidRows( Windows.Selected ) ;
   RETURN True ;
END MovePageDown ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveStartOfLine( Arg : ListP ) : ListP ;
VAR
   Area 			     : Buffers.AreaR ;
BEGIN
   WITH Windows.Selected^ DO
      Area.Start := Buffer^.Before.Start ;
      Area.End := Buffer^.Before.End ;
      IF Fast.BackUntilEndOfLineCh( Buffer^.Array , Area ) THEN
      END (* if *) ;
      Jump( Buffer , Area.End ) ;
   END (* with *) ;
   RETURN True ;
END MoveStartOfLine ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveEndOfLine( Arg : ListP ) : ListP ;
VAR
   Area 			     : Buffers.AreaR ;
BEGIN
   WITH Windows.Selected^ DO
      Area := Buffer^.After ;
      IF Fast.SkipUntilEndOfLineCh( Buffer^.Array , Area ) THEN
      END (* if *) ;
      Jump( Buffer , Area.Start ) ;
   END (* with *) ;
   RETURN True ;
END MoveEndOfLine ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveToNextLine( Arg : ListP ) : ListP ;
VAR
   Area 			     : Buffers.AreaR ;
BEGIN
   WITH Windows.Selected^ DO
      Area := Buffer^.After ;
      IF Fast.SkipUntilEndOfLineCh( Buffer^.Array , Area ) THEN
	 INC( Area.Start ) ;
      END (* if *) ;
      Jump( Buffer , Area.Start ) ;
      DisplayPosition.Move( 0 , +1 ) ;
   END (* with *) ;
   RETURN True ;
END MoveToNextLine;

(*----------------------------------------------------------------------*)

PROCEDURE MoveBufferLeft( Arg : ListP ) : ListP ;
VAR
   Count		  : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      FOR Count := 1 TO NumberRequired( Arg ) DO
	 IF Indentation > 0 THEN
	    DEC( Indentation ) ;
	 END (* if *) ;
      END (* for *) ;
   END (* with *) ;
   DisplayPosition.SetInvalidColumn (Windows.Selected);
   RETURN True ;
END MoveBufferLeft ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveBufferRight( Arg : ListP ) : ListP ;
VAR
   Count		  : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      FOR Count := 1 TO NumberRequired( Arg ) DO
(* why guard ?? - was > 0 *)
	 IF Indentation >= 0 THEN
	    INC( Indentation ) ;
	 END (* if *) ;
      END (* for *) ;
   END (* with *) ;
   DisplayPosition.SetInvalidColumn (Windows.Selected);
   RETURN True ;
END MoveBufferRight ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveBufferUp( Arg : ListP ) : ListP ;
VAR
   Count		  : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      FOR Count := 1 TO NumberRequired( Arg ) DO
	 IF Cursor.Position.Y < Edge.Bottom THEN
	    INC( Cursor.Position.Y ) ;
	 END (* if *) ;
      END (* for *) ;
   END (* with *) ;
   DisplayPosition.SetInvalidRows (Windows.Selected);
   RETURN True ;
END MoveBufferUp ;

(*----------------------------------------------------------------------*)

PROCEDURE MoveBufferDown( Arg : ListP ) : ListP ;
VAR
   Count		  : CARDINAL ;
BEGIN
   WITH Windows.Selected^ DO
      FOR Count := 1 TO NumberRequired( Arg ) DO
	 IF Cursor.Position.Y > Edge.Top THEN
	    DEC( Cursor.Position.Y ) ;
	 END (* if *) ;
      END (* for *) ;
   END (* with *) ;
   DisplayPosition.SetInvalidRows (Windows.Selected);
   RETURN True ;
END MoveBufferDown ;

(*----------------------------------------------------------------------*)

PROCEDURE JumpToMark (args: ListP): ListP;

   VAR
      activeWindow  : Windows.WindowP;
      index         : CARDINAL;
      marker        : Buffers.MarkerP;
      buffer        : Buffers.BufferP;
      window        : Windows.WindowP;

   BEGIN
      activeWindow := Windows.Selected;
      FOR index := 1 TO Buffers.EditMarkersCount () DO
         marker := Buffers.EditMarkers [index];
         buffer := marker^.Buffer;
         window := Windows.Find (buffer^.Window);
         IF (buffer # activeWindow^.Buffer) OR (marker^.Where # activeWindow^.Buffer^.After.Start) THEN
            IF window # activeWindow THEN
               Windows.Select (window, TRUE);
               Buffers.Select (buffer);
            END (* if *);
            Jump (buffer, marker^.Where);
            RETURN True
         END (* if *);
      END (* for *);
      RETURN False;
   END JumpToMark;

(*----------------------------------------------------------------------*)

PROCEDURE Initialise;

   VAR
      buffHorizontalCount  : List.ListP;
      buffVerticalCount    : List.ListP;

   BEGIN
      BuiltInActionWithParams ("Left", MoveLeft, "Cursor Left", "Count");
      BuiltInActionWithParams ("Right", MoveRight, "Cursor Right", "Count");
      BuiltInActionWithParams ("DownLine", MoveLineDown, "Move Down a Line", "Count");
      BuiltInActionWithParams ("UpLine", MoveLineUp, "Move Up a Line", "Count");

      BuiltInAction ("DownPage", MovePageDown, "Move Down a Screen");
      BuiltInAction ("UpPage", MovePageUp, "Move Up a Screen");
      BuiltInAction ("ToEnd", MoveToEndOfBuffer, "Move to buffer End");
      BuiltInAction ("ToStart", MoveToStartOfBuffer, "Move to buffer Start");

      BuiltInAction ("StartLin", MoveStartOfLine, "Move to Start of line");
      BuiltInAction ("EndLine", MoveEndOfLine, "Move to End of line");

      BuiltInAction ("NextLine", MoveToNextLine, "Move to next line");

      BuiltInActionWithParams ("WinLeft", ScrollWindowLeft, "Scroll Window Left", "Count");
      BuiltInActionWithParams ("WinRight", ScrollWindowRight, "Scroll Window Right", "Count");
      BuiltInActionWithParams ("WinUp", ScrollWindowUp, "Scroll Window Up", "Count");
      BuiltInActionWithParams ("WinDown", ScrollWindowDown, "Scroll Window Down", "Count");

      BuiltInActionWithParams ("BufLeft", MoveBufferLeft, "Buffer Left", "Count");
      BuiltInActionWithParams ("BufRight", MoveBufferRight, "Buffer Right", "Count");
      BuiltInActionWithParams ("BufUp", MoveBufferUp, "Buffer Up", "Count");
      BuiltInActionWithParams ("BufDown", MoveBufferDown , "Buffer Down", "Count");

      BuiltInActionWithParams ("JumpLine", JumpToLine, "Jump to Line", "Line");

      BuiltInAction ("JumpMark", JumpToMark, "Jump to Mark");

      Bind (BYTE(08CH), "Left", NIL);
      Bind (BYTE(08DH), "Right", NIL);
      Bind (BYTE(08EH), "DownLine", NIL);
      Bind (BYTE(08FH), "UpLine", NIL);

      Bind (BYTE(09EH), "DownPage", NIL);
      Bind (BYTE(09FH), "UpPage", NIL);
      Bind (BYTE(0AEH), "ToEnd", NIL);
      Bind (BYTE(0AFH), "ToStart", NIL);

      Bind (BYTE(0ACH), "StartLin", NIL);
      Bind (BYTE(0ADH), "EndLine", NIL);
(*
      Bind (BYTE(0C1H), "NextLine", NIL);
*)
      buffHorizontalCount := List.Cons (List.MakeAtom (20, List.NumberT), NIL);

      Bind (BYTE (0BCH), "BufLeft", buffHorizontalCount);
      Bind (BYTE (0BDH), "BufRight", buffHorizontalCount);

      buffVerticalCount := List.Cons (List.MakeAtom (5, List.NumberT), NIL);

      Bind (BYTE (0BFH), "BufUp", buffVerticalCount);
      Bind (BYTE (0BEH), "BufDown", buffVerticalCount);

      Bind (BYTE (090H), "JumpLine", NIL);
      Bind (BYTE (0A0H), "JumpMark", NIL);

   END Initialise;

(*----------------------------------------------------------------------*)

PROCEDURE Terminate;

   BEGIN
   END Terminate;

(*----------------------------------------------------------------------*)

END Movements.

