2
0

FreeOberon.Mod 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. MODULE FreeOberon;
  2. (* Copyright 2017-2020 Arthur Yefimov
  3. This file is part of Free Oberon.
  4. Free Oberon is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Free Oberon is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Free Oberon. If not, see <http://www.gnu.org/licenses/>.
  14. *)
  15. IMPORT G := Graph, T := Terminal, Files, Modules,
  16. OV, Editor, Term, Config, Strings, Out, Signals;
  17. CONST
  18. version* = '1.0.4'; (*Allegro4 branch*)
  19. (* Direction of Selection *)
  20. dirLeft = 0;
  21. dirRight = 1;
  22. dirUp = 2;
  23. dirDown = 3;
  24. (* States *)
  25. stateEditor = 0;
  26. stateTerminal = 1;
  27. (* Token Classes *)
  28. tokenOther = 0;
  29. tokenKeyword = 1;
  30. tokenNumber = 2;
  31. tokenString = 3;
  32. tokenComment = 4;
  33. TYPE
  34. StrList = POINTER TO StrListDesc;
  35. StrListDesc = RECORD
  36. s: ARRAY 256 OF CHAR;
  37. next: StrList
  38. END;
  39. Fnames = ARRAY 32, 256 OF CHAR;
  40. VAR
  41. progBuf: ARRAY 16300 OF CHAR; (* For interacting with a launched program *)
  42. inputBuf: ARRAY 16300 OF CHAR; (* Saves entered characters before Enter is pressed *)
  43. inputBufLen: INTEGER;
  44. programFinished: BOOLEAN;
  45. tempWindowed: BOOLEAN; (* True if editor is in windowed mode while program is running *)
  46. needWindowed: BOOLEAN;
  47. sysModules: StrList;
  48. app: OV.App;
  49. PROCEDURE IntToStr*(n: INTEGER; VAR s: ARRAY OF CHAR); (* !TODO move out *)
  50. (* LEN(s) > 1 *)
  51. VAR i, j: INTEGER; tmp: CHAR; neg: BOOLEAN;
  52. BEGIN
  53. IF n = 0 THEN
  54. s[0] := '0'; i := 1
  55. ELSE i := 0; neg := n < 0;
  56. IF neg THEN n := -n END;
  57. WHILE (n > 0) & (i < LEN(s) - 1) DO
  58. s[i] := CHR(ORD('0') + n MOD 10);
  59. n := n DIV 10; INC(i)
  60. END;
  61. IF neg & (i < LEN(s) - 1) THEN s[i] := '-'; INC(i) END
  62. END;
  63. s[i] := 0X; j := 0; DEC(i);
  64. WHILE j < i DO
  65. tmp := s[j]; s[j] := s[i]; s[i] := tmp;
  66. INC(j); DEC(i)
  67. END
  68. END IntToStr;
  69. PROCEDURE CountLines(s: ARRAY OF CHAR; width: INTEGER): INTEGER;
  70. VAR i, x, lines: INTEGER;
  71. BEGIN
  72. i := 0; x:= 0; lines := 1;
  73. WHILE s[i] # 0X DO
  74. IF s[i] = 0AX THEN
  75. INC(lines); x := 0
  76. ELSIF s[i] # 0DX THEN
  77. IF x = width - 1 THEN INC(lines); x := 0
  78. ELSE INC(x)
  79. END
  80. END;
  81. INC(i)
  82. END;
  83. RETURN lines END CountLines;
  84. PROCEDURE ShowErrors(s: ARRAY OF CHAR);
  85. VAR lines, width, x0, x, y, i: INTEGER;
  86. BEGIN
  87. width := T.charsX - 2;
  88. lines := CountLines(s, width);
  89. IF lines > 10 THEN lines := 10 END;
  90. i := 0; x0 := 1; x := x0;
  91. y := T.charsY - 2 - lines;
  92. WHILE (s[i] # 0X) & (y < T.charsY - 2) DO
  93. IF s[i] = 0AX THEN
  94. WHILE x < x0 + width DO (* Till end of line *)
  95. T.PutChar(x, y, ' ', 0, 3); INC(x)
  96. END;
  97. x := x0; INC(y)
  98. ELSIF s[i] # 0DX THEN
  99. T.PutChar(x, y, s[i], 0, 3);
  100. IF x = x0 + width - 1 THEN INC(y); x := x0
  101. ELSE INC(x)
  102. END
  103. END;
  104. INC(i)
  105. END;
  106. IF x > x0 THEN
  107. WHILE x < x0 + width DO
  108. T.PutChar(x, y, ' ', 0, 3); INC(x)
  109. END
  110. END;
  111. IF T.Draw() THEN G.Flip; G.Pause END (*!FIXME*)
  112. END ShowErrors;
  113. PROCEDURE StringsFindNext* (pattern, stringToSearch: ARRAY OF CHAR; startPos: INTEGER;
  114. VAR patternFound: BOOLEAN; VAR posOfPattern: INTEGER); (* !TODO move out *)
  115. VAR patternPos: INTEGER;
  116. BEGIN
  117. IF (startPos < Strings.Length (stringToSearch)) THEN
  118. patternPos := 0;
  119. LOOP
  120. IF (pattern[patternPos] = 0X) THEN
  121. (* reached end of pattern *)
  122. patternFound := TRUE;
  123. posOfPattern := startPos - patternPos;
  124. EXIT
  125. ELSIF (stringToSearch[startPos] = 0X) THEN
  126. (* end of string (but not of pattern) *)
  127. patternFound := FALSE;
  128. EXIT
  129. ELSIF (stringToSearch[startPos] = pattern[patternPos]) THEN
  130. (* characters identic, compare next one *)
  131. INC (startPos);
  132. INC (patternPos)
  133. ELSE
  134. (* difference found: reset indices and restart *)
  135. DEC(startPos, patternPos - 1);
  136. patternPos := 0
  137. END
  138. END
  139. ELSE patternFound := FALSE
  140. END
  141. END StringsFindNext;
  142. PROCEDURE FileNew(c: OV.Control);
  143. VAR e: Editor.Editor;
  144. p, br: OV.Control;
  145. count: INTEGER;
  146. BEGIN e := Editor.NewEditor();
  147. p := app.windows; br := p; count := 0;
  148. WHILE p # NIL DO INC(count);
  149. IF p.next = br THEN p := NIL ELSE p := p.next END
  150. END;
  151. IF app.windows # NIL THEN
  152. e.x := app.windows.x + 1; e.y := app.windows.y + 1;
  153. e.w := app.windows.w; e.h := app.windows.h;
  154. IF e.x + e.w >= T.charsX THEN e.w := T.charsX - e.x END;
  155. IF e.y + e.h >= T.charsY - 1 THEN e.h := T.charsY - e.y - 1 END;
  156. IF (e.w < 10) OR (e.h < 3) THEN
  157. e.x := 0; e.y := 1; e.w := T.charsX; e.h := T.charsY - 2
  158. END
  159. END;
  160. e.caption := 'NONAME??.Mod';
  161. e.caption[6] := CHR(ORD('0') + count DIV 10 MOD 10);
  162. e.caption[7] := CHR(ORD('0') + count MOD 10);
  163. OV.AddWindow(app, e)
  164. END FileNew;
  165. PROCEDURE DoOpenFile(filename: ARRAY OF CHAR);
  166. VAR e: Editor.Editor; newWin: BOOLEAN;
  167. BEGIN
  168. IF (app.windows # NIL) & (app.windows IS Editor.Editor) THEN
  169. e := app.windows(Editor.Editor)
  170. ELSE e := NIL
  171. END;
  172. newWin := (e = NIL) OR ~Editor.IsEmpty(e);
  173. IF newWin THEN e := Editor.NewEditor() END;
  174. IF e.text.LoadFromFile(filename) THEN
  175. e.caption := filename; e.filename := filename;
  176. IF newWin THEN OV.AddWindow(app, e) END
  177. END
  178. END DoOpenFile;
  179. PROCEDURE FocusOrOpenFile(filename: ARRAY OF CHAR);
  180. VAR e, f: Editor.Editor;
  181. BEGIN
  182. e := app.windows(Editor.Editor); f := e;
  183. WHILE (e # NIL) & (e.filename # filename) DO
  184. IF e.next = f THEN e := NIL ELSE e := e.next(Editor.Editor) END
  185. END;
  186. IF e = NIL THEN DoOpenFile(filename)
  187. ELSE app.windows := e; OV.SetFocus(app, e)
  188. END;
  189. OV.DrawApp(app)
  190. END FocusOrOpenFile;
  191. PROCEDURE ParseErrors(VAR s: ARRAY OF CHAR; filename: ARRAY OF CHAR);
  192. VAR i, j, pos, st, len, skip: INTEGER; found: BOOLEAN;
  193. BEGIN
  194. StringsFindNext(' pos ', s, 0, found, i);
  195. IF found THEN (* Read the position *)
  196. WHILE (s[i] # 0X) & ((s[i] < '0') OR (s[i] > '9')) DO INC(i) END;
  197. IF (s[i] >= '0') & (s[i] <= '9') THEN
  198. pos := 0;
  199. REPEAT pos := pos * 10 + ORD(s[i]) - ORD('0'); INC(i)
  200. UNTIL (s[i] < '0') OR (s[i] > '9');
  201. (* Skip spaces before 'err' *)
  202. WHILE s[i] = ' ' DO INC(i) END;
  203. IF s[i] = 'e' THEN (* Assume 'err' reached *)
  204. skip := 3; (* Skip 3 characters *)
  205. WHILE (skip > 0) & (s[i] # 0X) DO INC(i); DEC(skip) END;
  206. WHILE s[i] = ' ' DO INC(i) END; (* Skip spaces *)
  207. WHILE (s[i] >= '0') & (s[i] <= '9') DO INC(i) END; (* Skip numbers *)
  208. WHILE s[i] = ' ' DO INC(i) END; (* Skip spaces *)
  209. s[0] := ' '; j := 1;
  210. WHILE s[i] >= ' ' DO s[j] := s[i]; INC(i); INC(j) END;
  211. (* Remove trailing spaces *)
  212. WHILE (j > 0) & (s[j - 1] = ' ') DO DEC(j) END;
  213. s[j] := '.'; INC(j); s[j] := 0X;
  214. (* Capitalize first letter (0th is a space). *)
  215. IF (s[1] >= 'a') & (s[1] <= 'z') THEN s[1] := CAP(s[1]) END;
  216. FocusOrOpenFile(filename);
  217. app.windows(Editor.Editor).text.MoveToPos(pos);
  218. Editor.PrintText(app.windows(Editor.Editor));
  219. T.ResetCursorBlink (* !FIXME *)
  220. END
  221. END
  222. END
  223. END ParseErrors;
  224. PROCEDURE HandleMouseMotion(x, y: INTEGER);
  225. VAR newX, newY: INTEGER;
  226. BEGIN
  227. newX := x DIV T.charW; newY := y DIV T.charH;
  228. IF (newX # T.mouseX) OR (newY # T.mouseY) THEN T.MouseXY(newX, newY) END
  229. END HandleMouseMotion;
  230. PROCEDURE PollProgram;
  231. VAR len, i: INTEGER;
  232. err: INTEGER;
  233. s, sN: ARRAY 120 OF CHAR;
  234. PROCEDURE WriteProgBuf;
  235. VAR ch: CHAR; i: INTEGER;
  236. BEGIN
  237. i := 0;
  238. WHILE i < len DO
  239. ch := progBuf[i];
  240. IF ch = 0D0X THEN
  241. INC(i); ch := progBuf[i];
  242. IF ch = 081X THEN ch := CHR(240) (* Big Yo *)
  243. ELSE ch := CHR(ORD(ch) - 16)
  244. END
  245. ELSIF ch = 0D1X THEN
  246. INC(i); ch := CHR(ORD(progBuf[i]) + 96)
  247. ELSIF ch >= 080X THEN ch := '?'
  248. END;
  249. T.Write(ch); INC(i)
  250. END
  251. END WriteProgBuf;
  252. PROCEDURE Read(tillEnd: BOOLEAN);
  253. VAR loopLimit: INTEGER;
  254. BEGIN
  255. loopLimit := 5;
  256. REPEAT
  257. Term.ReadFromProcess(progBuf, len, LEN(progBuf));
  258. IF len > 0 THEN
  259. IF inputBufLen > 0 THEN
  260. FOR i := 0 TO inputBufLen - 1 DO T.Backspace END;
  261. inputBufLen := 0
  262. END;
  263. WriteProgBuf
  264. END;
  265. DEC(loopLimit)
  266. UNTIL (len <= 0) OR (loopLimit <= 0) & ~tillEnd
  267. END Read;
  268. BEGIN
  269. IF ~programFinished THEN
  270. IF Term.ProcessFinished(err) THEN
  271. Read(TRUE); (* Read everything until pipe is empty *)
  272. programFinished := TRUE;
  273. IF tempWindowed THEN G.SwitchToFullscreen END;
  274. IF err = 0 THEN
  275. T.WriteString(' Press any key to return to IDE')
  276. ELSE
  277. s := ' Runtime error ';
  278. IntToStr(err, sN); Strings.Append(sN, s);
  279. T.WriteString(s)
  280. END
  281. ELSE
  282. Read(FALSE) (* Attempt several reads *)
  283. END
  284. END
  285. END PollProgram;
  286. PROCEDURE WriteToProcess(s: ARRAY OF CHAR; len: INTEGER);
  287. VAR buf: ARRAY 2048 OF CHAR; i, bufLen: INTEGER; ch: CHAR;
  288. BEGIN
  289. bufLen := 0; i := 0;
  290. WHILE i < len DO
  291. ch := s[i];
  292. IF ch < 80X THEN
  293. buf[bufLen] := ch; INC(bufLen)
  294. ELSIF ORD(ch) = 240 THEN (* Big cyrillic Yo *)
  295. buf[bufLen] := 0D0X; buf[bufLen + 1] := 81X;
  296. INC(bufLen, 2)
  297. ELSIF ORD(ch) < 224 THEN (* Before small cyrillic R *)
  298. buf[bufLen] := 0D0X;
  299. buf[bufLen + 1] := CHR(ORD(ch) - 128 + 090H);
  300. INC(bufLen, 2)
  301. ELSE
  302. buf[bufLen] := 0D1X;
  303. buf[bufLen + 1] := CHR(ORD(ch) - 224 + 080H);
  304. INC(bufLen, 2)
  305. END;
  306. INC(i)
  307. END;
  308. Term.WriteToProcess(buf, bufLen)
  309. END WriteToProcess;
  310. PROCEDURE HandleTerminalKeyDown(key: G.Key; VAR quit: BOOLEAN);
  311. VAR code: INTEGER; ch: CHAR; buf: ARRAY 2 OF CHAR;
  312. BEGIN
  313. IF programFinished THEN
  314. IF (key.code = G.kEnter) & (key.mod * G.mAlt # {}) THEN
  315. T.ToggleFullscreen
  316. ELSIF (key.code # G.kAlt) & (key.code # G.kAltGr) THEN quit := TRUE
  317. END
  318. ELSE
  319. CASE key.code OF
  320. G.kEnter, G.kEnterPad:
  321. IF key.mod * G.mAlt # {} THEN T.ToggleFullscreen
  322. ELSE T.Ln;
  323. WriteToProcess(inputBuf, inputBufLen);
  324. inputBufLen := 0; buf[0] := 0AX;
  325. Term.WriteToProcess(buf, 1)
  326. END
  327. | G.kBackspace:
  328. IF inputBufLen > 0 THEN
  329. DEC(inputBufLen); T.Backspace
  330. END
  331. | G.kPause:
  332. IF G.CtrlPressed() THEN
  333. programFinished := TRUE;
  334. quit := TRUE (* !FIXME Kill the process *)
  335. END
  336. ELSE
  337. END
  338. END
  339. END HandleTerminalKeyDown;
  340. PROCEDURE HandleTerminalTextInput(key: G.Key);
  341. BEGIN
  342. IF (key.sym # 0) & (inputBufLen < LEN(inputBuf)) THEN
  343. inputBuf[inputBufLen] := CHR(key.sym); INC(inputBufLen);
  344. T.Write(CHR(key.sym))
  345. END
  346. END HandleTerminalTextInput;
  347. PROCEDURE RunTerminal;
  348. VAR event: G.Event; quit: BOOLEAN;
  349. BEGIN quit := FALSE;
  350. T.ClearScreen; T.GoToXY(0, 0);
  351. REPEAT
  352. G.WaitEvents(50);
  353. WHILE G.PollEvent(event) DO
  354. CASE event.type OF
  355. G.mouseMove: HandleMouseMotion(event.x, event.y)
  356. | G.keyDown: HandleTerminalKeyDown(event.key, quit)
  357. | G.textInput: HandleTerminalTextInput(event.key)
  358. | G.timer: T.Act
  359. ELSE
  360. END
  361. END;
  362. PollProgram;
  363. IF T.Draw() THEN G.Flip ELSE G.RepeatFlip END
  364. UNTIL quit
  365. END RunTerminal;
  366. PROCEDURE IsSysModule(name: ARRAY OF CHAR): BOOLEAN;
  367. VAR p: StrList;
  368. BEGIN p := sysModules;
  369. WHILE (p # NIL) & (p.s # name) DO p := p.next END;
  370. RETURN p # NIL END IsSysModule;
  371. PROCEDURE ModuleExists(s: ARRAY OF CHAR): BOOLEAN;
  372. VAR fname: ARRAY 250 OF CHAR;
  373. F: Files.File;
  374. exists: BOOLEAN;
  375. BEGIN
  376. fname := 'Programs/'; Strings.Append(s, fname);
  377. Strings.Append('.Mod', fname);
  378. F := Files.Old(fname);
  379. exists := F # NIL;
  380. IF F # NIL THEN Files.Close(F) END;
  381. RETURN exists END ModuleExists;
  382. PROCEDURE ExtModuleExists(s: ARRAY OF CHAR): BOOLEAN;
  383. VAR fname: ARRAY 250 OF CHAR;
  384. F: Files.File;
  385. exists: BOOLEAN;
  386. BEGIN
  387. fname := 'Programs/'; Strings.Append(s, fname);
  388. Strings.Append('/', fname); Strings.Append(s, fname);
  389. Strings.Append('.c', fname);
  390. F := Files.Old(fname);
  391. exists := F # NIL;
  392. IF F # NIL THEN Files.Close(F) END;
  393. RETURN exists END ExtModuleExists;
  394. PROCEDURE PrependPath(VAR mod: ARRAY OF CHAR; path: ARRAY OF CHAR);
  395. VAR i, j: INTEGER;
  396. BEGIN i := 0;
  397. WHILE (i < LEN(path)) & (path[i] # 0X) DO INC(i) END;
  398. WHILE (i >= 0) & (path[i] # '/') DO DEC(i) END;
  399. INC(i);
  400. IF i > 0 THEN j := 0;
  401. WHILE (j < LEN(mod)) & (mod[j] # 0X) DO INC(j) END;
  402. IF LEN(mod) >= i + j THEN
  403. WHILE j >= 0 DO mod[j + i] := mod[j]; DEC(j) END;
  404. j := 0;
  405. WHILE j < i DO mod[j] := path[j]; INC(j) END
  406. END
  407. END
  408. END PrependPath;
  409. PROCEDURE RemovePath(s: ARRAY OF CHAR; VAR res: ARRAY OF CHAR);
  410. VAR i: INTEGER;
  411. BEGIN i := 0;
  412. WHILE (i < LEN(s)) & (s[i] # 0X) DO INC(i) END;
  413. WHILE (i >= 0) & (s[i] # '/') DO DEC(i) END;
  414. IF i >= 0 THEN Strings.Extract(s, i + 1, 80, res)
  415. ELSE COPY(s, res)
  416. END
  417. END RemovePath;
  418. PROCEDURE RunCommand(filename: ARRAY OF CHAR;
  419. link, graph, main: BOOLEAN; list: StrList): BOOLEAN;
  420. CONST bufLen = 20480;
  421. VAR buf: ARRAY bufLen OF CHAR;
  422. p: StrList;
  423. len, err: INTEGER;
  424. command: ARRAY 32 OF CHAR;
  425. cmd: ARRAY 1024 OF CHAR;
  426. s, sN: ARRAY 80 OF CHAR;
  427. success: BOOLEAN;
  428. BEGIN
  429. IF ~link THEN command := 'compile'
  430. ELSIF graph THEN command := 'link_graph'
  431. ELSE command := 'link_console'
  432. END;
  433. IF Config.isWindows THEN
  434. IF Term.SearchPath('cmd.exe', cmd) # 0 THEN
  435. Strings.Insert('"', 0, cmd);
  436. Strings.Append('" /C data\bin\', cmd);
  437. Strings.Append(command, cmd);
  438. Strings.Append('.bat ', cmd)
  439. ELSE T.PutString(0, T.charsY - 1, 'Could not find cmd.exe', 15, 4, 0)
  440. END
  441. ELSE (* Linux *)
  442. COPY('data/bin/', cmd); Strings.Append(command, cmd);
  443. Strings.Append('.sh ', cmd)
  444. END;
  445. Strings.Append('Programs/', cmd);(*!FIXME*)
  446. Strings.Append(filename, cmd);
  447. IF main THEN Strings.Append(' -m', cmd)
  448. ELSIF link & (list # NIL) THEN
  449. p := list;
  450. WHILE p.next # NIL DO
  451. IF ModuleExists(p.s) THEN
  452. RemovePath(p.s, s); Strings.Append(' ', cmd);
  453. Strings.Append(s, cmd)
  454. END;
  455. p := p.next
  456. END
  457. END;
  458. Out.String('cmd=');Out.String(cmd);Out.Ln;(*!FIXME*)
  459. success := (Term.RunProcess(cmd, buf, bufLen, len, err) # 0) &
  460. (err = 0);
  461. IF ~success THEN
  462. s := ' Command returned ';
  463. IntToStr(err, sN); Strings.Append(sN, s);
  464. Strings.Append(' exit status ', s);
  465. IF (len > 0) & (len < bufLen) THEN
  466. IF buf[len - 1] = 0AX THEN buf[len - 1] := 0X
  467. ELSE buf[len] := 0X
  468. END;
  469. ParseErrors(buf, filename)
  470. ELSIF link THEN buf := 'Linking failed.'
  471. ELSE buf := 'Compilation failed.'
  472. END;
  473. IF buf[0] = 0X THEN ShowErrors(s)
  474. ELSE ShowErrors(buf)
  475. END
  476. END;
  477. RETURN success END RunCommand;
  478. PROCEDURE Compile(filename: ARRAY OF CHAR; main: BOOLEAN): BOOLEAN;
  479. BEGIN RETURN RunCommand(filename, FALSE, FALSE, main, NIL)
  480. END Compile;
  481. PROCEDURE Link(filename: ARRAY OF CHAR;
  482. graph: BOOLEAN; list: StrList): BOOLEAN;
  483. BEGIN RETURN RunCommand(filename, TRUE, graph, FALSE, list)
  484. END Link;
  485. PROCEDURE ResetSysModules;
  486. PROCEDURE Add(s: ARRAY OF CHAR);
  487. VAR p: StrList;
  488. BEGIN NEW(p); p.s := s; p.next := sysModules; sysModules := p
  489. END Add;
  490. BEGIN sysModules := NIL;
  491. Add('SYSTEM'); Add('Texts'); Add('Files'); Add('Strings');
  492. Add('In'); Add('Out'); Add('Math'); Add('MathL');
  493. Add('Modules'); Add('Platform'); Add('Oberon'); Add('Reals');
  494. Add('VT100'); Add('Graph'); Add('SDL2'); Add('Allegro');
  495. Add('Signals'); Add('Processes'); Add('Pthread'); Add('Semaphore');
  496. Add('Term')(*!FIXME Term?*)
  497. END ResetSysModules;
  498. PROCEDURE CompileAll(modules: StrList): BOOLEAN;
  499. VAR s: ARRAY 256 OF CHAR;
  500. p, last: StrList;
  501. ok, graph: BOOLEAN;
  502. BEGIN
  503. IF modules # NIL THEN
  504. ok := TRUE; p := modules; graph := FALSE;
  505. WHILE ok & (p.next # NIL) DO
  506. IF ModuleExists(p.s) THEN
  507. s := p.s; Strings.Append('.Mod', s);
  508. IF ~Compile(s, FALSE) THEN ok := FALSE END
  509. ELSIF IsSysModule(p.s) THEN
  510. IF p.s = 'Graph' THEN graph := TRUE END
  511. ELSE ok := FALSE
  512. END;
  513. p := p.next
  514. END;
  515. IF ok THEN
  516. IF ModuleExists(p.s) THEN
  517. s := p.s; Strings.Append('.Mod', s);
  518. IF ~Compile(s, TRUE) THEN ok := FALSE END
  519. END;
  520. IF ok & ~Link(p.s, graph, modules) THEN ok := FALSE END
  521. END
  522. ELSE ok := FALSE
  523. END;
  524. RETURN ok END CompileAll;
  525. PROCEDURE RunProgram(prg: ARRAY OF CHAR);
  526. VAR cmd, name, dir: ARRAY 256 OF CHAR;
  527. x: INTEGER;
  528. BEGIN
  529. (* Leave only "dir/d/Prg" from "dir/d/Prg.Mod" *)
  530. (* (or "Prg" from "Prg.Mod") *)
  531. x := Strings.Length(prg) - 1;
  532. WHILE (x > 0) & (prg[x] # ".") DO DEC(x) END;
  533. IF x > 0 THEN prg[x] := 0X END;
  534. (* Split "dir/d/Prg" to "dir/d" and "Prg" *)
  535. (* (or "Prg" to "" and "Prg") *)
  536. WHILE (x > 0) & (prg[x] # "/") DO DEC(x) END;
  537. IF x > 0 THEN
  538. Strings.Extract(prg, x + 1, 80, name);
  539. prg[x] := 0X
  540. ELSE COPY(prg, name); cmd[0] := 0X
  541. END;
  542. IF Config.isWindows THEN x := 0;
  543. WHILE prg[x] # 0X DO
  544. IF prg[x] = "/" THEN prg[x] := "\" END;
  545. INC(x)
  546. END
  547. END;
  548. dir := "Programs/";
  549. IF Config.isWindows THEN dir[Strings.Length(dir) - 1] := "\" END;
  550. Strings.Append(cmd, dir);
  551. IF ~Term.StartProcessDir(name, dir) THEN
  552. T.PutString(0, T.charsY - 1, " Program execution failed ", 15, 4, 0);
  553. IF T.Draw() THEN G.Flip; G.Pause END
  554. ELSE
  555. programFinished := FALSE;
  556. RunTerminal
  557. END
  558. END RunProgram;
  559. PROCEDURE OpenFileOkClick(c: OV.Control; filename: ARRAY OF CHAR);
  560. BEGIN DoOpenFile(filename)
  561. END OpenFileOkClick;
  562. PROCEDURE DoSaveFile(c: OV.Control; filename: ARRAY OF CHAR);
  563. VAR w: OV.Window; e: Editor.Editor;
  564. BEGIN
  565. IF filename[0] # 0X THEN w := c.app.windows;
  566. IF (w # NIL) & (w IS Editor.Editor) THEN e := w(Editor.Editor);
  567. IF e.text.SaveToFile(filename) THEN
  568. COPY(filename, e.caption); e.filename := filename
  569. END
  570. END
  571. END
  572. END DoSaveFile;
  573. PROCEDURE FileOpen(c: OV.Control);
  574. VAR w: Editor.FileDialog;
  575. BEGIN
  576. w := Editor.NewFileDialog(Editor.open);
  577. w.onFileOk := OpenFileOkClick;
  578. OV.AddWindow(app, w)
  579. END FileOpen;
  580. PROCEDURE FileReload(c: OV.Control);
  581. VAR e: Editor.Editor;
  582. BEGIN
  583. IF (c.app.windows # NIL) & (c.app.windows IS Editor.Editor) THEN
  584. e := c.app.windows(Editor.Editor);
  585. IF e.filename[0] # 0X THEN
  586. IF e.text.LoadFromFile(e.filename) THEN (*!FIXME*) END
  587. END
  588. END
  589. END FileReload;
  590. PROCEDURE FileSaveAs(c: OV.Control);
  591. VAR d: Editor.FileDialog;
  592. w: OV.Window; e: Editor.Editor;
  593. BEGIN d := Editor.NewFileDialog(Editor.save);
  594. d.onFileOk := DoSaveFile;
  595. w := c.app.windows;
  596. IF (w # NIL) & (w IS Editor.Editor) THEN e := w(Editor.Editor);
  597. IF e.filename[0] # 0X THEN
  598. OV.EditSetCaption(d.edtFilename, e.filename)
  599. END
  600. END;
  601. OV.AddWindow(app, d)
  602. END FileSaveAs;
  603. PROCEDURE FileSave(c: OV.Control);
  604. VAR w: OV.Window;
  605. BEGIN w := c.app.windows;
  606. IF (w # NIL) & (w IS Editor.Editor) THEN
  607. IF w(Editor.Editor).filename[0] = 0X THEN FileSaveAs(c)
  608. ELSE DoSaveFile(c, w(Editor.Editor).filename)
  609. END
  610. END
  611. END FileSave;
  612. PROCEDURE SkipComment(VAR R: Files.Rider; VAR ch: CHAR; VAR s: ARRAY OF CHAR);
  613. VAR last: CHAR;
  614. BEGIN last := ch; Files.Read(R, ch);
  615. WHILE ~R.eof & ((last # '*') OR (ch # ')')) DO
  616. IF (last = '(') & (ch = '*') THEN SkipComment(R, ch, s) END;
  617. last := ch; Files.Read(R, ch)
  618. END;
  619. IF ~R.eof THEN Files.Read(R, ch) END;
  620. WHILE ~R.eof & (ch <= ' ') DO Files.Read(R, ch) END
  621. END SkipComment;
  622. PROCEDURE GetSym(VAR R: Files.Rider; VAR ch: CHAR; VAR s: ARRAY OF CHAR);
  623. VAR i: INTEGER;
  624. BEGIN
  625. WHILE ~R.eof & (ch <= ' ') DO Files.Read(R, ch) END;
  626. i := 0;
  627. IF ~R.eof THEN
  628. IF ch = '(' THEN
  629. Files.Read(R, ch);
  630. IF ch = '*' THEN Files.Read(R, ch); SkipComment(R, ch, s)
  631. ELSE s[i] := ch; INC(i)
  632. END
  633. END;
  634. IF ('A' <= CAP(ch)) & (CAP(ch) <= 'Z') THEN
  635. WHILE ~R.eof &
  636. (('A' <= CAP(ch)) & (CAP(ch) <= 'Z') OR
  637. ('0' <= ch) & (ch <= '9')) DO
  638. IF i < LEN(s) - 1 THEN s[i] := ch; INC(i) END;
  639. Files.Read(R, ch)
  640. END
  641. ELSE
  642. WHILE ~R.eof & (ch > ' ') &
  643. ~(('A' <= CAP(ch)) & (CAP(ch) <= 'Z') OR
  644. ('0' <= ch) & (ch <= '9')) DO
  645. IF i < LEN(s) - 1 THEN s[i] := ch; INC(i) END;
  646. Files.Read(R, ch)
  647. END
  648. END
  649. END;
  650. s[i] := 0X
  651. END GetSym;
  652. PROCEDURE GetImportedModules(modname: ARRAY OF CHAR): StrList;
  653. VAR F: Files.File;
  654. R: Files.Rider;
  655. top, p: StrList;
  656. ch: CHAR;
  657. mod, s: ARRAY 256 OF CHAR;
  658. ok: BOOLEAN;
  659. BEGIN NEW(top); top.next := NIL; p := top;
  660. s := 'Programs/'; Strings.Append(modname, s); Strings.Append('.Mod', s);
  661. F := Files.Old(s);
  662. IF F # NIL THEN
  663. Files.Set(R, F, 0); Files.Read(R, ch); GetSym(R, ch, s);
  664. ok := s = 'MODULE'; GetSym(R, ch, s); GetSym(R, ch, s); (*!FIXME check module name*)
  665. IF ok THEN
  666. ok := s = ';'; GetSym(R, ch, s);
  667. IF ok THEN
  668. ok := s = 'IMPORT'; GetSym(R, ch, s);
  669. WHILE ok & ('A' <= CAP(s[0])) & (CAP(s[0]) <= 'Z') DO
  670. mod := s;
  671. GetSym(R, ch, s);
  672. IF s = ':=' THEN GetSym(R, ch, s); mod := s; GetSym(R, ch, s) END;
  673. IF IsSysModule(mod) THEN
  674. NEW(p.next); p := p.next; p.next := NIL; p.s := mod
  675. ELSE
  676. PrependPath(mod, modname);
  677. IF ModuleExists(mod) THEN
  678. NEW(p.next); p := p.next; p.next := NIL; p.s := mod
  679. END
  680. END;
  681. IF s = ',' THEN GetSym(R, ch, s) ELSE ok := FALSE END
  682. END
  683. END
  684. END
  685. END;
  686. RETURN top.next END GetImportedModules;
  687. PROCEDURE DebugStrList(p: StrList);
  688. BEGIN
  689. WHILE p # NIL DO
  690. Out.Char("'"); Out.String(p.s); Out.Char("'"); Out.Ln;
  691. p := p.next
  692. END
  693. END DebugStrList;
  694. PROCEDURE AddUniqueToList(what: StrList; VAR where: StrList);
  695. VAR p, q, nextP: StrList;
  696. BEGIN
  697. IF where = NIL THEN where := what
  698. ELSE
  699. p := what;
  700. WHILE p # NIL DO
  701. nextP := p.next;
  702. IF where.s # p.s THEN
  703. q := where;
  704. WHILE (q.next # NIL) & (q.next.s # p.s) DO q := q.next END;
  705. IF q.next = NIL THEN q.next := p; p.next := NIL END
  706. END;
  707. p := nextP
  708. END
  709. END
  710. END AddUniqueToList;
  711. PROCEDURE UsedModuleList(modname: ARRAY OF CHAR): StrList;
  712. VAR res, list, list2, p: StrList;
  713. BEGIN res := NIL;
  714. list := GetImportedModules(modname);
  715. p := list;
  716. WHILE p # NIL DO
  717. list2 := UsedModuleList(p.s);
  718. AddUniqueToList(list2, res);
  719. p := p.next
  720. END;
  721. NEW(p); p.s := modname; p.next := NIL; AddUniqueToList(p, res);
  722. RETURN res END UsedModuleList;
  723. PROCEDURE ImportsGraph(p: StrList): BOOLEAN;
  724. BEGIN
  725. WHILE (p # NIL) & (p.s # 'Graph') DO p := p.next END;
  726. RETURN p # NIL END ImportsGraph;
  727. (* "Module.Mod" -> "Module" *)
  728. PROCEDURE GetModuleName(filename: ARRAY OF CHAR; VAR modname: ARRAY OF CHAR);
  729. VAR i: INTEGER;
  730. BEGIN i := 0;
  731. WHILE (filename[i] # 0X) & (filename[i] # '.') DO
  732. modname[i] := filename[i]; INC(i)
  733. END;
  734. modname[i] := 0X
  735. END GetModuleName;
  736. PROCEDURE OnCompileAndRun(c: OV.Control);
  737. VAR w: OV.Window; graph: BOOLEAN;
  738. primaryFile, modname: ARRAY 256 OF CHAR;
  739. modules: StrList;
  740. BEGIN w := c.app.windows;
  741. IF (w # NIL) & (w IS Editor.Editor) THEN
  742. IF Editor.TextChanged(w(Editor.Editor)) THEN FileSave(c) END;
  743. IF w(Editor.Editor).filename[0] # 0X THEN
  744. COPY(w(Editor.Editor).filename, primaryFile);
  745. GetModuleName(primaryFile, modname);
  746. modules := UsedModuleList(modname);
  747. (*DebugStrList(modules);(*!FIXME*)*)
  748. graph := ImportsGraph(modules);
  749. needWindowed := graph;
  750. IF CompileAll(modules) THEN
  751. tempWindowed := needWindowed & T.isFullscreen;
  752. IF tempWindowed THEN G.SwitchToWindowed END;
  753. RunProgram(w(Editor.Editor).filename)
  754. END
  755. END
  756. END
  757. END OnCompileAndRun;
  758. PROCEDURE HelpAbout(c: OV.Control);
  759. BEGIN
  760. IF app.statusText[0] # 0X THEN OV.SetStatusText(app, '')
  761. ELSE OV.SetStatusText(app, 'Visit freeoberon.su')
  762. END
  763. END HelpAbout;
  764. PROCEDURE TileWindows*(c: OV.Control);
  765. VAR W, E: OV.Control;
  766. count, cols, rows, i, col, x, y, w, h, w2, h2: INTEGER;
  767. aw, ah, dw, dh: INTEGER; (* Accumulator, delta *)
  768. BEGIN E := app.windows; count := 0;
  769. IF E # NIL THEN W := E.next;
  770. WHILE W # NIL DO
  771. INC(count);
  772. IF W = E THEN W := NIL ELSE W := W.next END
  773. END;
  774. IF count = 2 THEN cols := 2
  775. ELSIF count < 4 THEN cols := 1
  776. ELSIF count < 9 THEN cols := 2
  777. ELSE cols := 3
  778. END;
  779. rows := count DIV cols; col := 1;
  780. x := 0; y := 1;
  781. w := T.charsX DIV cols; w2 := w;
  782. dw := T.charsX MOD cols;
  783. h := (T.charsY - 2) DIV rows;
  784. dh := (T.charsY - 2) MOD rows;
  785. IF h < 2 THEN h := 2; dh := 0 END;
  786. aw := dw; ah := 0;
  787. W := E.next; i := 0;
  788. WHILE W # NIL DO
  789. INC(ah, dh);
  790. IF ah < rows THEN h2 := h ELSE h2 := h + 1; DEC(ah, rows) END;
  791. OV.WindowResize(W, x, y, w2, h2);
  792. IF W = E THEN W := NIL ELSE W := W.next END;
  793. INC(y, h2); INC(i);
  794. IF (i = rows) & (col < cols) THEN (* New column *)
  795. i := 0; INC(col); INC(x, w2); y := 1; ah := 0;
  796. INC(aw, dw);
  797. IF aw < cols THEN w2 := w ELSE w2 := w + 1; DEC(aw, cols) END;
  798. IF col = cols THEN (* Last column *)
  799. rows := count - rows * (cols - 1);
  800. w := T.charsX - x;
  801. h := (T.charsY - 2) DIV rows;
  802. dh := (T.charsY - 2) MOD rows;
  803. IF h < 2 THEN h := 2; dh := 0 END
  804. END
  805. END
  806. END
  807. END
  808. END TileWindows;
  809. PROCEDURE CascadeWindows*(c: OV.Control);
  810. VAR W, E: OV.Control;
  811. x, y, w, h: INTEGER;
  812. BEGIN E := app.windows;
  813. x := 0; y := 1; w := T.charsX; h := T.charsY - 2;
  814. IF E # NIL THEN W := E.next;
  815. WHILE W # NIL DO
  816. OV.WindowResize(W, x, y, w, h);
  817. INC(x); INC(y); DEC(w); DEC(h);
  818. IF (w < 10) OR (h < 3) THEN
  819. x := 0; y := 1; w := T.charsX; h := T.charsY - 2
  820. END;
  821. IF W = E THEN W := NIL ELSE W := W.next END
  822. END
  823. END
  824. END CascadeWindows;
  825. PROCEDURE InitIDE;
  826. VAR w: OV.Window;
  827. m, m2: OV.Menu;
  828. BEGIN
  829. app := OV.NewApp();
  830. FileNew(app.menu);
  831. m := OV.NewMenu('&File', '', 0, NIL);
  832. OV.Add(m, OV.NewMenu('&New', 'Shift+F3', OV.hShiftF3, FileNew));
  833. OV.Add(m, OV.NewMenu('&Open', 'F3', OV.hF3, FileOpen));
  834. OV.Add(m, OV.NewMenu('&Reload', '', 0, FileReload));
  835. OV.Add(m, OV.NewMenu('&Save', 'F2', OV.hF2, FileSave));
  836. OV.Add(m, OV.NewMenu('Save &as...', 'Shift+F2', OV.hShiftF2, FileSaveAs));
  837. (*OV.Add(m, OV.NewMenu('Save a&ll', '', 0, NIL));*)
  838. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  839. OV.Add(m, OV.NewMenu('E&xit', 'Alt+X', OV.hAltX, OV.QuitApp));
  840. OV.AddMenu(app, m);
  841. m := OV.NewMenu('&Edit', '', 0, NIL);
  842. m2 := OV.NewMenu('&Undo', 'DelText', OV.hAltBackspace, NIL); m2.status := OV.disabled;
  843. OV.Add(m, m2);
  844. m2 := OV.NewMenu('&Redo', '', 0, NIL); m2.status := OV.disabled;
  845. OV.Add(m, m2);
  846. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  847. OV.Add(m, OV.NewMenu('Cu&t', 'Ctrl+X', OV.hCtrlX, Editor.EditCut));
  848. OV.Add(m, OV.NewMenu('&Copy', 'Ctrl+C', OV.hCtrlC, Editor.EditCopy));
  849. OV.Add(m, OV.NewMenu('&Paste', 'Ctrl+V', OV.hCtrlV, Editor.EditPaste));
  850. OV.Add(m, OV.NewMenu('C&lear', 'Ctrl+Del', OV.hCtrlDel, Editor.EditClear));
  851. OV.Add(m, OV.NewMenu('Select &All', 'Ctrl+A', OV.hCtrlA, Editor.EditSelectAll));
  852. OV.Add(m, OV.NewMenu('U&nselect', '', 0, Editor.EditUnselect));
  853. OV.AddMenu(app, m);
  854. m := OV.NewMenu('&Search', '', 0, NIL);
  855. OV.Add(m, OV.NewMenu('&Find...', '', 0, NIL));
  856. (*!TODO*) m.children.prev.status := OV.disabled;
  857. OV.Add(m, OV.NewMenu('&Replace...', '', 0, NIL));
  858. (*!TODO*) m.children.prev.status := OV.disabled;
  859. OV.Add(m, OV.NewMenu('&Search again', '', 0, NIL));
  860. (*!TODO*) m.children.prev.status := OV.disabled;
  861. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  862. OV.Add(m, OV.NewMenu('&Go to line number...', '', 0, NIL));
  863. (*!TODO*) m.children.prev.status := OV.disabled;
  864. OV.Add(m, OV.NewMenu('&Find procedure...', '', 0, NIL));
  865. (*!TODO*) m.children.prev.status := OV.disabled;
  866. OV.AddMenu(app, m);
  867. m := OV.NewMenu('&Run', '', 0, NIL);
  868. OV.Add(m, OV.NewMenu('&Run', 'Ctrl+F9', OV.hCtrlF9, OnCompileAndRun));
  869. OV.Add(m, OV.NewMenu('Run &Directory...', '', 0, NIL));
  870. (*!TODO*) m.children.prev.status := OV.disabled;
  871. OV.Add(m, OV.NewMenu('P&arameters...', '', 0, NIL));
  872. (*!TODO*) m.children.prev.status := OV.disabled;
  873. OV.AddMenu(app, m);
  874. m := OV.NewMenu('&Compile', '', 0, NIL);
  875. OV.Add(m, OV.NewMenu('&Compile', 'Alt+F9', OV.hAltF9, OnCompileAndRun));
  876. OV.Add(m, OV.NewMenu('&Make', 'Shift+F9', OV.hShiftF9, OnCompileAndRun));
  877. OV.Add(m, OV.NewMenu('Make && &Run', 'F9', OV.hF9, OnCompileAndRun));
  878. OV.Add(m, OV.NewMenu('&Build', '', 0, OnCompileAndRun));
  879. OV.AddMenu(app, m);
  880. m := OV.NewMenu('&Debug', '', 0, NIL);
  881. OV.Add(m, OV.NewMenu('&Output', '', 0, NIL));
  882. (*!TODO*) m.children.prev.status := OV.disabled;
  883. OV.AddMenu(app, m);
  884. m := OV.NewMenu('&Tools', '', 0, NIL);
  885. OV.Add(m, OV.NewMenu('&Messages', 'F11', OV.hF11, NIL));
  886. (*!TODO*) m.children.prev.status := OV.disabled;
  887. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  888. OV.Add(m, OV.NewMenu('&Calculator', '', 0, NIL));
  889. (*!TODO*) m.children.prev.status := OV.disabled;
  890. OV.Add(m, OV.NewMenu('Ascii &table', '', 0, NIL));
  891. (*!TODO*) m.children.prev.status := OV.disabled;
  892. OV.AddMenu(app, m);
  893. m := OV.NewMenu('&Options', '', 0, NIL);
  894. OV.Add(m, OV.NewMenu('Mode&...', 'Normal', 0, NIL));
  895. (*!TODO*) m.children.prev.status := OV.disabled;
  896. OV.Add(m, OV.NewMenu('&Compiler...', '', 0, NIL));
  897. (*!TODO*) m.children.prev.status := OV.disabled;
  898. OV.Add(m, OV.NewMenu('&Memory sizes...', '', 0, NIL));
  899. (*!TODO*) m.children.prev.status := OV.disabled;
  900. OV.Add(m, OV.NewMenu('&Linker...', '', 0, NIL));
  901. (*!TODO*) m.children.prev.status := OV.disabled;
  902. OV.Add(m, OV.NewMenu('&Directories...', '', 0, NIL));
  903. (*!TODO*) m.children.prev.status := OV.disabled;
  904. OV.Add(m, OV.NewMenu('&Tools...', '', 0, NIL));
  905. (*!TODO*) m.children.prev.status := OV.disabled;
  906. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  907. m2 := OV.NewMenu('&Environment', '', 0, NIL);
  908. OV.Add(m2, OV.NewMenu('&Preferences...', '', 0, NIL));
  909. (*!TODO*) m2.children.prev.status := OV.disabled;
  910. OV.Add(m2, OV.NewMenu('&Editor...', '', 0, NIL));
  911. (*!TODO*) m2.children.prev.status := OV.disabled;
  912. OV.Add(m2, OV.NewMenu('Code&Complete...', '', 0, NIL));
  913. (*!TODO*) m2.children.prev.status := OV.disabled;
  914. OV.Add(m2, OV.NewMenu('Code&Templates...', '', 0, NIL));
  915. (*!TODO*) m2.children.prev.status := OV.disabled;
  916. OV.Add(m2, OV.NewMenu('&Desktop...', '', 0, NIL));
  917. (*!TODO*) m2.children.prev.status := OV.disabled;
  918. OV.Add(m2, OV.NewMenu('Keyboard && &mouse...', '', 0, NIL));
  919. (*!TODO*) m2.children.prev.status := OV.disabled;
  920. OV.Add(m2, OV.NewMenu('Learn &Keys', '', 0, NIL));
  921. (*!TODO*) m2.children.prev.status := OV.disabled;
  922. OV.Add(m, m2);
  923. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  924. OV.Add(m, OV.NewMenu('&Open...', '', 0, NIL));
  925. (*!TODO*) m.children.prev.status := OV.disabled;
  926. OV.Add(m, OV.NewMenu('&Save', 'fo.ini', 0, NIL));
  927. (*!TODO*) m.children.prev.status := OV.disabled;
  928. OV.Add(m, OV.NewMenu('Save &as...', '', 0, NIL));
  929. (*!TODO*) m.children.prev.status := OV.disabled;
  930. OV.AddMenu(app, m);
  931. m := OV.NewMenu('&Window', '', 0, NIL);
  932. OV.Add(m, OV.NewMenu('&Tile', '', 0, TileWindows));
  933. OV.Add(m, OV.NewMenu('C&ascade', '', 0, CascadeWindows));
  934. OV.Add(m, OV.NewMenu('Cl&ose all', '', 0, OV.CloseAllWindows));
  935. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  936. OV.Add(m, OV.NewMenu('&Size/Move', 'Ctrl+F5', OV.hCtrlF5, NIL));
  937. (*!TODO*) m.children.prev.status := OV.disabled;
  938. OV.Add(m, OV.NewMenu('&Zoom', 'F5', OV.hF5, OV.ZoomCurWindow));
  939. OV.Add(m, OV.NewMenu('&Next', 'F6', OV.hF6, OV.NextWindow));
  940. OV.Add(m, OV.NewMenu('&Previous', 'Shift+F6', OV.hShiftF6, OV.PrevWindow));
  941. OV.Add(m, OV.NewMenu('&Close', 'Alt+F3', OV.hAltF3, OV.CloseCurWindow));
  942. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  943. OV.Add(m, OV.NewMenu('&List...', 'Alt+0', OV.hAlt0, NIL));
  944. (*!TODO*) m.children.prev.status := OV.disabled;
  945. OV.Add(m, OV.NewMenu('&Refresh display', '', 0, OV.RefreshDisplay));
  946. OV.AddMenu(app, m);
  947. m := OV.NewMenu('&Help', '', 0, NIL);
  948. OV.Add(m, OV.NewMenu('&Contents', '', 0, NIL));
  949. (*!TODO*) m.children.prev.status := OV.disabled;
  950. OV.Add(m, OV.NewMenu('&Index', 'Shift+F1', OV.hShiftF1, NIL));
  951. (*!TODO*) m.children.prev.status := OV.disabled;
  952. OV.Add(m, OV.NewMenu('&Topic search', 'Ctrl+F1', OV.hCtrlF1, NIL));
  953. (*!TODO*) m.children.prev.status := OV.disabled;
  954. OV.Add(m, OV.NewMenu('&Previous topic', 'Alt+F1', OV.hAltF1, NIL));
  955. (*!TODO*) m.children.prev.status := OV.disabled;
  956. OV.Add(m, OV.NewMenu('&Using help', '', 0, NIL));
  957. (*!TODO*) m.children.prev.status := OV.disabled;
  958. OV.Add(m, OV.NewMenu('&Files...', '', 0, NIL));
  959. (*!TODO*) m.children.prev.status := OV.disabled;
  960. OV.Add(m, OV.NewMenu('-', '', 0, NIL));
  961. OV.Add(m, OV.NewMenu('&About...', '', OV.hF1, HelpAbout));
  962. OV.AddMenu(app, m);
  963. OV.AddStatusbar(app, OV.NewQuickBtn('Help', 'F1', 0, HelpAbout));
  964. OV.AddStatusbar(app, OV.NewQuickBtn('Save', 'F2', 0, FileSave));
  965. OV.AddStatusbar(app, OV.NewQuickBtn('Open', 'F3', 0, FileOpen));
  966. OV.AddStatusbar(app, OV.NewQuickBtn('Compile & Run', 'F9', 0, OnCompileAndRun));
  967. OV.AddStatusbar(app, OV.NewQuickBtn('Local menu', 'Alt+F10', 0, NIL));
  968. (*!TODO*) app.statusbar.children.prev.status := OV.disabled
  969. END InitIDE;
  970. PROCEDURE OpenFiles(VAR fnames: Fnames);
  971. VAR i: INTEGER;
  972. BEGIN i := 0;
  973. WHILE (i < LEN(fnames)) & (fnames[i] # '') DO
  974. DoOpenFile(fnames[i]); INC(i)
  975. END;
  976. IF i # 0 THEN OV.NextWindow(app.windows) END
  977. END OpenFiles;
  978. PROCEDURE ParseArgs(VAR fs, sw: BOOLEAN;
  979. VAR fnames: Fnames);
  980. VAR i, nofnames: INTEGER;
  981. s: ARRAY 256 OF CHAR;
  982. BEGIN fs := FALSE; sw := FALSE; i := 0; nofnames := 0;
  983. WHILE i # Modules.ArgCount DO
  984. Modules.GetArg(i, s);
  985. IF s = '--window' THEN fs := FALSE
  986. ELSIF s = '--software' THEN sw := TRUE
  987. ELSIF nofnames < LEN(fnames) THEN
  988. COPY(s, fnames[nofnames]); INC(nofnames)
  989. END;
  990. INC(i)
  991. END;
  992. IF nofnames < LEN(fnames) THEN fnames[nofnames][0] := 0X END
  993. END ParseArgs;
  994. PROCEDURE Init(): BOOLEAN;
  995. VAR success, fs, sw: BOOLEAN;
  996. fnames: Fnames;
  997. BEGIN
  998. success := FALSE;
  999. ParseArgs(fs, sw, fnames);
  1000. IF T.Init(fs, sw) THEN
  1001. InitIDE;
  1002. needWindowed := TRUE;
  1003. ResetSysModules;
  1004. OpenFiles(fnames);
  1005. success := TRUE
  1006. ELSE Out.String('Terminal init failed.'); Out.Ln
  1007. END;
  1008. RETURN success END Init;
  1009. BEGIN
  1010. IF ~Init() THEN Out.String('Could not initialize.'); Out.Ln
  1011. ELSE OV.RunApp(app)
  1012. END;
  1013. G.Close
  1014. END FreeOberon.