2
0

Viewer.Mod 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. MODULE Viewer;
  2. IMPORT Files, Out, T := TermBox, Args, Graph;
  3. CONST
  4. lineLen = 140;
  5. TYPE
  6. Line = POINTER TO LineDesc;
  7. LineDesc = RECORD
  8. s: ARRAY lineLen OF CHAR;
  9. prev, next: Line
  10. END;
  11. Viewer = RECORD
  12. first, last: Line;
  13. count: INTEGER; (** Количество строк *)
  14. curY: INTEGER; (** Сдвиг вниз от первой строки *)
  15. firstOnScreen: Line; (** Первая строка, видимая сейчас на экране *)
  16. redraw: BOOLEAN (** Нужно ли перерисовывать *)
  17. END;
  18. VAR
  19. X, Y, W, H: INTEGER;
  20. fg, bg, border, scrollFg, scrollBg: INTEGER;
  21. PROCEDURE ReadFile(VAR v: Viewer; fname: ARRAY OF CHAR);
  22. VAR
  23. F: Files.File;
  24. r: Files.Rider;
  25. ch: CHAR;
  26. p: Line;
  27. i: INTEGER;
  28. BEGIN
  29. F := Files.Old(fname);
  30. IF F = NIL THEN
  31. Out.String('Could not read file "');
  32. Out.String(fname); Out.String('".'); Out.Ln
  33. ELSE
  34. Files.Set(r, F, 0);
  35. NEW(v.first);
  36. p := v.first;
  37. i := 0;
  38. v.count := 1;
  39. Files.ReadChar(r, ch);
  40. WHILE ~r.eof DO
  41. IF ch = 0AX THEN
  42. p.s[i] := 0X;
  43. NEW(p.next);
  44. p.next.prev := p;
  45. p := p.next;
  46. i := 0;
  47. INC(v.count)
  48. ELSIF ch # 0DX THEN
  49. IF i < LEN(p.s) - 1 THEN p.s[i] := ch; INC(i) END
  50. END;
  51. Files.ReadChar(r, ch)
  52. END;
  53. p.s[i] := 0X;
  54. v.last := p
  55. END;
  56. v.firstOnScreen := v.first;
  57. v.curY := 0
  58. END ReadFile;
  59. PROCEDURE MoveLineUp(VAR v: Viewer);
  60. BEGIN
  61. IF v.curY > 0 THEN
  62. DEC(v.curY);
  63. v.firstOnScreen := v.firstOnScreen.prev
  64. END
  65. END MoveLineUp;
  66. PROCEDURE MoveLineDown(VAR v: Viewer);
  67. BEGIN
  68. IF v.curY < v.count - H THEN
  69. INC(v.curY);
  70. v.firstOnScreen := v.firstOnScreen.next
  71. END
  72. END MoveLineDown;
  73. PROCEDURE MoveScreenUp(VAR v: Viewer);
  74. VAR i: INTEGER;
  75. BEGIN
  76. i := H;
  77. WHILE i # 0 DO MoveLineUp(v); DEC(i) END
  78. END MoveScreenUp;
  79. PROCEDURE MoveScreenDown(VAR v: Viewer);
  80. VAR i: INTEGER;
  81. BEGIN
  82. i := H;
  83. WHILE i # 0 DO MoveLineDown(v); DEC(i) END
  84. END MoveScreenDown;
  85. PROCEDURE MoveToTop(VAR v: Viewer);
  86. BEGIN
  87. v.firstOnScreen := v.first;
  88. v.curY := 0
  89. END MoveToTop;
  90. PROCEDURE MoveToBottom(VAR v: Viewer);
  91. VAR y: INTEGER;
  92. p: Line;
  93. BEGIN
  94. y := v.count - H;
  95. IF y <= 0 THEN
  96. MoveToTop(v)
  97. ELSE
  98. v.curY := y;
  99. p := v.first;
  100. WHILE y # 0 DO
  101. p := p.next;
  102. DEC(y)
  103. END;
  104. v.firstOnScreen := p
  105. END
  106. END MoveToBottom;
  107. PROCEDURE HandleKey(VAR v: Viewer; key: INTEGER; VAR done: BOOLEAN);
  108. BEGIN
  109. v.redraw := TRUE;
  110. IF key = T.kEsc THEN done := TRUE
  111. ELSIF key = T.kUp THEN MoveLineUp(v)
  112. ELSIF key = T.kDown THEN MoveLineDown(v)
  113. ELSIF key = T.kPgUp THEN MoveScreenUp(v)
  114. ELSIF key = T.kPgDn THEN MoveScreenDown(v)
  115. ELSIF key = T.kHome THEN MoveToTop(v)
  116. ELSIF key = T.kEnd THEN MoveToBottom(v)
  117. ELSE v.redraw := FALSE
  118. END
  119. END HandleKey;
  120. PROCEDURE DrawLine(v: Viewer; p: Line; y: INTEGER);
  121. VAR x: INTEGER;
  122. BEGIN
  123. x := 0;
  124. WHILE (p.s[x] # 0X) & (x < W) DO
  125. T.SetCell(X + x, Y + y, p.s[x], fg, bg);
  126. INC(x)
  127. END;
  128. T.Print(X, Y + H, W,
  129. 'Двигайтесь клавишами со стрелками, а также Home, End, PageUp, PageDown',
  130. bg, border)
  131. END DrawLine;
  132. PROCEDURE InitialDraw(VAR v: Viewer);
  133. BEGIN
  134. T.ClearTo(fg, border);
  135. T.Fill(X, Y, W, H, ' ', fg, bg);
  136. END InitialDraw;
  137. PROCEDURE DrawScrollbar(v: Viewer);
  138. VAR y, h, n: INTEGER;
  139. BEGIN
  140. h := H * H DIV v.count;
  141. IF h < 1 THEN h := 1 END;
  142. IF h < H THEN
  143. n := v.count - H;
  144. y := (v.curY * (H - h) + n DIV 2) DIV n;
  145. T.Fill(X + W - 2, Y, 2, H, ' ', fg, scrollBg);
  146. T.Fill(X + W - 2, Y + y, 2, h, ' ', fg, scrollFg)
  147. END
  148. END DrawScrollbar;
  149. PROCEDURE Draw(v: Viewer);
  150. VAR p: Line;
  151. i: INTEGER;
  152. BEGIN
  153. T.Fill(X, Y, W, H, ' ', fg, bg);
  154. p := v.firstOnScreen;
  155. i := 0;
  156. WHILE (i < H) & (p # NIL) DO
  157. DrawLine(v, p, i);
  158. INC(i);
  159. p := p.next
  160. END;
  161. DrawScrollbar(v);
  162. T.Flush
  163. END Draw;
  164. PROCEDURE Run(VAR v: Viewer);
  165. VAR e: T.Event;
  166. done: BOOLEAN;
  167. BEGIN
  168. InitialDraw(v);
  169. v.redraw := TRUE;
  170. REPEAT
  171. IF v.redraw THEN
  172. Draw(v);
  173. v.redraw := FALSE
  174. END;
  175. T.WaitEvent(e);
  176. IF e.type = T.quit THEN done := TRUE
  177. ELSIF e.type = T.key THEN HandleKey(v, e.key, done)
  178. END
  179. UNTIL done;
  180. END Run;
  181. PROCEDURE View(fname: ARRAY OF CHAR);
  182. VAR v: Viewer;
  183. BEGIN
  184. T.Init; T.HideCursor; T.HideMouse;
  185. T.Size(W, H); DEC(W, 4); DEC(H, 2); X := 2; Y := 1;
  186. fg := 3; bg := 1; border := 9; scrollBg := 0; scrollFg := 3;
  187. ReadFile(v, fname);
  188. Run(v);
  189. T.Close
  190. END View;
  191. PROCEDURE Usage;
  192. VAR s: ARRAY 256 OF CHAR;
  193. BEGIN
  194. Out.String('Viewer. Usage:'); Out.Ln;
  195. Args.Get(0, s);
  196. Out.String(' '); Out.String(s);
  197. Out.String(' fileName'); Out.Ln
  198. END Usage;
  199. PROCEDURE Do;
  200. VAR s: ARRAY 1024 OF CHAR;
  201. BEGIN
  202. IF Args.Count() = 1 THEN
  203. Args.Get(1, s);
  204. View(s)
  205. ELSE
  206. Usage;
  207. View('../README.md') (*This is for easier demonstration, you may delete it*)
  208. END
  209. END Do;
  210. BEGIN
  211. Do
  212. END Viewer.