rface.red 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. %
  2. % RFACE.RED - Code to support execution of text from within EMODE.
  3. %
  4. % Author: William F. Galway
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 8 June 1982
  9. % Copyright (c) 1982 University of Utah
  10. %
  11. FirstCall := T; % Force full init when calling EMODE for first time.
  12. DefConst(MaxChannels, 32); % Maximum number of channels supported by
  13. % PSL.
  14. DefConst(DISPLAYTIME, 1000); % Number of milliseconds between redisplays
  15. % (very roughly--see code)
  16. % Vector of "edit routines" associated with channels.
  17. ChannelEditRoutine := MkVect(const(MaxChannels));
  18. % Vectors of buffers associated with channel (when appropriate). Each
  19. % entry in the vector is an expression to be evaluated (to allow extra
  20. % indirection).
  21. InputBufferForChannel := MkVect(const(MaxChannels));
  22. OutputBufferForChannel := MkVect(const(MaxChannels));
  23. % A window to "pop up" when the associated buffer is written into. This
  24. % probably should NOT be associated with a channel?
  25. % UNIMPLEMENTED FOR NOW. Needs MORE THOUGHT!
  26. % OutputWindowForChannel := MkVect(const(MaxChannels));
  27. % See below for definition of RlispDispatchList and LispDispatchList.
  28. RlispMode := '(SetKeys RlispDispatchList) . FundamentalTextMode;
  29. LispMode := '(SetKeys LispDispatchList) . FundamentalTextMode;
  30. % Routines for channel I/O to & from buffers
  31. FLUID '(
  32. TimeSinceRedisplay % Used to decide if time to redisplay or not
  33. % A flag for Rlisp's ON/OFF mechanism. When T, means that the "output"
  34. % (or OUT_WINDOW) window should be "popped up" when output
  35. % occurs.
  36. !*outwindow
  37. % Holds the buffername that was selected before BufferPrintChar
  38. % switches to the output buffer.
  39. previous_to_ouput_buffer
  40. % Kludge flag, T when input buffer is OUT_WINDOW buffer (for M-E).
  41. reading_from_output
  42. EmodeBufferChannel % Channel used for EMODE I/O. Perhaps this should
  43. % be expanded to allow different channels for
  44. % different purposes (break loops, error messages,
  45. % etc.) (Or, perhaps the whole model needs more
  46. % thought! )
  47. );
  48. !*outwindow := T;
  49. Symbolic Procedure OpenBufferChannel(Inbuffer, Outbuffer, Outwindow);
  50. % Open channel for buffer I/O. Outwindow currently unused.
  51. begin Scalar chn;
  52. SpecialWriteFunction!* := 'BufferPrintChar;
  53. SpecialReadFunction!* := 'BufferReadChar;
  54. SpecialCloseFunction!* := 'CloseBufferChannel;
  55. TimeSinceRedisplay := time(); % Get time from system
  56. chn := Open("buffers", 'SPECIAL);
  57. % Set up "editor" for the channel.
  58. ChannelEditRoutine[chn] := 'EmodeChannelEdit;
  59. InputBufferForChannel[chn] := Inbuffer;
  60. OutputBufferForChannel[chn] := Outbuffer;
  61. return chn
  62. end;
  63. Symbolic Procedure CloseBufferChannel(chn);
  64. % Close up an EMODE buffer channel.
  65. <<
  66. chn := Sys2Int chn; % Sys2Int should be temporary fix?
  67. ChannelEditRoutine[chn] := NIL;
  68. InputBufferForChannel[chn] := NIL;
  69. OutputBufferForChannel[chn] := NIL;
  70. >>;
  71. % Some history keeping stuff for debugging, we (sometimes) keep a circular
  72. % list of characters sent to BufferPrintChar in order to hunt down obscure
  73. % bugs.
  74. FLUID '(BPhist BPindx);
  75. BPhist := MkString(75, char BLANK);
  76. BPindx := 0;
  77. Symbolic Procedure BufferPrintChar(Chn,ch);
  78. % "Print" a character into the buffer corresponding to channel "Chn".
  79. % Perhaps a future version should "pop up" an associated window (or select
  80. % a "window configuration"?), if any, (and if some flag is set?) CLEARLY,
  81. % this needs more thought!
  82. begin scalar tmp, outbuffername,
  83. ErrOut!*; % ErrOut!* is a system FLUID
  84. % Keep a history of the characters, in the circular history buffer, for
  85. % debugging.
  86. % (Not needed right now.)
  87. % BPhist[BPindx] := ch;
  88. % BPindx := if BPindx >= size(BPhist) then 0 else 1 + BPindx;
  89. % Rebind to avoid calling self if there is an ERROR in this routine (?)
  90. ErrOut!* := OldErrOut;
  91. % HUM, select the appropriate buffer.
  92. if not(CurrentBufferName
  93. eq (outbuffername := eval OutputBufferForChannel[chn]))
  94. then
  95. <<
  96. previous_to_ouput_buffer := CurrentBufferName;
  97. SelectBuffer(outbuffername);
  98. >>;
  99. InsertCharacter(ch);
  100. % Refresh after every character might be nice, but it's costly! The
  101. % compromise is to refresh on every line--or after a time limit is
  102. % exceeded, whichever comes first.
  103. if ch = char EOL
  104. then
  105. <<
  106. % Make sure we're in two window mode, unless also reading from
  107. % OUT_WINDOW, so the user can see what we print into the buffer.
  108. % Don't pop up window if !*Outwindow is NIL.
  109. % NEEDS more thought.
  110. if !*outwindow and not(reading_from_output) then
  111. EnsureOutputVisible(outbuffername, previous_to_ouput_buffer);
  112. Refresh();
  113. >>
  114. else if ((tmp := time()) - TimeSinceRedisplay) > const(DISPLAYTIME) then
  115. <<
  116. TimeSinceRedisplay := tmp;
  117. if !*outwindow and not(reading_from_output) then
  118. EnsureOutputVisible(outbuffername, previous_to_ouput_buffer);
  119. Refresh();
  120. >>;
  121. end;
  122. % Ensure the visibility of the outbuffername buffer, oldbuffername gives
  123. % the "context" that the call occurs from.
  124. Symbolic Procedure EnsureOutputVisible(outbuffername,oldbuffername);
  125. % Don't do anything if the buffer is already visible.
  126. % Otherwise go through a rather elaborate kludge.
  127. if not Buffer_VisibleP(outbuffername) then
  128. <<
  129. SelectBuffer(oldbuffername);
  130. % Go to "two window" mode if just one "major window" on screen, and
  131. % it's a "text window".
  132. if MajorWindowCount() eq 1
  133. AND buffers_view_creator eq 'create_text_view
  134. then
  135. TwoRFACEWindows()
  136. else
  137. % Otherwise, just "create a view" into the OUT_WINDOW buffer.
  138. select_or_create_buffer('OUT_WINDOW,NIL);
  139. SelectBuffer(outbuffername);
  140. >>;
  141. Symbolic Procedure BufferReadChar(Chn);
  142. % Read a character from at location "point" in appropriate buffer for
  143. % channel "Chn", advance point.
  144. begin scalar ch;
  145. chn := Sys2Int chn; % Sys2Int should be temporary fix?
  146. %??? if not(CurrentWindowDescriptor eq InputWindowForChannel[chn]) then
  147. SelectBuffer(eval InputBufferForChannel[chn]);
  148. % (End of buffer test needs to be cleaned up.)
  149. if point = length CurrentLine
  150. and EndOfBufferP(NextIndex CurrentLineIndex)
  151. then
  152. return char EOF; % "End Of File" if at end of buffer
  153. % ****OR, should we do something like this? (Not very popular when
  154. % tried--end of buffer was typically due to a syntax error, often very hard
  155. % to know how to correct the problem.)
  156. % % Prompt user for more input if at end of buffer, then continue as
  157. % % usual.
  158. % <<
  159. % EmodeChannelEdit(chn, "END OF BUFFER: more input expected.");
  160. %
  161. % % Ultimate kludge! Get back to current buffer. (Seem to be
  162. % % mysterious problems with "CurrentLine" inconsistencies.)
  163. %% if not(CurrentWindowDescriptor eq InputWindowForChannel[chn]) then
  164. %
  165. % SelectBuffer(eval InputBufferForChannel[chn]);
  166. % >>;
  167. ch := CurrentCharacter(); % Get the character
  168. if !*ECHO then % Echo to OUT_WINDOW if ECHO flag is set.
  169. <<
  170. BufferPrintChar(Int2Sys Chn, Int2Sys ch); % NOTE Int2Sys
  171. % Super kludge! Get back to current window
  172. %??? if not(CurrentWindowDescriptor eq InputWindowForChannel[chn]) then
  173. SelectBuffer(eval InputBufferForChannel[chn]);
  174. >>;
  175. !$ForwardCharacter(); % Advance to next in buffer
  176. return Int2Sys(ch); % Convert to SYSLISP integer
  177. end;
  178. Two_window_midpoint := NIL;
  179. Symbolic Procedure TwoRFACEWindows();
  180. % Enter two window mode for RLISP interface. Puts prompt information just
  181. % below the upper window. ("Prompt" means "message window"--not EMODE's
  182. % prompt window.)
  183. if MajorWindowCount() neq 2 then
  184. % Only do something if not already in "two window mode".
  185. begin scalar old_prompt, old_msg, TopWindow;
  186. old_prompt :=
  187. if Prompt_Window then cdr atsoc('window_label, Prompt_Window);
  188. old_msg :=
  189. if Message_Window then cdr atsoc('window_label, Message_Window);
  190. % Two_window_midpoint is location of dividing line of dashes, wrt
  191. % ScreenBase, roughly speaking.
  192. % (3 and 5 are rather ad-hoc guesses.)
  193. if not numberp(two_window_midpoint) OR two_window_midpoint < 3
  194. OR two_window_midpoint > (Row ScreenDelta) - 5
  195. then
  196. two_window_midpoint := Fix (0.5 * (Row ScreenDelta - 2));
  197. Setup_Windows
  198. list(
  199. % Looks into current buffer
  200. TopWindow :=
  201. FramedWindowDescriptor(CurrentBufferName,
  202. Coords(Column ScreenBase - 1,
  203. Row ScreenBase - 1),
  204. Coords(Column ScreenDelta + 2,
  205. two_window_midpoint)),
  206. % Looks into the "message buffer", used for error messages
  207. % and general stuff.
  208. Message_Window :=
  209. UnframedWindowDescriptor('MESSAGE_BUFFER,
  210. % Base is at two_window_midpoint
  211. Coords(Column ScreenBase,
  212. Row ScreenBase + two_window_midpoint),
  213. % a single line (so delta row = 0)
  214. Coords(Column ScreenDelta, 0)),
  215. % Always looks into the 'OUT_WINDOW buffer,
  216. % until we can figure out a better way to handle the
  217. % situation??
  218. FramedWindowDescriptor('OUT_WINDOW,
  219. Coords(Column ScreenBase - 1,
  220. Row ScreenBase +
  221. two_window_midpoint + 1),
  222. % Run down to the bottom, minus a one line
  223. % window.
  224. Coords(Column ScreenDelta + 2,
  225. Row ScreenDelta
  226. - two_window_midpoint - 2)),
  227. % Looks into the "prompt line" buffer.
  228. Prompt_Window :=
  229. UnframedWindowDescriptor('PROMPT_BUFFER,
  230. % Base is at bottom
  231. Coords(Column ScreenBase,
  232. Row ScreenBase + Row ScreenDelta),
  233. % a single line (so delta row = 0)
  234. Coords(Column ScreenDelta, 0))
  235. );
  236. % Restore the labels from their old values (if any).
  237. SelectWindowContext(Prompt_Window);
  238. window_label := old_prompt;
  239. SelectWindowContext(Message_Window);
  240. window_label := old_msg;
  241. % Keep track of "minor windows".
  242. minor_window_list := list(Prompt_Window, Message_Window);
  243. SelectWindow TopWindow; % ??? should this be necessary?
  244. end;
  245. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  246. % Set up bindings for Rlisp Mode.
  247. RlispDispatchList :=
  248. list(
  249. % M-; inserts a comment--isn't nearly as nice as EMACS version yet.
  250. cons(char meta !;, 'InsertComment),
  251. % M-E puts us at beginning of line and then simply causes us to return
  252. % (exit) to the caller (roughly speaking).
  253. cons(char meta E, 'ReturnFromEmodeEdit),
  254. % M-C-Y deletes the last "expression" printed in OUT_WINDOW.
  255. cons(char meta cntrl Y, 'insert_last_expression)
  256. );
  257. % Set up bindings for Lisp Mode. (See HP-EMODEX for additions to this
  258. % list.)
  259. LispDispatchList :=
  260. list(
  261. % M-; inserts a comment--isn't nearly as nice as EMACS version yet.
  262. cons(char meta !;, 'InsertComment),
  263. % M-E puts us at beginning of line and then simply causes us to return
  264. % (exit) to the caller (roughly speaking).
  265. cons(char meta E, 'ReturnFromEmodeEdit),
  266. % M-C-Y deletes the last "expression" printed in OUT_WINDOW.
  267. cons(char meta cntrl Y, 'insert_last_expression)
  268. );
  269. Symbolic Procedure insert_last_expression();
  270. % Insert "last expression" typed in the OUT_WINDOW buffer.
  271. begin scalar cbuf;
  272. cbuf := CurrentBufferName; % Remember current buffer.
  273. SelectBuffer('OUT_WINDOW);
  274. % "Mark" points to start of expression, "Point" gives the end.
  275. % First, back up over any trailing blank lines.
  276. while not BeginningOfBufferP(CurrentLineIndex) and point = 0 do
  277. !$BackwardCharacter();
  278. % Now, copy the text into the "kill buffer".
  279. copy_region();
  280. % Move back to the end of the output buffer.
  281. !$EndOfBuffer();
  282. % Select the original buffer.
  283. SelectBuffer(cbuf);
  284. insert_kill_buffer();
  285. end;
  286. Symbolic Procedure ReturnFromEmodeEdit();
  287. % (Typically invoked by M-E.) Causes EMODE to return to procedure that
  288. % called it (via "EmodeChannelEdit"). Arranges for output to go to end of
  289. % OUT_WINDOW buffer.
  290. begin scalar cbuf;
  291. % Set point and mark for output buffer, unless it's also the input
  292. % buffer.
  293. if CurrentBufferName neq 'OUT_WINDOW then
  294. <<
  295. cbuf := CurrentBufferName;
  296. SelectBuffer('OUT_WINDOW);
  297. !$EndOfBuffer();
  298. SetMark();
  299. SelectBuffer(cbuf); % Switch back to original buffer.
  300. reading_from_output := NIL;
  301. >>
  302. else
  303. reading_from_output := T;
  304. % Remember current spot, in case user wants to come back here.
  305. SetMark();
  306. % If we're at the end of the buffer, insert an EOL (gratis).
  307. if Point = Length CurrentLine
  308. and EndOfBufferP(NextIndex CurrentLineIndex)
  309. then
  310. <<
  311. !$CRLF();
  312. !$BackwardLine(); % Start out on the previous line.
  313. >>;
  314. % Start reading from the start of the line that M-E was typed at.
  315. !$BeginningOfLine();
  316. % Set things up to read from and write to EMODE buffers.
  317. SelectEmodeChannels();
  318. leave_dispatch_loop();
  319. end;
  320. % Make sure *EMODE's defined (as opposed to unbound?) at load time. Hope
  321. % we don't load inside EMODE!
  322. !*EMODE := NIL;
  323. % Redefine QUIT so that it restores the terminal to echoing before exiting.
  324. if FUnboundP('original!-quit) then
  325. CopyD('original!-quit, 'quit);
  326. Symbolic Procedure quit();
  327. <<
  328. if !*EMODE then % If invoked from "inside" EMODE.
  329. <<
  330. SelectOldChannels(); % Switch to original channels.
  331. EchoOn(); % Turn echoing back on.
  332. >>;
  333. original!-quit();
  334. % Fire up EMODE, if we called quit from inside it.
  335. if !*EMODE then
  336. EMODE(); % Select RLISP-INTERFACE mode upon restart.
  337. >>;
  338. Symbolic Procedure EmodeChannelEdit(chn, PromptStr);
  339. % Invoke EMODE as the editor for a buffer channel. Display the prompt on
  340. % "message_window".
  341. <<
  342. % Select "old" channels, so if an error occurs we don't get a bad
  343. % recursive situation where printing into a buffer causes more trouble!
  344. SelectOldChannels();
  345. % But, keep echoing turned off, we need some other hook to restore
  346. % echoing if an error occurs.
  347. if null PromptStr then % Use empty string if no prompt given.
  348. PromptStr := "";
  349. %?? if not(CurrentWindowDescriptor eq InputWindowForChannel[chn]) then
  350. SelectBuffer(eval InputBufferForChannel[chn]);
  351. % Advance to end of next line, on theory that we want to move to next
  352. % expression to evalute.
  353. if not EndOfBufferP(NextIndex CurrentLineIndex) then
  354. <<
  355. !$ForwardLine();
  356. !$EndOfLine();
  357. >>;
  358. ERRORSET(list('EMODE1, PromptStr),T,!*BACKTRACE);
  359. >>;
  360. Symbolic Procedure PromptAndEdit(PromptStr);
  361. % Allow the user to "edit" the default input channel.
  362. PromptAndEditOnChannel(IN!*, PromptStr);
  363. Symbolic Procedure PromptAndEditOnChannel(chn, PromptStr);
  364. % If there is an editor associated with the channel, call it, passing the
  365. % channel and prompt string "PromptStr" as arguments. Always return NIL.
  366. <<
  367. if not null ChannelEditRoutine[chn] then
  368. Apply(ChannelEditRoutine[chn], list(chn, PromptStr));
  369. NIL
  370. >>;
  371. Symbolic Procedure MakeInputAvailable();
  372. % THIS IS THE MAGIC FUNCTION invoked by READ, and other "reader functions".
  373. % PROMPTSTRING!* is a global (FLUID) variable.
  374. PromptAndEdit(PROMPTSTRING!*);
  375. FLUID '(
  376. OldStdIn
  377. OldStdOut
  378. OldErrOut
  379. );
  380. Symbolic Procedure SelectOldChannels();
  381. % Select channels that were in effect when "Rlisp Interface" was started
  382. % up. (But don't turn echoing on.) NOTE that the "old channels" are
  383. % normally selected while EMODE is actually running (this is somewhat
  384. % counter intuitive). This is so that any error messages created by bugs
  385. % in EMODE will not be printed into EMODE buffers. (If they were, it might
  386. % break things recursively! )
  387. <<
  388. % Postion the cursor to the bottom of the screen.
  389. SetTerminalCursor(Column ScreenBase, Row ScreenDelta);
  390. % Currently we avoid closing the channels. Unclear if this is right. If
  391. % we do decide to close channels, remember not to close a channel after
  392. % it's already closed! (In case, e.g., ErrOut!* = STDOUT!*.)
  393. STDIN!* := OldStdIn;
  394. STDOUT!* := OldStdOut;
  395. ErrOut!* := OldErrOut;
  396. RDS STDIN!*; % Select the channels.
  397. WRS STDOUT!*;
  398. >>;
  399. Symbolic Procedure InsertComment();
  400. <<
  401. !$EndOfLine();
  402. insert_string "% ";
  403. >>;