MODULE editor;

(* based on the kilo editor building course*)

(* Step 21 *)

(******************** INCLUDES ******************)

IMPORT FIO, SYSTEM, termios, STextIO, NumberIO;
IMPORT CharClass, STextIO, libc, ASCII;
IMPORT Strings, errno;

(******************** DATA ******************)

VAR 
    c           : CHAR;
    p           : POINTER TO CHAR;
    thetermios  : termios.TERMIOS;
    raw         : termios.TERMIOS;
    result      : INTEGER;
    number      : CARDINAL;
    (* testing *)
    test        : BOOLEAN;

(******************** TERMINAL ******************)

     PROCEDURE CtrlKey(c: CHAR) : CARDINAL;

        VAR
            n : BITSET;

    BEGIN
        n := BITSET(ORD(c));
        n := n * BITSET(1FH);
        RETURN CARDINAL(n)
    END CtrlKey;

    PROCEDURE die (s : ARRAY OF CHAR);
    BEGIN
        libc.perror(s);
        HALT
    END die;

    PROCEDURE disableRawMode(): INTEGER;
        VAR
            TCSAFLUSH : INTEGER;
            result    : INTEGER; 
        
    BEGIN
        TCSAFLUSH := termios.tcsflush ();
        IF termios.tcsetattr(FIO.StdIn, TCSAFLUSH, thetermios) = -1 THEN
            die("tcsetattr")
        END;
        RETURN result;
    END disableRawMode;

    PROCEDURE enableRawMode;

        VAR
            TCSAFLUSH   : INTEGER;
            result      : INTEGER;
            bresult     : BOOLEAN;
    BEGIN
        TCSAFLUSH := termios.tcsflush (); 
        libc.atexit(disableRawMode);
        bresult := termios.SetFlag(raw,termios.icrnl, FALSE);
        bresult := termios.SetFlag(raw,termios.ixon, FALSE);
        bresult := termios.SetFlag(raw,termios.lecho, FALSE);
        bresult := termios.SetFlag(raw,termios.opost, FALSE);
        bresult := termios.SetFlag(raw,termios.licanon, FALSE);
        bresult := termios.SetFlag(raw,termios.liexten, FALSE);
        bresult := termios.SetFlag(raw,termios.lisig, FALSE);

        bresult := termios.SetFlag(raw,termios.ibrkint, FALSE);
        bresult := termios.SetFlag(raw,termios.inpck, FALSE);
        bresult := termios.SetFlag(raw,termios.istrip, FALSE);

        bresult := termios.SetFlag(raw,termios.cs8, TRUE);
        IF termios.tcsetattr(FIO.StdIn, TCSAFLUSH, raw) = -1 THEN
            die("tcsetattr")
        END;

        (* PROCEDURE SetChar (t: TERMIOS; c: ControlChar; ch: CHAR) : BOOLEAN ; *)
        (* termios.vmin := 0;
        termios.vtime := 1; *)
        bresult := termios.SetChar(raw,termios.vmin,CHR(0));
        bresult := termios.SetChar(raw,termios.vtime,CHR(1));
    END enableRawMode;

    PROCEDURE  editorReadKey() : CHAR;
        VAR
            c : CHAR;
            nread : INTEGER;
    BEGIN
        p := SYSTEM.ADR(c);
        WHILE FIO.ReadNBytes(FIO.StdIn,1,p) <> 1 DO 
           ;
        END;
        RETURN c
    END editorReadKey; 

(******************** output ******************)


(******************** input  ******************)

    PROCEDURE editorProcessKeypress;
        VAR
            c       : CHAR;
            b       : BOOLEAN;
    BEGIN
        c := editorReadKey();
        CASE ORD(c) OF
          17 : HALT;
        END
    END editorProcessKeypress;

(********************  INIT  ******************)



BEGIN
    thetermios := termios.InitTermios();
    raw := termios.InitTermios();
    IF termios.tcgetattr(FIO.StdIn, thetermios) = -1 THEN
        die("tcgetattr")
    END;
    IF termios.tcgetattr(FIO.StdIn, raw) = -1 THEN
        die("tcgetattr")
    END;

    enableRawMode;
    
    LOOP
        editorProcessKeypress();
    END;


END editor.