MODULE editor; (* based on the kilo editor building course*) (* Step 24 *) (*** IMPORTS ***) IMPORT IO, termios, FIO, libc, CharClass, NumberIO, ASCII ; IMPORT STextIO, Strings, SYSTEM; (*** data ***) CONST clearScreenStrLen = 4; cursorHomeStrLen = 3; VAR c : CHAR; theTermios : termios.TERMIOS; TCSAFLUSH : INTEGER; i : CARDINAL; (* escape sequences *) clearScreenStr : ARRAY[0..3] OF CHAR; cursorHomeStr : ARRAY[0..2] OF CHAR; (* escape sequences length *) (*** 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.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr), cursorHomeStrLen); libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr), clearScreenStrLen); libc.perror(s); FOR i := 0 TO Strings.Length(s) DO IO.Write(s[i]) END; HALT END die; PROCEDURE disablerawMode() : INTEGER; VAR result : INTEGER; BEGIN IO.BufferedMode(0,TRUE); IO.BufferedMode(1,TRUE); result := termios.tcsetattr(FIO.StdIn, TCSAFLUSH, theTermios); IF result = -1 THEN theTermios := termios.KillTermios(theTermios); die("tcsetattr") ELSE RETURN result END; END disablerawMode; PROCEDURE enablerawMode; BEGIN libc.atexit(disablerawMode); theTermios := termios.InitTermios(); IF termios.tcgetattr(FIO.StdIn, theTermios) = -1 THEN die("tcgetattr") END; IO.UnBufferedMode(0,TRUE); IO.UnBufferedMode(1,TRUE); END enablerawMode; PROCEDURE editorReadKey() : CHAR; VAR c : CHAR; BEGIN IO.Read(c); RETURN c END editorReadKey; PROCEDURE editorProcessKeypress; VAR c : CHAR; BEGIN c := editorReadKey(); CASE ORD(c) OF 17 : libc.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr), cursorHomeStrLen); libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr), clearScreenStrLen); HALT; END END editorProcessKeypress; (*** Output ***) PROCEDURE editorRefreshScreen; BEGIN libc.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr), cursorHomeStrLen); libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr), clearScreenStrLen); END editorRefreshScreen; (*** Input ***) (*** Init ***) PROCEDURE InitScreenEscapes; VAR temp : ARRAY[0..10] OF CHAR; BEGIN cursorHomeStr := ""; Strings.Concat(cursorHomeStr,ASCII.esc,cursorHomeStr); Strings.Concat(cursorHomeStr,"[H",cursorHomeStr); clearScreenStr := ""; Strings.Concat(clearScreenStr,ASCII.esc,clearScreenStr); Strings.Concat(clearScreenStr,"[2J",clearScreenStr); END InitScreenEscapes; BEGIN InitScreenEscapes; TCSAFLUSH := termios.tcsflush (); enablerawMode; editorRefreshScreen; LOOP editorProcessKeypress; editorRefreshScreen; END; END editor.