Browse Source

Small updates, installation text update

Arthur Yefimov 1 year ago
parent
commit
17be4eda61
6 changed files with 241 additions and 1076 deletions
  1. 234 0
      Programs/Viewer.Mod
  2. 4 4
      install.sh
  3. 0 10
      src/Autodoc/Data/style.css
  4. 2 0
      src/Builder.Mod
  5. 1 1
      src/Graph.Mod
  6. 0 1061
      src/Programs/FreeOberon.Mod

+ 234 - 0
Programs/Viewer.Mod

@@ -0,0 +1,234 @@
+MODULE Viewer;
+IMPORT Files, Out, T := TermBox, Args, Graph;
+
+CONST
+  lineLen = 140;
+
+TYPE
+  Line = POINTER TO LineDesc;
+  LineDesc = RECORD
+    s: ARRAY lineLen OF CHAR;
+    prev, next: Line
+  END;
+
+  Viewer = RECORD
+    first, last: Line;
+    count: INTEGER; (** Количество строк *)
+    curY: INTEGER; (** Сдвиг вниз от первой строки *)
+    firstOnScreen: Line; (** Первая строка, видимая сейчас на экране *)
+    redraw: BOOLEAN (** Нужно ли перерисовывать *)
+  END;
+
+VAR
+  X, Y, W, H: INTEGER;
+  fg, bg, border, scrollFg, scrollBg: INTEGER;
+
+PROCEDURE ReadFile(VAR v: Viewer; fname: ARRAY OF CHAR);
+VAR
+  F: Files.File;
+  r: Files.Rider;
+  ch: CHAR;
+  p: Line;
+  i: INTEGER;
+BEGIN
+  F := Files.Old(fname);
+  IF F = NIL THEN
+    Out.String('Could not read file "');
+    Out.String(fname); Out.String('".'); Out.Ln
+  ELSE
+    Files.Set(r, F, 0);
+    NEW(v.first);
+    p := v.first;
+    i := 0;
+    v.count := 1;
+    Files.ReadChar(r, ch);
+    WHILE ~r.eof DO
+      IF ch = 0AX THEN
+        p.s[i] := 0X;
+        NEW(p.next);
+        p.next.prev := p;
+        p := p.next;
+        i := 0;
+        INC(v.count)
+      ELSIF ch # 0DX THEN
+        IF i < LEN(p.s) - 1 THEN p.s[i] := ch; INC(i) END
+      END;
+      Files.ReadChar(r, ch)
+    END;
+    p.s[i] := 0X;
+    v.last := p
+  END;
+  v.firstOnScreen := v.first;
+  v.curY := 0
+END ReadFile;
+
+PROCEDURE MoveLineUp(VAR v: Viewer);
+BEGIN
+  IF v.curY > 0 THEN
+    DEC(v.curY);
+    v.firstOnScreen := v.firstOnScreen.prev
+  END
+END MoveLineUp;
+
+PROCEDURE MoveLineDown(VAR v: Viewer);
+BEGIN
+  IF v.curY < v.count - H THEN
+    INC(v.curY);
+    v.firstOnScreen := v.firstOnScreen.next
+  END
+END MoveLineDown;
+
+PROCEDURE MoveScreenUp(VAR v: Viewer);
+VAR i: INTEGER;
+BEGIN
+  i := H;
+  WHILE i # 0 DO MoveLineUp(v); DEC(i) END
+END MoveScreenUp;
+
+PROCEDURE MoveScreenDown(VAR v: Viewer);
+VAR i: INTEGER;
+BEGIN
+  i := H;
+  WHILE i # 0 DO MoveLineDown(v); DEC(i) END
+END MoveScreenDown;
+
+PROCEDURE MoveToTop(VAR v: Viewer);
+BEGIN
+  v.firstOnScreen := v.first;
+  v.curY := 0
+END MoveToTop;
+
+PROCEDURE MoveToBottom(VAR v: Viewer);
+VAR y: INTEGER;
+  p: Line;
+BEGIN
+  y := v.count - H;
+  IF y <= 0 THEN
+    MoveToTop(v)
+  ELSE
+    v.curY := y;
+    p := v.first;
+    WHILE y # 0 DO
+      p := p.next;
+      DEC(y)
+    END;
+    v.firstOnScreen := p
+  END
+END MoveToBottom;
+
+PROCEDURE HandleKey(VAR v: Viewer; key: INTEGER; VAR done: BOOLEAN);
+BEGIN
+  v.redraw := TRUE;
+  IF key = T.kEsc THEN done := TRUE
+  ELSIF key = T.kUp THEN MoveLineUp(v)
+  ELSIF key = T.kDown THEN MoveLineDown(v)
+  ELSIF key = T.kPgUp THEN MoveScreenUp(v)
+  ELSIF key = T.kPgDn THEN MoveScreenDown(v)
+  ELSIF key = T.kHome THEN MoveToTop(v)
+  ELSIF key = T.kEnd THEN MoveToBottom(v)
+  ELSE v.redraw := FALSE
+  END
+END HandleKey;
+
+PROCEDURE DrawLine(v: Viewer; p: Line; y: INTEGER);
+VAR x: INTEGER;
+BEGIN
+  x := 0;
+  WHILE (p.s[x] # 0X) & (x < W) DO
+    T.SetCell(X + x, Y + y, p.s[x], fg, bg);
+    INC(x)
+  END;
+  T.Print(X, Y + H, W,
+    'Двигайтесь клавишами со стрелками, а также Home, End, PageUp, PageDown',
+    bg, border)
+END DrawLine;
+
+PROCEDURE InitialDraw(VAR v: Viewer);
+BEGIN
+  T.ClearTo(fg, border);
+  T.Fill(X, Y, W, H, ' ', fg, bg);
+END InitialDraw;
+
+PROCEDURE DrawScrollbar(v: Viewer);
+VAR y, h, n: INTEGER;
+BEGIN
+  h := H * H DIV v.count;
+  IF h < 1 THEN h := 1 END;
+  IF h < H THEN
+    n := v.count - H;
+    y := (v.curY * (H - h) + n DIV 2) DIV n;
+
+    T.Fill(X + W - 2, Y, 2, H, ' ', fg, scrollBg);
+    T.Fill(X + W - 2, Y + y, 2, h, ' ', fg, scrollFg)
+  END
+END DrawScrollbar;
+
+PROCEDURE Draw(v: Viewer);
+VAR p: Line;
+  i: INTEGER;
+BEGIN
+  T.Fill(X, Y, W, H, ' ', fg, bg);
+  p := v.firstOnScreen;
+  i := 0;
+  WHILE (i < H) & (p # NIL) DO
+    DrawLine(v, p, i);
+    INC(i);
+    p := p.next
+  END;
+  DrawScrollbar(v);
+  T.Flush
+END Draw;
+
+PROCEDURE Run(VAR v: Viewer);
+VAR e: T.Event;
+  done: BOOLEAN;
+BEGIN
+  InitialDraw(v);
+  v.redraw := TRUE;
+  REPEAT
+    IF v.redraw THEN
+      Draw(v);
+      v.redraw := FALSE
+    END;
+    T.WaitEvent(e);
+    IF e.type = T.quit THEN done := TRUE
+    ELSIF e.type = T.key THEN HandleKey(v, e.key, done)
+    END
+  UNTIL done;
+END Run;
+
+PROCEDURE View(fname: ARRAY OF CHAR);
+VAR v: Viewer;
+BEGIN
+  T.Init; T.HideCursor; T.HideMouse;
+  T.Size(W, H); DEC(W, 4); DEC(H, 2); X := 2; Y := 1;
+  fg := 3; bg := 1; border := 9; scrollBg := 0; scrollFg := 3;
+  ReadFile(v, fname);
+  Run(v);
+  T.Close
+END View;
+
+PROCEDURE Usage;
+VAR s: ARRAY 256 OF CHAR;
+BEGIN
+  Out.String('Viewer. Usage:'); Out.Ln;
+  Args.Get(0, s);
+  Out.String('  '); Out.String(s);
+  Out.String(' fileName'); Out.Ln
+END Usage;
+
+PROCEDURE Do;
+VAR s: ARRAY 1024 OF CHAR;
+BEGIN
+  IF Args.Count() = 1 THEN
+    Args.Get(1, s);
+    View(s)
+  ELSE
+    Usage;
+    View('../README.md') (*This is for easier demonstration, you may delete it*)
+  END
+END Do;
+
+BEGIN
+  Do
+END Viewer.

+ 4 - 4
install.sh

@@ -12,14 +12,14 @@ echo "README.md file."
 echo
 echo "On OS Debian / Ubuntu / Linux Mint and so on:"
 echo "  sudo apt-get update"
-echo "  sudo apt-get install -y git gcc libc-dev liballegro5-dev"
-echo "or:"
+echo "  sudo apt-get install -y git gcc libc-dev liballegro5-dev liballegro-image5-dev liballegro-audio5-dev liballegro-acodec5-dev"
+echo "or, if sudo is not installed on Debian:"
 echo "  su"
 echo "  apt-get update"
-echo "  apt-get install -y git gcc libc-dev liballegro5-dev"
+echo "  apt-get install -y git gcc libc-dev liballegro5-dev liballegro-image5-dev liballegro-audio5-dev liballegro-acodec5-dev"
 echo
 echo "On OS Fedora:"
-echo "  sudo dnf install -y git gcc glibc-devel allegro5-devel allegro5-addon-image allegro5-addon-audio allegro5-addon-acodec allegro5-addon-dialog allegro5-devel allegro5-addon-image-devel allegro5-addon-audio-devel allegro5-addon-acodec-devel allegro5-addon-dialog-devel argro5-addon-dialog-devel"
+echo "  sudo dnf install -y git gcc glibc-devel allegro5-devel allegro5-addon-image allegro5-addon-audio allegro5-addon-acodec allegro5-devel allegro5-addon-image-devel allegro5-addon-audio-devel allegro5-addon-acodec-devel"
 echo
 echo "On Arch Linux:"
 echo "  sudo pacman -Sy git gcc pkgconf glibc allegro"

+ 0 - 10
src/Autodoc/Data/style.css

@@ -77,11 +77,6 @@ a:hover {
   text-align: center;
 }
 
-.footer .date {
-  color: var(--head2-bg);
-  margin-top: 1em;
-}
-
 .main {
   padding: 20px 0;
   flex: 1;
@@ -238,16 +233,11 @@ h2, h3, h4, h5, h6 {
   color: var(--comment-fg);
 }
 
-.group-title:empty,
 .group > .comment:empty,
 .object > .comment:empty {
   display: none;
 }
 
-.comment code {
-  color: var(--tab-row-fg);
-}
-
 .record-fields .comment {
   color: #C91E0C;
   color: var(--tab-row-fg);

+ 2 - 0
src/Builder.Mod

@@ -555,6 +555,8 @@ BEGIN mod.foreign := FALSE; res := 401; NEW(top); top.next := NIL; p := top;
           END
         END;
         findLinkInfo := NIL
+      ELSE Debug.StrVal('Read name is: ', s);
+        Debug.StrVal('Mod name is: ', mod.s)
       END
     ELSE Debug.StrVal('GetImportedModules: First symbol is: ', s)
     END

+ 1 - 1
src/Graph.Mod

@@ -781,7 +781,7 @@ BEGIN Al.unlock_bitmap(bmp.bmp)
 END UnlockBitmap;
 
 PROCEDURE GetPixel*(bmp: Bitmap; x, y: INTEGER; VAR color: Color);
-BEGIN 
+BEGIN
   Al.get_pixel(bmp.bmp, x, y, SYSTEM.VAL(Al.Color, color))
 END GetPixel;
 

+ 0 - 1061
src/Programs/FreeOberon.Mod

@@ -1,1061 +0,0 @@
-MODULE FreeOberon; (* COPY *)
-(* Copyright 2017-2023 Arthur Yefimov
-
-This file is part of Free Oberon.
-
-Free Oberon is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Free Oberon is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Free Oberon.  If not, see <http://www.gnu.org/licenses/>.
-*)
-IMPORT T := TermBox, Files, Args, Utf8, Builder, Env, Debug, Graph,
-       OV, Editor, Term, FoStrings, Config, Strings, Int, Out, Kernel;
-(** Free Oberon IDE and Compiler. Part of Free Oberon IDE internal code *)
-CONST
-  (* Direction of Selection *)
-  dirLeft  = 0;
-  dirRight = 1;
-  dirUp    = 2;
-  dirDown  = 3;
-
-  (* States *)
-  stateEditor   = 0;
-  stateTerminal = 1;
-
-  (* Character Classes *)
-  charOther       = 0; (*!FIXME Remove these constants *)
-  charAlpha       = 1;
-  charDigit       = 2;
-  charMinusPlus   = 3;
-  charQuote       = 4;
-  charOpenBracket = 5;
-
-  (* Token Classes *)
-  tokenOther   = 0;
-  tokenKeyword = 1;
-  tokenNumber  = 2;
-  tokenString  = 3;
-  tokenComment = 4;
-
-  (* Defaults *)
-  defW = 106;
-  defH = 25;
-  defLang = 'en';
-
-TYPE
-  Fnames = ARRAY 32, 256 OF CHAR;
-
-  LanguageDialog* = POINTER TO LanguageDialogDesc;
-  LanguageDialogDesc = RECORD(OV.WindowDesc)
-    btnRu*, btnEn*: OV.Button
-  END;
-
-VAR
-  progBuf: ARRAY 16300 OF SHORTCHAR; (* For interaction with running program *)
-  inputBuf: ARRAY 16300 OF CHAR; (* Holds entered chars before Enter pressed *)
-  inputBufLen: INTEGER;
-  programFinished: BOOLEAN;
-  lastFileDialogDir: ARRAY 256 OF CHAR; (* Directory path for file dialog *)
-  app: OV.App;
-
-  curX, curY: INTEGER; (* Text cursor position *)
-  curFg, curBg: INTEGER; (* Current foreground and background of proc. Write *)
-  terminalNeedRedraw: BOOLEAN; (* Used when a compiled program is running *)
-  terminalMouseShown: BOOLEAN; (* Same *)
-
-  lastW, lastH: INTEGER; (* Last screen size *)
-
-(* Language Dialog *)
-
-PROCEDURE LanguageButtonClick*(c: OV.Control);
-VAR lang: ARRAY 10 OF CHAR;
-BEGIN
-  IF c.caption = 'English' THEN lang := 'en' ELSE lang := 'ru' END;
-  IF lang # FoStrings.lang THEN FoStrings.SetLang(lang) END;
-  OV.CloseCurWindow(c)
-END LanguageButtonClick;
-
-PROCEDURE InitLanguageDialog*(c: LanguageDialog);
-VAR lbl: OV.Label;
-  s: FoStrings.String;
-BEGIN OV.InitWindow(c);
-  c.modal := TRUE; c.w := 37; c.h := 8; OV.CenterWindow(c);
-
-  FoStrings.Get('labelChooseLanguage', s);
-  lbl := OV.NewLabel(s);
-  lbl.align := OV.center;
-  lbl.do.resize(lbl, 1, 2, c.w - 2, 1);
-  OV.Add(c, lbl);
-
-  (* Ru button *)
-  c.btnRu := OV.NewButton('Русский');
-  c.btnRu.onClick := LanguageButtonClick;
-  c.btnRu.do.resize(c.btnRu, 5, 4, 11, 1);
-  OV.Add(c, c.btnRu);
-
-  (* En button *)
-  c.btnEn := OV.NewButton('English');
-  c.btnEn.onClick := LanguageButtonClick;
-  c.btnEn.do.resize(c.btnEn, 20, 4, 11, 1);
-  OV.Add(c, c.btnEn)
-END InitLanguageDialog;
-
-PROCEDURE NewLanguageDialog*(): LanguageDialog;
-VAR c: LanguageDialog;
-BEGIN NEW(c); InitLanguageDialog(c) ;
-RETURN c END NewLanguageDialog;
-
-(* General *)
-
-PROCEDURE CountLines(s: ARRAY OF CHAR; width: INTEGER): INTEGER;
-VAR i, x, lines: INTEGER;
-BEGIN
-  i := 0; x:= 0; lines := 1;
-  WHILE s[i] # 0X DO
-    IF s[i] = 0AX THEN
-      INC(lines); x := 0
-    ELSIF s[i] # 0DX THEN
-      IF x = width - 1 THEN INC(lines); x := 0
-      ELSE INC(x)
-      END
-    END;
-    INC(i)
-  END ;
-RETURN lines END CountLines;
-
-PROCEDURE ShowError(s: ARRAY OF CHAR);
-BEGIN Editor.SetMsg(app.windows(Editor.Editor), s)
-END ShowError;
-
-PROCEDURE FileNew(c: OV.Control);
-VAR e: Editor.Editor;
-  p, br: OV.Control;
-  count: INTEGER;
-  tW, tH: INTEGER;
-BEGIN e := Editor.NewEditor();
-  p := app.windows; br := p; count := 0;
-  WHILE p # NIL DO INC(count);
-    IF p.next = br THEN p := NIL ELSE p := p.next END
-  END;
-  IF app.windows # NIL THEN
-    e.x := app.windows.x + 1; e.y := app.windows.y + 1;
-    e.w := app.windows.w; e.h := app.windows.h;
-    T.Size(tW, tH);
-    IF e.x + e.w >= tW THEN e.w := tW - e.x END;
-    IF e.y + e.h >= tH - 1 THEN e.h := tH - e.y - 1 END;
-    IF (e.w < 10) OR (e.h < 3) THEN
-      e.x := 0; e.y := 1; e.w := tW; e.h := tH - 2
-    END
-  END;
-  e.caption := 'NONAME??.Mod';
-  e.caption[6] := CHR(ORD('0') + count DIV 10 MOD 10);
-  e.caption[7] := CHR(ORD('0') + count MOD 10);
-  OV.AddWindow(app, e)
-END FileNew;
-
-PROCEDURE FnameToCaption(IN fname: ARRAY OF CHAR; VAR caption: ARRAY OF CHAR);
-BEGIN
-  IF Strings.Pos(Config.stdPath, fname, 0) = 0 THEN
-    Strings.Extract(fname, Strings.Length(Config.stdPath),
-      LEN(caption), caption)
-  ELSE caption := fname$
-  END
-END FnameToCaption;
-
-PROCEDURE DoOpenFile(IN fname: ARRAY OF CHAR);
-VAR e: Editor.Editor; newWin: BOOLEAN;
-BEGIN
-  IF (app.windows # NIL) & (app.windows IS Editor.Editor) THEN
-    e := app.windows(Editor.Editor)
-  ELSE e := NIL
-  END;
-  newWin := (e = NIL) OR ~Editor.IsEmpty(e);
-  IF newWin THEN e := Editor.NewEditor() END;
-  IF e.text.LoadFromFile(fname) THEN
-    e.fname := fname$;
-    FnameToCaption(fname, e.caption);
-    IF newWin THEN OV.AddWindow(app, e) END
-  ELSE (*!FIXME*)
-  END
-END DoOpenFile;
-
-PROCEDURE FocusOrOpenFile(fname: ARRAY OF CHAR);
-VAR e, f: Editor.Editor;
-BEGIN
-  e := app.windows(Editor.Editor); f := e;
-  WHILE (e # NIL) & (e.fname # fname) DO
-    IF e.next = f THEN e := NIL ELSE e := e.next(Editor.Editor) END
-  END;
-  IF e = NIL THEN DoOpenFile(fname) ELSE app.windows := e; OV.SetFocus(e) END;
-  OV.DrawApp(app)
-END FocusOrOpenFile;
-
-PROCEDURE ScrollScreen;
-VAR x, y, tW, tH: INTEGER;
-  ch: CHAR;
-  fg, bg: INTEGER;
-BEGIN
-  T.Size(tW, tH);
-  FOR y := 0 TO tH - 2 DO
-    FOR x := 0 TO tW - 1 DO
-      T.GetCell(x, y + 1, ch, fg, bg);
-      T.SetCell(x, y, ch, fg, bg)
-    END
-  END;
-  FOR x := 0 TO tW - 1 DO
-    T.SetCell(x, tH - 1, ' ', curFg, curBg)
-  END;
-  terminalNeedRedraw := TRUE
-END ScrollScreen;
-
-PROCEDURE Ln;
-VAR tW, tH: INTEGER;
-BEGIN T.Size(tW, tH); curX := 0;
-  IF curY >= tH - 1 THEN ScrollScreen; curY := tH - 1
-  ELSE INC(curY); terminalNeedRedraw := TRUE
-  END;
-END Ln;
-
-PROCEDURE Write(ch: CHAR);
-VAR tW, tH: INTEGER;
-BEGIN
-  IF ch = 0AX THEN Ln
-  ELSIF ~Config.isWindows OR (ch # 0DX) THEN
-    T.SetCell(curX, curY, ch, curFg, curBg);
-    T.Size(tW, tH);
-    IF curX >= tW - 1 THEN
-      curX := 0;
-      IF curY >= tH - 1 THEN ScrollScreen; curY := tH - 1 ELSE INC(curY) END
-    ELSE INC(curX)
-    END;
-    terminalNeedRedraw := TRUE
-  END;
-  T.SetCursor(curX, curY)
-END Write;
-
-PROCEDURE WriteString(s: ARRAY OF CHAR);
-VAR i: INTEGER;
-BEGIN i := 0;
-  WHILE s[i] # 0X DO Write(s[i]); INC(i) END
-END WriteString;
-
-PROCEDURE Backspace;
-VAR tW, tH: INTEGER;
-BEGIN
-  IF curX = 0 THEN T.Size(tW, tH);
-    IF curY # 0 THEN curX := tW - 1; DEC(curY) END
-  ELSE DEC(curX);
-  END;
-  T.SetCell(curX, curY, ' ', curFg, curBg);
-  T.SetCursor(curX, curY);
-  terminalNeedRedraw := TRUE
-END Backspace;
-
-PROCEDURE PollProgram;
-VAR len, i: INTEGER;
-    err: INTEGER;
-    s, sN: FoStrings.String;
-
-  PROCEDURE WriteProgBuf;
-  VAR ch: SHORTCHAR; i: INTEGER;
-    z: ARRAY 16300 OF CHAR;
-  BEGIN
-    IF len < LEN(progBuf) THEN ch := progBuf[len]; progBuf[len] := 0X END;
-    Utf8.Decode(progBuf, z);
-    i := 0; WHILE z[i] # 0X DO Write(z[i]); INC(i) END;
-    IF len < LEN(progBuf) THEN progBuf[len] := ch END
-  END WriteProgBuf;
-
-  PROCEDURE Read(tillEnd: BOOLEAN);
-  VAR loopLimit: INTEGER;
-  BEGIN
-    loopLimit := 20;
-    REPEAT
-      Term.ReadFromProcess(progBuf, len, LEN(progBuf));
-      IF len > 0 THEN
-        IF inputBufLen > 0 THEN
-          FOR i := 0 TO inputBufLen - 1 DO Backspace END;
-          inputBufLen := 0
-        END;
-        WriteProgBuf
-      END;
-      DEC(loopLimit)
-    UNTIL (len <= 0) OR (loopLimit <= 0) & ~tillEnd
-  END Read;
-BEGIN
-  IF ~programFinished THEN
-    IF Term.ProcessFinished(err) THEN
-      Read(TRUE); (* Read everything until pipe is empty *)
-      programFinished := TRUE;
-      IF err = 0 THEN s := ' '; FoStrings.Append('pressAnyKeyToReturnToIde', s)
-      ELSE s := ' '; FoStrings.Append('runtimeError', s);
-        Strings.Append(' ', s); Int.Append(err, s)
-      END;
-      WriteString(s)
-    ELSE
-      Read(FALSE) (* Attempt several reads *)
-    END
-  END
-END PollProgram;
-
-PROCEDURE WriteToProcess(s: ARRAY OF CHAR; len: INTEGER);
-VAR buf: ARRAY 2048 OF SHORTCHAR;
-  q: ARRAY 5 OF SHORTCHAR;
-  i, j, L, bufLen: INTEGER;
-BEGIN bufLen := 0; i := 0;
-  WHILE i < len DO
-    Utf8.EncodeChar(s[i], q, L); j := 0;
-    WHILE j # L DO buf[bufLen] := q[j]; INC(bufLen); INC(j) END;
-    INC(i)
-  END;
-  Term.WriteToProcess(buf, bufLen)
-END WriteToProcess;
-
-PROCEDURE HandleTerminalTextInput(ch: CHAR);
-BEGIN
-  IF (ch # 0X) & (inputBufLen < LEN(inputBuf)) THEN
-    inputBuf[inputBufLen] := ch; INC(inputBufLen); Write(ch)
-  END
-END HandleTerminalTextInput;
-
-PROCEDURE KillProgram;
-BEGIN
-  programFinished := TRUE;
-  (*!TODO Kill program *)
-END KillProgram;
-
-PROCEDURE HandleTerminalKeyDown(VAR E: T.Event; VAR quit: BOOLEAN);
-VAR code: INTEGER; ch: CHAR; buf: ARRAY 2 OF SHORTCHAR;
-BEGIN
-  IF programFinished THEN
-    quit := TRUE
-  ELSE
-    CASE E.key OF
-      T.kEnter, T.kEnterPad:
-      Ln;
-      WriteToProcess(inputBuf, inputBufLen);
-      inputBufLen := 0; buf[0] := 0AX;
-      Term.WriteToProcess(buf, 1)
-    | T.kBackspace:
-      IF inputBufLen > 0 THEN
-        DEC(inputBufLen); Backspace
-      END
-    | T.kPause:
-      IF T.mCtrl IN E.mod THEN
-        KillProgram;
-        quit := TRUE
-      END
-    ELSE
-      HandleTerminalTextInput(E.ch)
-    END
-  END
-END HandleTerminalKeyDown;
-
-PROCEDURE RunTerminal;
-VAR E: T.Event; quit: BOOLEAN;
-BEGIN quit := FALSE;
-  T.Clear;
-  terminalNeedRedraw := TRUE;
-  terminalMouseShown := FALSE; T.HideMouse;
-  REPEAT
-    PollProgram;
-    IF terminalNeedRedraw THEN T.Flush; terminalNeedRedraw := FALSE END;
-    T.WaitEvent(E);
-    IF E.type = T.timer THEN
-    ELSIF E.type = T.key THEN HandleTerminalKeyDown(E, quit)
-    ELSIF E.type = T.quit THEN KillProgram
-    ELSIF E.type = T.mouse THEN
-      IF E.button # 0 THEN T.ShowMouse END
-    END;
-    IF terminalNeedRedraw THEN T.Flush; terminalNeedRedraw := FALSE END
-  UNTIL quit;
-  IF ~terminalMouseShown THEN T.ShowMouse END
-END RunTerminal;
-
-PROCEDURE RunProgram(IN prg: ARRAY OF CHAR);
-VAR dir, err: ARRAY 256 OF CHAR;
-  s, d: ARRAY 2048 OF SHORTCHAR;
-  i: INTEGER;
-  tW, tH: INTEGER;
-BEGIN dir := prg$; curX := 0; curY := 0; curFg := 7; curBg := 0;
-  T.SetCursor(0, 0); T.Size(tW, tH);
-  i := 0; WHILE dir[i] # 0X DO INC(i) END;
-  WHILE (i # -1) & (dir[i] # '/') & (dir[i] # '\') DO DEC(i) END;
-  INC(i); dir[i] := 0X; Utf8.Encode(prg, s); Utf8.Encode(dir, d);
-  IF Term.StartProcessIn(s, d) THEN programFinished := FALSE; RunTerminal
-  ELSE FoStrings.GetErrorStr(423, err); ShowError(err)
-  END
-END RunProgram;
-
-(** Puts in dir part of string s, before the last '/'.
-    If there is no '/', dir is ''. *)
-PROCEDURE DirName(IN s: ARRAY OF CHAR; OUT dir: ARRAY OF CHAR);
-VAR i: INTEGER;
-BEGIN
-  i := 0; WHILE s[i] # 0X DO INC(i) END;
-  WHILE (i >= 0) & (s[i] # '/') DO DEC(i) END;
-  dir[i + 1] := 0X;
-  WHILE i >= 0 DO dir[i] := s[i]; DEC(i) END
-END DirName;
-
-PROCEDURE OpenFileOkClick(c: OV.Control; fname: ARRAY OF CHAR);
-BEGIN
-  DirName(fname, lastFileDialogDir);
-  DoOpenFile(fname)
-END OpenFileOkClick;
-
-PROCEDURE DoSaveFile(c: OV.Control; fname: ARRAY OF CHAR);
-VAR w: OV.Window; e: Editor.Editor;
-BEGIN
-  Debug.StrVal('DoSaveFile fname = ', fname);
-  IF fname[0] # 0X THEN w := c.app.windows;
-    IF (w # NIL) & (w IS Editor.Editor) THEN e := w(Editor.Editor);
-      IF e.text.SaveToFile(fname) THEN
-        e.fname := fname$;
-        FnameToCaption(fname, e.caption)
-      END
-    END
-  END
-END DoSaveFile;
-
-PROCEDURE FileOpen(c: OV.Control);
-VAR w: Editor.FileDialog;
-BEGIN
-  w := Editor.NewFileDialog(Editor.open, lastFileDialogDir);
-  w.onFileOk := OpenFileOkClick;
-  OV.AddWindow(app, w)
-END FileOpen;
-
-PROCEDURE FileReload(c: OV.Control);
-VAR e: Editor.Editor;
-BEGIN
-  IF (c.app.windows # NIL) & (c.app.windows IS Editor.Editor) THEN
-    e := c.app.windows(Editor.Editor);
-    IF e.fname[0] # 0X THEN
-      IF e.text.LoadFromFile(e.fname) THEN (*!FIXME*) END
-    END
-  END
-END FileReload;
-
-PROCEDURE FileSaveAs(c: OV.Control);
-VAR d: Editor.FileDialog;
-  w: OV.Window; e: Editor.Editor;
-BEGIN d := Editor.NewFileDialog(Editor.save, lastFileDialogDir);
-  d.onFileOk := DoSaveFile;
-  w := c.app.windows;
-  IF (w # NIL) & (w IS Editor.Editor) THEN e := w(Editor.Editor);
-    IF e.fname[0] # 0X THEN Editor.FileDialogSetFname(d, e.fname) END
-  END;
-  OV.AddWindow(app, d)
-END FileSaveAs;
-
-PROCEDURE FileSave(c: OV.Control);
-VAR w: OV.Window;
-BEGIN w := c.app.windows;
-  IF (w # NIL) & (w IS Editor.Editor) THEN
-    IF w(Editor.Editor).fname[0] = 0X THEN FileSaveAs(c)
-    ELSE DoSaveFile(c, w(Editor.Editor).fname)
-    END
-  END
-END FileSave;
-
-PROCEDURE SearchFind(c: OV.Control);
-VAR w, e: OV.Window;
-BEGIN e := c.app.windows;
-  IF (e # NIL) & (e IS Editor.Editor) THEN
-    w := Editor.NewSearchDialog(e(Editor.Editor));
-    OV.AddWindow(app, w)
-  END
-END SearchFind;
-
-PROCEDURE SearchAgain(c: OV.Control);
-VAR e: OV.Window;
-BEGIN e := c.app.windows;
-  IF (e # NIL) & (e IS Editor.Editor) THEN
-    Editor.SearchNext(e(Editor.Editor))
-  END
-END SearchAgain;
-
-PROCEDURE OptionsLanguage(c: OV.Control);
-VAR w: OV.Window;
-BEGIN
-  w := NewLanguageDialog();
-  OV.AddWindow(app, w)
-END OptionsLanguage;
-
-PROCEDURE BuildErrorCallback(IN fname: ARRAY OF CHAR;
-    col, line, error: INTEGER; IN msg: ARRAY OF CHAR);
-VAR e: Editor.Editor;
-BEGIN
-  IF fname[0] # 0X THEN
-    FocusOrOpenFile(fname);
-    e := app.windows(Editor.Editor);
-    IF (col >= 1) & (line >= 1) THEN
-      IF (col = 1) & (line # 1) THEN
-        e.text.MoveToLineCol(line - 1, 256, e.h - 2)
-      ELSE e.text.MoveToLineCol(line, col, e.h - 2)
-      END
-    END;
-    Editor.PrintText(app.windows(Editor.Editor))
-  END;
-  ShowError(msg)
-END BuildErrorCallback;
-
-PROCEDURE OnBuild(c: OV.Control);
-VAR w: OV.Window;
-  foreign: BOOLEAN;
-  mainFname, modname, exename, errFname, s: ARRAY 256 OF CHAR;
-  errLine, errCol, res: INTEGER;
-  modules: Builder.Module;
-  e: Editor.Editor;
-BEGIN w := c.app.windows;
-  IF (w # NIL) & (w IS Editor.Editor) THEN
-    IF Editor.TextChanged(w(Editor.Editor)) THEN FileSave(c) END;
-    IF w(Editor.Editor).fname[0] # 0X THEN
-      mainFname := w(Editor.Editor).fname$;
-      Debug.StrVal('File name of main module: ', mainFname);
-      Builder.SetWorkDir(mainFname);
-      Debug.StrVal('Work directory: ', Builder.workDir);
-      Builder.GetModuleName(mainFname, modname);
-      Debug.StrVal('Module name: ', modname);
-      modules := Builder.UsedModuleList(modname, mainFname,
-        errFname, errLine, errCol, foreign, res);
-      IF foreign THEN res := 402 END;
-      Debug.IntVal('Result of UserModuleList: ', res);
-      IF res = 0 THEN
-        IF Builder.CompileAll(modules, exename, FALSE, BuildErrorCallback)
-        THEN RunProgram(exename)
-        END
-      ELSE
-        FocusOrOpenFile(errFname);
-        e := app.windows(Editor.Editor);
-        e.text.MoveToLineCol(errLine, errCol, e.h - 2);
-        FoStrings.MakeErrorStr(res, s);
-        ShowError(s)
-      END
-    END
-  END
-END OnBuild;
-
-PROCEDURE HelpAbout(c: OV.Control);
-CONST W = 37; H = 13;
-VAR w: OV.Window; L: OV.Label; b: OV.Button;
-  s: FoStrings.String;
-  Y: INTEGER;
-  tW, tH: INTEGER;
-BEGIN w := OV.NewWindow(); w.modal := TRUE;
-  FoStrings.Get('titleAbout', w.caption);
-  T.Size(tW, tH);
-  w.do.resize(w, (tW - W) DIV 2, (tH - H) DIV 2, W, H);
-  Y := 2;
-
-  FoStrings.Get('titleFreeOberon', s);
-  L := OV.NewLabel(s); L.align := OV.center;
-  L.do.resize(L, 1, Y, W - 2, 1); OV.Add(w, L); INC(Y, 2);
-
-  FoStrings.Get('version', s); Strings.Append(' ', s);
-  Strings.Append(Config.version, s);
-  L := OV.NewLabel(s); L.align := OV.center;
-  L.do.resize(L, 1, Y, W - 2, 1); OV.Add(w, L); INC(Y, 2);
-
-  FoStrings.Get('copyright', s); Strings.Append(' 2017-', s);
-  Int.Append(Config.year, s); Strings.Append(' ', s);
-  FoStrings.Append('copyrightBy', s);
-  
-  L := OV.NewLabel(s); L.align := OV.center;
-  L.do.resize(L, 1, Y, W - 2, 1); OV.Add(w, L); INC(Y, 2);
-
-  FoStrings.Get('authorName', s); Strings.Append(', free.oberon.org', s);
-  L := OV.NewLabel(s); L.align := OV.center;
-  L.do.resize(L, 1, Y, W - 2, 1); OV.Add(w, L); INC(Y, 2);
-
-  FoStrings.Get('btnOk', s);
-  b := OV.NewButton(s); b.default := TRUE;
-  b.do.resize(b, (W - 8) DIV 2, Y, 8, 1); OV.Add(w, b); INC(Y, 2);
-  b.onClick := OV.CloseCurWindow;
-
-  OV.AddWindow(app, w);
-  OV.SetFocus(b)
-END HelpAbout;
-
-PROCEDURE TileWindows*(c: OV.Control);
-VAR W, E: OV.Control;
-  count, cols, rows, i, col, x, y, w, h, w2, h2: INTEGER;
-  aw, ah, dw, dh: INTEGER; (* Accumulator, delta *)
-  tW, tH: INTEGER;
-BEGIN E := app.windows; count := 0;
-  T.Size(tW, tH);
-  IF E # NIL THEN W := E.next;
-    WHILE W # NIL DO
-      INC(count);
-      IF W = E THEN W := NIL ELSE W := W.next END
-    END;
-    IF count < 4 THEN rows := 1
-    ELSIF count < 9 THEN rows := 2
-    ELSE rows := 3
-    END;
-    cols := count DIV rows; col := 1;
-
-    x := 0; y := 1;
-    w := tW DIV cols; w2 := w;
-    dw := tW MOD cols;
-    h := (tH - 2) DIV rows;
-    dh := (tH - 2) MOD rows;
-    IF h < 2 THEN h := 2; dh := 0 END;
-    aw := dw; ah := 0;
-    W := E.next; i := 0;
-    WHILE W # NIL DO
-      INC(ah, dh);
-      IF ah < rows THEN h2 := h ELSE h2 := h + 1; DEC(ah, rows) END;
-      OV.WindowResize(W, x, y, w2, h2);
-      IF W = E THEN W := NIL ELSE W := W.next END;
-      INC(y, h2); INC(i);
-      IF (i = rows) & (col < cols) THEN (* New column *)
-        i := 0; INC(col); INC(x, w2); y := 1; ah := 0;
-        INC(aw, dw);
-        IF aw < cols THEN w2 := w ELSE w2 := w + 1; DEC(aw, cols) END;
-        IF col = cols THEN (* Last column *)
-          rows := count - rows * (cols - 1);
-          w := tW - x;
-          h := (tH - 2) DIV rows;
-          dh := (tH - 2) MOD rows;
-          IF h < 2 THEN h := 2; dh := 0 END
-        END
-      END
-    END
-  END
-END TileWindows;
-
-PROCEDURE CascadeWindows*(c: OV.Control);
-VAR W, E: OV.Control;
-  x, y, w, h: INTEGER;
-  tW, tH: INTEGER;
-BEGIN E := app.windows;
-  T.Size(tW, tH);
-  x := 0; y := 1; w := tW; h := tH - 2;
-  IF E # NIL THEN W := E.next;
-    WHILE W # NIL DO
-      OV.WindowResize(W, x, y, w, h);
-      INC(x); INC(y); DEC(w); DEC(h);
-      IF (w < 10) OR (h < 3) THEN
-        x := 0; y := 1; w := tW; h := tH - 2
-      END;
-      IF W = E THEN W := NIL ELSE W := W.next END
-    END
-  END
-END CascadeWindows;
-
-PROCEDURE FixClipboardText(VAR s: ARRAY OF CHAR);
-CONST CR = 0DX; LF = 0AX;
-VAR i, j: INTEGER;
-BEGIN
-  i := 0; WHILE (i # LEN(s)) & (s[i] # 0X) & (s[i] # CR) DO INC(i) END;
-  j := i;
-  WHILE (i # LEN(s)) & (s[i] # 0X) DO
-    IF s[i] = CR THEN INC(i);
-      IF i # LEN(s) THEN
-        IF s[i] # LF THEN s[j] := LF; INC(j) END
-      END
-    ELSE s[j] := s[i]; INC(i); INC(j)
-    END
-  END;
-  s[j] := 0X
-END FixClipboardText;
-
-PROCEDURE EditPasteClipboard*(c: OV.Control);
-VAR e: Editor.Editor;
-  s: ARRAY 50000 OF CHAR;
-BEGIN
-  IF (c.app.windows # NIL) & (c.app.windows IS Editor.Editor) THEN
-    Graph.GetClipboardText(T.GetWindow(), s);
-    FixClipboardText(s);
-    Editor.PasteText(app, s)
-  END
-END EditPasteClipboard;
-
-PROCEDURE EditCopyClipboard*(c: OV.Control);
-VAR s: ARRAY 50000 OF CHAR;
-BEGIN
-  IF (c.app.windows # NIL) & (c.app.windows IS Editor.Editor) THEN
-    c.app.windows(Editor.Editor).text.CopySelection(s);
-    Graph.SetClipboardText(T.GetWindow(), s)
-  END
-END EditCopyClipboard;
-
-PROCEDURE EditCutClipboard*(c: OV.Control);
-BEGIN
-  IF (c.app.windows # NIL) & (c.app.windows IS Editor.Editor) THEN
-    EditCopyClipboard(c);
-    Editor.EditClear(c.app.windows(Editor.Editor))
-  END
-END EditCutClipboard;
-
-PROCEDURE OnResize(w, h: INTEGER);
-VAR o, br: OV.Window;
-BEGIN
-  o := app.windows; br := o;
-  REPEAT
-    IF (o.w = lastW) & (o.h = lastH - 2) & (o.x = 0) & (o.y = 1) THEN
-      o.x := 0; o.y := 1; o.w := w; o.h := h - 2
-    END;
-    o := o.next(OV.Window)
-  UNTIL o = br;
-  lastW := w; lastH := h
-END OnResize;
-
-PROCEDURE InitIDE;
-VAR w: OV.Window;
-  m, m2: OV.Menu;
-  s, q: FoStrings.String;
-BEGIN
-  app := OV.NewApp();
-  T.Size(lastW, lastH);
-  OV.SetOnResize(app, OnResize);
-  FileNew(app.menu);
-
-  FoStrings.Get('menuFile', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuNew', s);
-  OV.Add(m, OV.NewMenu(s, 'Shift+F3', OV.hShiftF3, FileNew));
-  FoStrings.Get('menuOpen', s);
-  OV.Add(m, OV.NewMenu(s, 'F3', OV.hF3, FileOpen));
-  FoStrings.Get('menuReload', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, FileReload));
-  FoStrings.Get('menuSave', s);
-  OV.Add(m, OV.NewMenu(s, 'F2', OV.hF2, FileSave));
-  FoStrings.Get('menuSaveAs', s);
-  OV.Add(m, OV.NewMenu(s, 'Shift+F2', OV.hShiftF2, FileSaveAs));
-  (*FoStrings.Get('menuSaveAll', s);*)
-  (*OV.Add(m, OV.NewMenu(s, '', 0, NIL));*)
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuExit', s);
-  OV.Add(m, OV.NewMenu(s, 'Alt+X', OV.hAltX, OV.QuitApp));
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuEdit', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuUndo', s);
-  FoStrings.Get('actionDelText', q);
-  m2 := OV.NewMenu(s, q, OV.hAltBackspace, NIL); m2.status := OV.disabled;
-  OV.Add(m, m2);
-  FoStrings.Get('menuRedo', s);
-  m2 := OV.NewMenu(s, '', 0, NIL); m2.status := OV.disabled;
-  OV.Add(m, m2);
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuCut', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+X', OV.hCtrlX, EditCutClipboard));
-  FoStrings.Get('menuCopy', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+C', OV.hCtrlC, EditCopyClipboard));
-  FoStrings.Get('menuPaste', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+V', OV.hCtrlV, EditPasteClipboard));
-  FoStrings.Get('menuClear', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+Del', OV.hCtrlDel, Editor.EditClear));
-  FoStrings.Get('menuSelectAll', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+A', OV.hCtrlA, Editor.EditSelectAll));
-  FoStrings.Get('menuUnselect', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, Editor.EditUnselect));
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuCutInternal', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+Shift+X', OV.hCtrlShiftX, Editor.EditCut));
-  FoStrings.Get('menuCopyInternal', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+Shift+C', OV.hCtrlShiftC, Editor.EditCopy));
-  FoStrings.Get('menuPasteInternal', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+Shift+V', OV.hCtrlShiftV, Editor.EditPaste));
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuSearch', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuFind', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+F', OV.hCtrlF, SearchFind));
-  FoStrings.Get('menuReplace', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuSearchAgain', s);
-  OV.Add(m, OV.NewMenu(s, 'F12', OV.hF12, SearchAgain));
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuGoToLineNumber', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuFindProcedure', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuRun', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuRunRun', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+F9', OV.hCtrlF9, OnBuild));
-  FoStrings.Get('menuRunDirectory', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuParameters', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuCompile', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  OV.Add(m, OV.NewMenu(s, 'Alt+F9', OV.hAltF9, OnBuild));
-  FoStrings.Get('menuMake', s);
-  OV.Add(m, OV.NewMenu(s, 'Shift+F9', OV.hShiftF9, OnBuild));
-  FoStrings.Get('menuMakeAndRun', s);
-  OV.Add(m, OV.NewMenu(s, 'F9', OV.hF9, OnBuild));
-  FoStrings.Get('menuBuild', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, OnBuild));
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuDebug', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuOutput', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuTools', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuMessages', s);
-  OV.Add(m, OV.NewMenu(s, 'F11', OV.hF11, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuCalculator', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuAsciiTable', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuOptions', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuMode', s);
-  FoStrings.Get('menuNormalMode', q);
-  OV.Add(m, OV.NewMenu(s, q, 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuLanguage', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, OptionsLanguage));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuCompiler', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuMemorySizes', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuLinker', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuDirectories', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuTools', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuEnvironment', s);
-  m2 := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuPreferences', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  FoStrings.Get('menuEditor', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  FoStrings.Get('menuCodeComplete', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  FoStrings.Get('menuCodeTemplates', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  FoStrings.Get('menuDesktop', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  FoStrings.Get('menuKeyboardAndMouse', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  FoStrings.Get('menuLearnKeys', s);
-  OV.Add(m2, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m2.children.prev.status := OV.disabled;
-  OV.Add(m, m2);
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuOpenOptions', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuSaveOptions', s);
-  OV.Add(m, OV.NewMenu(s, 'fo.ini', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuSaveOptionsAs', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuWindow', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuTile', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, TileWindows));
-  FoStrings.Get('menuCascade', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, CascadeWindows));
-  FoStrings.Get('menuCloseAll', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, OV.CloseAllWindows));
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuSizeMove', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+F5', OV.hCtrlF5, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuZoom', s);
-  OV.Add(m, OV.NewMenu(s, 'F5', OV.hF5, OV.ZoomCurWindow));
-  FoStrings.Get('menuNextWindow', s);
-  OV.Add(m, OV.NewMenu(s, 'F6', OV.hF6, OV.NextWindow));
-  FoStrings.Get('menuPreviousWindow', s);
-  OV.Add(m, OV.NewMenu(s, 'Shift+F6', OV.hShiftF6, OV.PrevWindow));
-  FoStrings.Get('menuCloseWindow', s);
-  OV.Add(m, OV.NewMenu(s, 'Alt+F3', OV.hAltF3, OV.CloseCurWindow));
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuListWindows', s);
-  OV.Add(m, OV.NewMenu(s, 'Alt+0', OV.hAlt0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuRefreshDisplay', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, OV.RefreshDisplay));
-  OV.AddMenu(app, m);
-  FoStrings.Get('menuHelp', s);
-  m := OV.NewMenu(s, '', 0, NIL);
-  FoStrings.Get('menuContents', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuIndex', s);
-  OV.Add(m, OV.NewMenu(s, 'Shift+F1', OV.hShiftF1, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuTopicSearch', s);
-  OV.Add(m, OV.NewMenu(s, 'Ctrl+F1', OV.hCtrlF1, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuPreviousTopic', s);
-  OV.Add(m, OV.NewMenu(s, 'Alt+F1', OV.hAltF1, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuUsingHelp', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  FoStrings.Get('menuHelpFiles', s);
-  OV.Add(m, OV.NewMenu(s, '', 0, NIL));
-  (*!TODO*) m.children.prev.status := OV.disabled;
-  OV.Add(m, OV.NewMenu('-', '', 0, NIL));
-  FoStrings.Get('menuAbout', s);
-  OV.Add(m, OV.NewMenu(s, '', OV.hF1, HelpAbout));
-  OV.AddMenu(app, m);
-
-  FoStrings.Get('btnHelp', s);
-  OV.AddStatusbar(app, OV.NewQuickBtn(s, 'F1', 0, HelpAbout));
-  FoStrings.Get('btnSave', s);
-  OV.AddStatusbar(app, OV.NewQuickBtn(s, 'F2', 0, FileSave));
-  FoStrings.Get('btnOpen', s);
-  OV.AddStatusbar(app, OV.NewQuickBtn(s, 'F3', 0, FileOpen));
-  FoStrings.Get('btnCompileAndRun', s);
-  OV.AddStatusbar(app, OV.NewQuickBtn(s, 'F9', 0, OnBuild));
-  FoStrings.Get('btnLocalMenu', s);
-  OV.AddStatusbar(app, OV.NewQuickBtn(s, 'Alt+F10', 0, NIL))
-END InitIDE;
-
-PROCEDURE OpenFiles(VAR fnames: Fnames);
-VAR i: INTEGER;
-BEGIN i := 0;
-  WHILE (i < LEN(fnames)) & (fnames[i] # '') DO
-    DoOpenFile(fnames[i]); INC(i)
-  END;
-  IF i # 0 THEN OV.NextWindow(app.windows) END
-END OpenFiles;
-
-PROCEDURE ParseFileNameArg(VAR s: ARRAY OF CHAR);
-VAR L: INTEGER;
-  found: BOOLEAN;
-BEGIN
-  (* Replace all \ with / and set L to length of s *)
-  L := 0; found := FALSE;
-  WHILE s[L] # 0X DO
-    IF (s[L] = '\') OR (s[L] = '/') THEN s[L] := '/'; found := TRUE END;
-    INC(L)
-  END;
-
-  IF ~found THEN
-    IF (L < 4) OR (Strings.Pos('.Mod', s, L - 4) = -1) THEN
-      Strings.Append('.Mod', s)
-    END;
-    (*!FIXME first check if file not exists: *)
-    Strings.Insert(Config.stdPath, 0, s)
-  END
-END ParseFileNameArg;
-
-PROCEDURE ParseSize(IN s: ARRAY OF CHAR; VAR w, h: INTEGER);
-VAR i: INTEGER;
-  x: ARRAY 30 OF CHAR;
-BEGIN i := 0; w := 0; h := 0;
-  WHILE (s[i] # 0X) & (s[i] # 'x') DO INC(i) END;
-  Strings.Extract(s, 0, i, x); w := Int.Val(x);
-  Strings.Extract(s, i + 1, 30, x); h := Int.Val(x)
-END ParseSize;
-
-PROCEDURE IdentifyLanguage(VAR lang: ARRAY OF CHAR);
-BEGIN
-  Env.GetLang(lang); lang[2] := 0X;
-  IF ~FoStrings.LangExists(lang) THEN lang := defLang END
-END IdentifyLanguage;
-
-PROCEDURE ParseArgs(VAR fs, sw: BOOLEAN; VAR w, h: INTEGER;
-    VAR lang: ARRAY OF CHAR; VAR fnames: Fnames);
-VAR i, nofnames, count: INTEGER;
-  s: ARRAY 2048 OF CHAR;
-BEGIN fs := Config.startInFullscreen; sw := FALSE; i := 1;
-  nofnames := 0; w := defW; h := defH; lang := ''; count := Args.Count();
-  WHILE i <= count DO Args.Get(i, s);
-    IF s = '--window' THEN fs := FALSE
-    ELSIF s = '--fullscreen' THEN fs := TRUE
-    ELSIF s = '--software' THEN sw := TRUE
-    ELSIF s = '--debug' THEN Config.SetDebug(TRUE)
-    ELSIF s = '--size' THEN
-      IF i # count THEN INC(i); Args.Get(i, s); ParseSize(s, w, h) END
-    ELSIF s = '--lang' THEN
-      IF i # count THEN
-        INC(i); Args.Get(i, lang);
-        IF ~FoStrings.LangExists(lang) THEN Out.String('Language "');
-          Out.String(lang); Out.String('" does not exist.'); Out.Ln;
-          lang := ''
-        END
-      END
-    ELSIF nofnames < LEN(fnames) THEN
-      ParseFileNameArg(s);
-      fnames[nofnames] := s$;
-      INC(nofnames)
-    ELSE Out.String('Too many files.'); Out.Ln
-    END;
-    INC(i)
-  END;
-  IF nofnames < LEN(fnames) THEN fnames[nofnames][0] := 0X END;
-  IF lang = '' THEN IdentifyLanguage(lang) END
-END ParseArgs;
-
-PROCEDURE Init(): BOOLEAN;
-VAR success, fs, sw: BOOLEAN;
-  w, h: INTEGER;
-  lang: ARRAY 6 OF CHAR;
-  s: FoStrings.String;
-  fnames: Fnames;
-  opt: SET;
-BEGIN
-  success := FALSE;
-  lastFileDialogDir[0] := 0X;
-  ParseArgs(fs, sw, w, h, lang, fnames);
-  opt := {T.resizable, T.center};
-  IF fs THEN INCL(opt, T.fullscreen) ELSE INCL(opt, T.window) END;
-  T.Settings(w, h, opt);
-  FoStrings.SetLang(lang);
-  FoStrings.Get('titleFreeOberon', s);
-  T.SetTitle(s);
-  T.Init;
-  IF T.Done THEN
-    InitIDE;
-    OpenFiles(fnames);
-    success := TRUE
-  ELSE Out.String('Terminal init failed.'); Out.Ln
-  END ;
-RETURN success END Init;
-
-BEGIN
-  IF ~Init() THEN Out.String('Could not initialize.'); Out.Ln
-  ELSE OV.RunApp(app)
-  END;
-  T.Close
-END FreeOberon.