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

IMPLEMENTATION MODULE Help;

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

FROM Strings IMPORT EqualCC, CopyCC, LengthC, ConcatCC;
IMPORT IO, GlobalString, Command, TimeAndDate, File;

FROM Memory IMPORT ALLOCATE, DEALLOCATE;
FROM Universe IMPORT EndOfLineCh, BYTE, Editing, EscapeCh, HelpCh;
FROM List IMPORT True, False, Self;
IMPORT Display, Windows, Screen, Buffers, Actions, List, StringData,
       Errors, Execute, DisplayPosition, Fast;
FROM Characters IMPORT ArrowShaftChar, RightArrowHeadChar,
		       LeftArrowHeadChar, UpArrowLeftChar,
		       LeftBracket, RightBracket,
		       UpArrowRightChar, DownArrowLeftChar,
		       DownArrowRightChar;
IMPORT HelpKeys, HelpBuffers (* , HelpActions, HelpWindows *) ;

IMPORT Debug;

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

CONST
   Height       = 22;
   Width        = 78;

   ColumnWidth	= List.HelpTextSize + 1;

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

VAR
   HelpFile			 : CARDINAL;
   CurrentLevel 		 : CARDINAL;
   writeIndex                    : CARDINAL;
   ColumnCount			 : CARDINAL;
   StartColumn			 : CARDINAL;

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

PROCEDURE AddChar (Ch: BYTE);

   BEGIN
      IF HighLight THEN
         IF (BYTE (020H) <= Ch) AND (Ch <= BYTE (03FH)) THEN
            Ch := BYTE (CARDINAL (Ch) - 020H)
         ELSIF (BYTE (040H) <= Ch) AND (Ch <= BYTE (07FH)) THEN
            Ch := BYTE (CARDINAL (Ch) + 080H)
         END (* if *);
      END (* if *);

      WITH HelpWindow^.Buffer^ DO
         IF writeIndex < After.End THEN
 	    Array.Data^ [writeIndex] := Ch;
	    INC (writeIndex)
         END (* if *)
      END (* with *);

      IF Ch = EndOfLineCh THEN ColumnCount := 0
      ELSE INC (ColumnCount)
      END (* if *)

   END AddChar;

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

PROCEDURE ReplaceChar (Ch: BYTE);

   BEGIN
      WITH HelpWindow^.Buffer^ DO
         IF writeIndex > After.Start THEN
	    Array.Data^ [writeIndex - 1] := Ch
         END (* if *)
      END (* with *)
   END ReplaceChar;

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

PROCEDURE AddHex (Nibble: CARDINAL);

   BEGIN
      Nibble := Nibble MOD 16 ;
      IF Nibble > 9 THEN
         AddChar( BYTE( Nibble - 10 + CARDINAL( 'A' ) ) ) ;
      ELSE
         AddChar( BYTE( Nibble + CARDINAL( '0' ) ) ) ;
      END (* if *) ;
   END AddHex ;

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

PROCEDURE Add2Hex( Byte : CARDINAL ) ;

   BEGIN
      AddHex( Byte DIV 16 ) ;
      AddHex( Byte ) ;
   END Add2Hex ;

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

PROCEDURE AddText( Text : ARRAY OF CHAR ) ;

   VAR
      Index		     : CARDINAL ;
      Length		     : CARDINAL ;
   BEGIN
      StartColumn := ColumnCount ;
      Index := 0 ;
      Length := LengthC( Text ) ;
      WHILE Index < Length DO
         AddChar( BYTE( Text[ Index ] ) ) ;
         INC( Index ) ;
      END (* while *) ;
   END AddText ;

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

PROCEDURE AddNumber( Number : CARDINAL ) ;

   BEGIN
      IF Number > 9 THEN
         AddNumber( Number DIV 10 ) ;
      END (* if *) ;
      AddChar( BYTE( ( Number MOD 10 ) + ORD( '0' ) ) ) ;
   END AddNumber ;

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

PROCEDURE EmptyWindowBuffer (Window: Windows.WindowP);

   BEGIN
      WITH Window^.Buffer^ DO
         Before.Start := 0;
         Before.End := 0;
         After.Start := 0;
         After.End := Array.Size
      END (* with *);
      ColumnCount := 0;
      Changed := FALSE;
      WITH Window^.Cursor DO
         Position.X := Window^.Edge.Left;
         Position.Y := Window^.Edge.Top;
         Column := Window^.Edge.Left;
         PartialColumn := 0;
         OnText := TRUE
      END (* with *);
      INCL (Window^.Status, Windows.CursorXKnownF)
   END EmptyWindowBuffer;

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

PROCEDURE SensitiveBox( WantX , WantY , Level : CARDINAL ;
			Text : ARRAY OF CHAR ) ;
BEGIN
   WITH MenuPosition[ Level ] DO
      IF ( WantX = X )
      AND ( WantY = Y )
      AND ( NOT MenuPosition[ Level ].Virgin ) THEN
         ReplaceChar( BYTE( LeftBracket ) ) ;
	 HighLight := TRUE ;
      END (* if *) ;
      AddText( Text ) ;
      HighLight := FALSE ;
      IF ( WantX = X )
      AND ( WantY = Y )
      AND ( NOT MenuPosition[ Level ].Virgin ) THEN
         AddChar( BYTE( RightBracket ) ) ;
      ELSE
	 AddChar( BYTE( ' ' ) ) ;
      END (* if *) ;
   END (* with *) ;
END SensitiveBox ;

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

PROCEDURE SelectedSensitive( WantX , WantY , Level : CARDINAL ) : BOOLEAN ;

   BEGIN
      WITH MenuPosition [Level] DO
         RETURN (WantX = X) AND (WantY = Y) AND (NOT MenuPosition [Level].Virgin);
      END (* with *);
   END SelectedSensitive;

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

PROCEDURE NewLine ;

   BEGIN
      AddChar( EndOfLineCh ) ;
   END NewLine ;

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

PROCEDURE PadTo( Column : CARDINAL ) ;

   BEGIN
      WHILE ColumnCount < Column DO
         AddChar( BYTE( ' ' ) ) ;
      END (* while *) ;
   END PadTo ;

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

PROCEDURE PadToNextColumn ;

   BEGIN
      PadTo( StartColumn + ColumnWidth ) ;
   END PadToNextColumn ;

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

PROCEDURE AddComment( Text : ARRAY OF CHAR ) ;

   BEGIN
      AddText( Text ) ;
      PadTo( 30 ) ;
   END AddComment ;

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

PROCEDURE Header( RelativeY : CARDINAL ) ;
BEGIN
   CASE RelativeY OF
   0 :
      AddText( "Help Level = " ) ;
      AddNumber( HelpLevel ) ;
(*
      AddText( ", X=" ) ;
      AddNumber( MenuPosition[ HelpLevel ].X ) ;
      AddText( ", Y=" ) ;
      AddNumber( MenuPosition[ HelpLevel ].Y ) ;
*)
      PadTo( 29 ) ;
      AddText( "Select help topic with cursor keys : " ) ;
      WITH MenuPosition[ HelpLevel ] DO
	 IF Y < MaxY THEN
	    AddChar( BYTE( DownArrowLeftChar ) ) ;
	    AddChar( BYTE( DownArrowRightChar ) ) ;
	 ELSE
	    AddText( "  " ) ;
	 END (* if *) ;
	 AddChar( BYTE( ' ' ) ) ;
	 IF X < MaxX THEN
	    AddChar( BYTE( ArrowShaftChar ) ) ;
	    AddChar( BYTE( RightArrowHeadChar ) ) ;
	 ELSE
	    AddText( "  " ) ;
	 END (* if *) ;
	 AddChar( BYTE( ' ' ) ) ;
	 IF X > MinX THEN
	    AddChar( BYTE( LeftArrowHeadChar ) ) ;
	    AddChar( BYTE( ArrowShaftChar ) ) ;
	 ELSE
	    AddText( "  " ) ;
	 END (* if *) ;
	 AddChar( BYTE( ' ' ) ) ;
	 IF Y > MinY THEN
	    AddChar( BYTE( UpArrowLeftChar ) ) ;
	    AddChar( BYTE( UpArrowRightChar ) ) ;
	 END (* if *) ;
      END (* with *) ;	    
|
   1 :
      AddText( "Heading : " ) ;
      SensitiveBox( 0 , 0 , CurrentLevel , "General" ) ;
      PadTo( 24 ) ;
      SensitiveBox( 1 , 0 , CurrentLevel , "Keys" ) ;
      PadTo( 32 ) ;
      SensitiveBox( 2 , 0 , CurrentLevel , "Buffers" ) ;
(*
      PadTo( 43 ) ;
      SensitiveBox( 3 , 0 , CurrentLevel , "Actions" ) ;
      PadTo( 54 ) ;
      SensitiveBox( 4 , 0 , CurrentLevel , "Windows" ) ;
*)
   ELSE
   END (* case *) ;
END Header ;

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

PROCEDURE HelpCommand (Arg: List.ListP): List.ListP;

   VAR
      PreviousWindow  : Windows.WindowP;
      I		      : CARDINAL;
      Result	      : List.ListP;
      exitWindow      : Windows.WindowP;

   BEGIN
      HighLight := FALSE;
      Self^.Byte := HelpCh;
      Result := MoreHelp (NIL);
      CurrentLevel := HelpLevel;

      WITH MenuPosition [HelpLevel] DO
         Virgin := FALSE;
         X := 0;
         Y := 0;
         MinX := 0;
         MaxX := 2; (* Number of horizontal sensitive box headers - 1 *)
         MinY := 0;
         MaxY := 0;
      END (* with *);

      PreviousWindow := Windows.Selected;
      EXCL (HelpWindow^.Status, Windows.HiddenF);
      Windows.Select (HelpWindow, TRUE);

      REPEAT
         Display.Something; (* will co-routine return to ValidateHelpRow *)
         IF NOT Execute.Idle () THEN
           SpecialPerform;
         END (* if *);
      UNTIL HelpLevel < CurrentLevel;

      INCL (HelpWindow^.Status, Windows.HiddenF);
      exitWindow := Windows.ExitWindow (PreviousWindow);
      Windows.Select (exitWindow, FALSE);

      CurrentLevel := HelpLevel;
      EmptyWindowBuffer (HelpWindow);

      RETURN True ;

   END HelpCommand;

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

PROCEDURE MoreHelp (Arg: List.ListP): List.ListP;

   VAR I: CARDINAL;

   BEGIN
      IF HelpLevel < MaxHelpLevels THEN
         Actions.PushAndBind (HelpWindow^.Buffer, Self^.Byte, "MoreHelp", NIL);
         Actions.PushAndBind (HelpWindow^.Buffer, EscapeCh, "EndHelp", NIL);
         INC (HelpLevel);
         FOR I := HelpLevel TO MaxHelpLevels DO
  	    WITH MenuPosition [I] DO
	       Virgin := TRUE;
	       X := 0;
	       Y := 0;
	       MinX := 0;
	       MaxX := 0;
	       MinY := 0;
	       MaxY := 0;
	       Details.Selected := FALSE;
               Details.Initialized := FALSE
	    END (* with *)
         END (* for *)
      END (* if *);
      Changed := TRUE;
      RETURN True
   END MoreHelp;

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

PROCEDURE HelpComplete( Arg : List.ListP ) : List.ListP ;
VAR
   I				  : CARDINAL ;
BEGIN
   Actions.PopAndUnBind( Windows.Selected^.Buffer , Self^.Byte ) ;
   Actions.PopAndUnBind( Windows.Selected^.Buffer , HelpCh ) ;
   IF HelpLevel > 0 THEN
      DEC( HelpLevel ) ;
      FOR I := HelpLevel + 1 TO MaxHelpLevels DO
	 WITH MenuPosition[ I ] DO
	    Virgin := TRUE ;
	    X := 0 ;
	    Y := 0 ;
	    MinX := 0 ;
	    MaxX := 0 ;
	    MinY := 0 ;
	    MaxY := 0 ;
	 END (* with *) ;
      END (* for *) ;
   ELSE
      Errors.Panic( "Help.HelpComplete Level = 0" ) ;
   END (* if *) ;
   RETURN True ;
END HelpComplete ;

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

PROCEDURE SpecialPerform ();

   VAR
      Ch      : BYTE;
      Action  : Actions.ActionR;
      Result  : List.ListP;

   BEGIN
      Ch := Execute.NextAction (Action);
      WITH MenuPosition [HelpLevel] DO

         IF Ch = BYTE (08CH) THEN
	    (* Cursor Left *)
	    IF X > MinX THEN DEC (X) END
         ELSIF Ch = BYTE (08DH) THEN
	    (* Cursor Right *)
	    IF X < MaxX THEN INC (X) END
         ELSIF Ch = BYTE (08EH) THEN
	    (* Cursor Down *)
	    IF Y < MaxY THEN INC (Y) END
         ELSIF Ch = BYTE (08FH) THEN
	    (* Cursor up *)
	    IF Y > MinY THEN DEC (Y) END
         ELSE
	    Actions.Perform (Ch, Action)
         END (* if *)
      END (* with *)
   END SpecialPerform;

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

PROCEDURE ValidateHelpRow (Window: Windows.WindowP; Y: Windows.Vertical);

   VAR
      RelativeY  : Windows.Vertical;
      rowStart   : CARDINAL;

   BEGIN
      RelativeY := Y - Window^.Edge.Top;
      EmptyWindowBuffer (Window);
      rowStart := RelativeY * Width;
      writeIndex := rowStart;
      IF MenuPosition [CurrentLevel].Details.Selected THEN
         Details (RelativeY, MenuPosition [CurrentLevel].Details.ActionName);
      ELSE
         CASE MenuPosition [CurrentLevel].X OF
            0: HelpKeys.HelpPrimativeKeys (CurrentLevel, RelativeY)
         |  1: HelpKeys.HelpFunctionKeys (CurrentLevel, RelativeY)
         |  2: HelpBuffers.HelpBuffers (CurrentLevel, RelativeY)
(*
         |  3: HelpActions.HelpActions (CurrentLevel, RelativeY)
         |  4: HelpWindows.HelpWindows (CurrentLevel, RelativeY)
*)
         END (* case *);
      END (* if *);
      NewLine;
      WITH Window^ DO
         WITH DisplayAreas [Y] DO
 	    Area.Start := rowStart;
	    Area.End := rowStart + Width;
	    Pending.Fold := FALSE;
	    Pending.CountValid := FALSE;
	    Pending.WidePartialCount := 0;
	    MarkerTruncated := FALSE;
	    RealEnd := 0;
	    Valid := TRUE
         END (* with *)
      END (* with *)
   END ValidateHelpRow;

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

PROCEDURE ReadLine( VAR Buffer : ARRAY OF CHAR ) ;
VAR
   Length		: CARDINAL ;
   Ch			: CHAR ;
   Result		: INTEGER ;
BEGIN
   Length := 0 ;
   WHILE NOT IO.XEndOfFile( HelpFile ) DO
      Result := IO.SReadByte( HelpFile ) ;
      IF Result >= 0 THEN
	 Ch := CHAR( Result ) ;
	 Buffer[ Length ] := Ch ;
	 IF Ch = CHAR( EndOfLineCh ) THEN
	    Buffer[ Length ] := 0C ;
	    RETURN
	 END (* if *) ;
	 IF Length < HIGH( Buffer ) THEN
	    INC( Length ) ;
	 END (* if *) ;
      END (* if *) ;
   END (* while *) ;
   Buffer[ Length ] := CHAR( EndOfLineCh ) ;
END ReadLine ;

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

TYPE CacheRec = RECORD
                   level   : CARDINAL;
                   offset  : CARDINAL
                END;

VAR cache: RECORD
              data  : ARRAY [1..10] OF CacheRec;
              free  : CARDINAL
           END;

PROCEDURE Cache (lev: CARDINAL; off: CARDINAL; update: BOOLEAN);

   VAR i: CARDINAL;

   BEGIN
      i := 1;
      WHILE i < cache.free DO
        IF cache.data [i].level = lev THEN
           IF update THEN cache.data [i].offset := off END;
           RETURN
        END (* if *);
        INC (i)
      END (* if *);
      IF cache.free < 10 THEN

(* :*
Debug.WriteS ("Cache: (");
Debug.WriteC (lev);
Debug.WriteS (", ");
Debug.WriteC (off);
Debug.WriteS (")*N");
*: *)

         WITH cache.data [cache.free]  DO
            level := lev;
            offset := off
         END (* with *);
         INC (cache.free)
      END (* if *)
   END Cache;

PROCEDURE GetCache (lev: CARDINAL; VAR off: CARDINAL): BOOLEAN;

   VAR i: CARDINAL;

   BEGIN
      i := 1;
      WHILE i < cache.free DO
         IF cache.data [i].level = lev THEN
            off := cache.data [i].offset;
            RETURN TRUE
         END (* if *);
         INC (i)
      END (* while *);
      RETURN FALSE
   END GetCache;

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

PROCEDURE FindHelpSection (    nameP  : List.NameListP;
                               level  : CARDINAL;
                           VAR abort  : BOOLEAN        ): BOOLEAN;

   VAR
      target  : ARRAY [0..80] OF CHAR;
      buffer  : ARRAY [0..80] OF CHAR;
      offset  : CARDINAL;

   BEGIN
      CopyCC ("|||", target);
      ConcatCC (target, nameP^.Name, target);
      ConcatCC (target, "|||", target);

      buffer [0] := CHAR (MenuPosition [HelpLevel].Y + ORD ('0'));
      buffer [1] := 0C;
      ConcatCC (target, buffer, target);

(* :*
Debug.WriteS ("FindHelpSection: looking for '");
Debug.WriteS (target);
Debug.WriteS ("'*N");
*: *)

      abort := FALSE;

      IF NOT Execute.Idle () THEN

(* :*
Debug.WriteS ("FindHelpSection: abort*N");
*: *)

         abort := TRUE;
         RETURN FALSE
      END (* if *);

      IF GetCache (level, offset) THEN
         IO.XSetFileOffset (HelpFile, offset);
         ReadLine (buffer);
         IF EqualCC (buffer, target) THEN

(* :*
Debug.WriteS ("FindHelpSection: found at cached offset*N");
*: *)

            RETURN TRUE
         END (* if *);

(* :*
Debug.WriteS ("FindHelpSection: cache value (");
Debug.WriteC (level);
Debug.WriteS (", ");
Debug.WriteC (offset);
Debug.WriteS (") incorrect*N");
*: *)

      END (* if *);

      IO.XSetFileOffset (HelpFile, 0);

      WHILE NOT IO.XEndOfFile (HelpFile) DO
         IF NOT Execute.Idle () THEN

(* :*
Debug.WriteS ("FindHelpSection: abort*N");
*: *)

            abort := TRUE;
            RETURN FALSE
         END (* if *);
         ReadLine (buffer);
         IF EqualCC (buffer, target) THEN

(* :*
Debug.WriteS ("FindHelpSection: found by hard graft*N");
*: *)

 	    Cache (level, IO.XGetFileOffset (HelpFile) - (LengthC (buffer) + 1), TRUE);
            RETURN TRUE
         END (* if *)
      END (* while *);

(* :*
Debug.WriteS ("FindHelpSection: failed (EOF)*N");
*: *)

      RETURN FALSE
   END FindHelpSection;

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

PROCEDURE Details (RelativeY: CARDINAL; NameP: List.NameListP);

   VAR
      RealY   : CARDINAL;
      buffer  : ARRAY [0..80] OF CHAR;

   BEGIN
      RealY := HelpWindow^.Edge.Top + RelativeY;

      WITH MenuPosition [HelpLevel] DO

         IF NOT (Details.Initialized AND (Y = Details.Level)) THEN
            IF NOT Details.Initialized THEN
               Details.Level := 0;
               cache.free := 1
            ELSE Details.Level := Y
            END (* if *);
            INC (MaxY);
            Details.Found := FALSE;
            IF FindHelpSection (NameP, Y, Details.Aborted) THEN
               Details.Found := TRUE;
               Details.Complete := FALSE;
               Details.NextLine := 0
            END (* if *);
            DisplayPosition.SetInvalidColumn (HelpWindow);
            Details.Initialized := TRUE;
         END (* if *);

         IF Details.Found THEN

            IF Details.NextLine > RelativeY THEN (* this line already read *)
               WITH HelpWindow^.Buffer^ DO
                  WHILE Array.Data^ [writeIndex] # EndOfLineCh DO INC (writeIndex) END
               END (* with *)
            ELSE
               IF Details.Complete THEN RETURN END;
               REPEAT
                  IF NOT Execute.Idle () THEN RETURN END;
                  ReadLine (buffer);
	          IF (buffer [0] = '|') AND (buffer [1] = '|') AND (buffer [2] = '|') THEN
                     Details.Complete := TRUE
                  ELSE
                     writeIndex := Details.NextLine * Width;
                     AddText (buffer);
                     INC (Details.NextLine)
                  END (* if *)
               UNTIL (Details.NextLine > RelativeY) OR Details.Complete;
               IF (Details.NextLine = Height) OR Details.Complete THEN
                  Cache (Y + 1, IO.XGetFileOffset (HelpFile) - (LengthC (buffer) + 1), FALSE)
               END (* if *)
            END (* if *)

         ELSE

            IF RelativeY = 0 THEN
               IF Details.Aborted THEN AddText ("Detailed help aborted")
               ELSE AddText ("Sorry, no detailed help available")
               END (* if *)
            END (* if *)

         END (* if *)

      END (* with *)
   END Details;

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

PROCEDURE DisplayHelpCh (Ch: BYTE; VAR Pending: Windows.PendingR): BOOLEAN;

   (* 00..1F are inverse 20..3F
      20..BF are normal
      C0..FF are inverse 40..7F  *)

   BEGIN
      IF Ch <= BYTE (01FH) THEN Screen.InverseCh (BYTE (CARDINAL (Ch) + 020H))
      ELSIF Ch <= BYTE (080H) THEN RETURN Display.DisplayCharacter (Ch, Pending)
      ELSIF Ch < BYTE (0C0H) THEN Screen.UpdateCh (Ch)
      ELSE Screen.InverseCh (BYTE (CARDINAL (Ch) - 080H))
      END (* if *);
      RETURN TRUE;
   END DisplayHelpCh;

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

PROCEDURE WidthDisplayHelpCh (Ch: BYTE; X, ArrayIndex: CARDINAL): CARDINAL;

   BEGIN
      IF Ch > BYTE (0A0H) THEN
         RETURN Display.DisplayWidth (BYTE (CARDINAL (Ch) = 080H), X, ArrayIndex);
      ELSE
         RETURN 1;
      END (* if *);
   END WidthDisplayHelpCh;

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

PROCEDURE Dummy (Arg: List.ListP): List.ListP;

   BEGIN
      RETURN False
   END Dummy;

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

PROCEDURE Initialise;

   VAR
      HelpFileName  : ARRAY [0..255] OF CHAR;
      Length	    : CARDINAL;

   BEGIN
      HighLight := FALSE;
      HelpLevel := 0;

      LOOP
         IF Windows.New (HelpWindow, 1, Screen.BottomRow - Height - 1, Width, Height) THEN
            IF Buffers.New (HelpWindow^.Buffer, (Width * Height) + 100, HelpWindow^.Identity) THEN
(*
               IF StringData.CopyCD ("<<<Help>>>", HelpWindow^.Buffer^.Name) THEN
*)
                  EXIT;
(*
               END (* if *);
*)
            END (* if *);
         END (* if *);
         Errors.Panic ("Help: insufficient memory to create help window*N")
      END (* loop *);

      HelpWindow^.DisplayCh := DisplayHelpCh;
      HelpWindow^.WidthDisplayCh := WidthDisplayHelpCh;
      HelpWindow^.ValidateRow := ValidateHelpRow;
      HelpWindow^.Margins.Real := HelpWindow^.Edge;
      HelpWindow^.Margins.Current := HelpWindow^.Edge;

      EXCL (HelpWindow^.Status, Windows.DisplayEndF);
      INCL (HelpWindow^.Status, Windows.DisplayAtLeastOneLineF);
      INCL (HelpWindow^.Status, Windows.NoCursorF);
      INCL (HelpWindow^.Status, Windows.HiddenF);

      Actions.BuiltInAction ("Escape", Dummy, "");
      Actions.BuiltInAction ("Disaster", Dummy, "");

      Actions.BuiltInAction ("Help", HelpCommand, "Help !!");
      Actions.BuiltInAction ("MoreHelp", MoreHelp, "Next Help level");
      Actions.BuiltInAction ("EndHelp", HelpComplete, "Exit Help level");

      Actions.Bind (BYTE(0C5H), "Help", NIL);

      IF GlobalString.GetGlobalString (HelpFileName, Length, "EDIT$HelpFile") >= 0 THEN
	 HelpFile := IO.XFindInput (HelpFileName)
      ELSE
	 HelpFile := IO.XFindInput ("null:")
      END (* if *);

   END Initialise;

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

PROCEDURE Terminate;

  BEGIN
  END Terminate;

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

END Help.

