xref: /inferno-os/doc/dev.ms (revision 46439007cf417cbd9ac8049bb4122c890097a0fa)
1.TL
2Program Development under Inferno
3.AU
4Roger Peppé
5rog@vitanuova.com
6.SH
7Introduction
8.PP
9Inferno provides a set of programs that, used in
10combination, provide a powerful development environment
11in which to write Limbo programs.
12.I Limbo (1)
13is the compiler for the Limbo language; there
14are versions that run inside and outside the Inferno
15environment.
16.I Acme (1)
17is an integrated window system and editor, and the
18preferred source-code editing tool within Inferno.
19The Limbo debugger,
20.I wm-debug (1),
21allows interactive inspection of running Limbo programs.
22.I Stack (1)
23allows a quick inspection of the execution stack of a
24currently running process.
25.SH
26Getting started
27.PP
28This document assumes that you have already managed
29to install Inferno and have managed to obtain an Inferno
30window, running the Inferno window manager,
31.I wm (1).
32The document
33\&``Installing Inferno'' in this volume has details on this.
34If running within emu, it is worth giving Inferno
35as large a window as possible, as it cannot be resized later.
36This paper assumes that you are using a three-button mouse, as it is
37not feasible to use Acme without a three-button mouse.
38(if you have a two button mouse with a ``mouse wheel'',
39the wheel can be used as the middle button).
40The first thing to do is to get Acme going. By clicking
41on the Vita Nuova logo at the bottom left of the window,
42you can display a menu naming some preconfigured commands.
43If this has an ``Acme'' entry, then just clicking on that entry
44will start acme. If not, then click on the ``Shell'' entry,
45and type
46.P1
47acme
48.P2
49to start it up. The Acme window should then appear,
50filling most of the screen (the window manager toolbar
51should still be visible).
52.SH
53Acme basics
54.PP
55For a general overview and the rationale behind Acme, see ``Acme:
56A User Interface for Programmers'', elsewhere in this volume,
57and for detailed documentation, see
58.I acme (1).
59The basics are as follows:
60.PP
61Acme windows are text-only and organised into columns.
62A distinctive feature of Acme is that there are no graphical
63title bars to windows; instead, each window (and additionally
64each column, and the whole Acme window itself) has
65a textual
66.I tag ,
67which can be edited at will, and is initially primed to contain
68a few appropriate commands.
69.PP
70An Acme command is just represented by text; any textual
71command word may be executed simply by clicking with the middle
72mouse button on the word. (See ``Acme mouse commands'', below).
73If Acme recognizes the word that has been clicked on
74as one of its internal commands (e.g. Put, Undo), then it will take the appropriate
75action; otherwise it will run the text as a shell command.
76(See
77.I sh (1)).
78.SH
79Acme mouse commands
80.PP
81Mouse usage within Acme is somewhat more versatile
82than in most other window systems. Each of the three
83mouse buttons has its own action, and there are also
84actions bound to
85.I chords
86of mouse buttons (i.e. mouse buttons depressed simultaneously).
87Mouse buttons are numbered from left (1) to right (3).
88Button 1 follows similar conventions to other window systems -
89it selects text; a double click will select a line if at the beginning or end
90of a line, or match brackets if on a bracket character, or select
91a word otherwise.
92Button 2, as mentioned above, executes an
93Acme command; a single click with button 2 will execute
94the single word under the click, otherwise the swept text
95will be executed.
96Button 3 is a general ``look'' operator; if the text under the
97click represents a filename, then Acme will open a new
98window for the file and read it in, otherwise it will search
99within the current window for the next occurrence of the
100text.
101Clicking button 2 or button 3 on some text already selected
102by button 1 causes the click to refer exactly to the text
103selected, rather than gathering likely-looking characters
104from around the click as is the default.
105.PP
106There are two mouse chord sequences which are
107commonly used in Acme (and you will find that some
108other programs in the system also recognise these sequences,
109e.g.
110.I wm-sh (1)).
111They are both available once some text
112has been selected by dragging the mouse with button 1,
113but before the button has been released. At this point,
114touching button 2 will delete the selected text and save
115it in Acme's
116.I snarf
117buffer; clicking button 3 replaces the selected text with the contents
118of the snarf buffer. Before button 1 has been released,
119these two buttons reverse each other's actions, so, for
120example, selecting some text with button 1, keeping button 1
121held down, then clicking button 2 and button 3 in succession,
122will save the selected text in the snarf buffer while leaving the
123original intact.
124The following table summarises the mouse commands in
125Acme:
126.KS
127.TS
128center box;
129l l .
130B1	Select text.
131B2	Execute text.
132B3	Open file or search for text.
133B1-B2	Cut text.
134B1-B3	Paste text.
135B2-B3	Cancel the pending B2 action.
136B3-B2	Cancel the pending B3 action.
137.TE
138.ce
139.I "Acme mouse command summary"
140.KE
141
142.SH
143Scrolling and resizing Acme windows
144.PP
145The scroll bars in Acme are somewhat different from
146conventional scroll bars (including the scroll bars found
147in other parts of Inferno). Clicking, or dragging, with
148button-2 on the scrollbar acts the most like the conventional
149behaviour, namely that the further down the scroll bar
150you click, the further down the file you are shown.
151.PP
152True to form, however, Acme doesn't omit to make
153the other buttons useful: button-1 and button-3
154move backwards and forwards through the file respectively.
155The nearer the top of the scrollbar the mouse, the
156slower the movement. Holding one of these buttons
157down on the scrollbar will cause the scrolling motion
158to auto-repeat, so it is easy to scroll gently through the
159entire file, for instance.
160.PP
161The small square at the top left of each Acme window is
162the handle for resizing the window. Dragging this square
163from one place to another (within Acme) will move the
164window to the new place. A single button click in this square
165will grow the window: button 1 grows it a little bit; button 2
166grows it as much as possible without obscuring the other
167window titles in the column; button 3 grows it so it covers
168the whole column (all other windows in the column are
169obscured).
170.SH
171Creating a new file
172.PP
173All Limbo programs are composed of
174.I modules
175and each module is stored in its own file. To write a Limbo
176program, you need to write at least one module,
177the Limbo
178.I "source file" ,
179which will then be compiled into Dis code which can
180then be run by the Inferno Virtual Machine (VM).
181The first step is to decide where to store the file.
182When Acme starts up, it creates a new window containing
183a list of all the files in the directory in which it was started
184(usually your home directory). As a consequence of the
185mouse rules above, a click of button-3 on any of those
186filenames in that window will open a new window
187showing that file or, if it is a directory, a list of the
188files and directories it contains.
189.PP
190An important aspect in Acme's mouse commands, is
191that the command is interpreted
192.I "relative to the window's current directory",
193where the current directory is determined from
194the filename in the window's tag. For instance,
195Acme commands executed in the tag or body of
196a window on the file
197.CW "/usr/joebloggs/myfile.txt"
198would run in the directory
199.CW /usr/joebloggs .
200.PP
201So, to create a new file in Acme, first open the
202directory in which to create the file. (If this is
203your home directory, then it's probably already on the screen;
204otherwise, you can just type (anywhere) the name of
205the directory, and button-3 click on it. If the directory
206does not exist, then no window will be created.
207Then, within the directory's window or its tag,
208choose a name,
209.I filename ,
210for your file (I'll use
211.CW myprog
212from here on,
213for explanatory convenience)
214, type the text:
215.P1
216New \fIfilename\fP.b
217.P2
218select this text (the Escape key can also be used to highlight
219text that you have just typed), and button-2 click on it.
220This should create a new empty window in which you
221can edit your Limbo source file. It will also create a
222window giving a warning that the file does not
223currently exist - you can get rid of this by clicking
224with button-2 on the text
225.CW Del
226in the tag of that window.
227.SH
228Editing the source file
229.PP
230You can now edit text in the new window.
231Type in the following program:
232.P1
233implement Myprog;
234include "sys.m";
235	sys: Sys;
236include "draw.m";
237
238Myprog: module {
239	init: fn(nil: ref Draw->Context, argv: list of string);
240};
241
242init(nil: ref Draw->Context, argv: list of string)
243{
244	sys = load Sys Sys->PATH;
245	sys->print("Hello, world\en");
246}
247.P2
248When typing it in, note that two new commands have appeared
249in the tag of the new window:
250.CW Put
251and
252.CW Undo .
253.CW Put
254saves the file;
255.CW Undo
256undoes the last change to the file, and successive
257executions of
258.CW Undo
259will move further back in time. In case you move
260too far back accidentally, there is also
261.CW Redo ,
262which redoes a change that you have just undone.
263Changes in the body of any window in Acme can be undone
264this way.
265.PP
266Click with button-2 on the
267.CW Put
268command, and the file is now saved and ready to be
269compiled. If you have problems at this point (say
270Acme complains about not being able to write the
271file), you have probably chosen an inappropriate
272directory, one in which you do not have write permission,
273in which to put the file. In this case you can change the
274name of the file simply by editing its name in the window's
275tag, and clicking on
276.CW Put
277again.
278.SH
279Compiling the source file
280.PP
281Now, you are in a position to compile the Limbo program.
282Although you can execute the Limbo compiler directly
283from the tag of the new file's window, it is usually more
284convenient to do it from a shell window. To start a shell
285window, type
286.CW win '' ``
287at the right of the tag of the new file's window, select
288it, and click with button-2 on it.
289A new window should appear showing a shell prompt (usually
290.CW "; " '' ``
291or
292.CW "% " ''). ``
293At this, you can type any of the commands mentioned
294in Section 1 of the Programmer's Manual.
295Note that, following Acme's usual rule, the shell has
296started up in the same directory as the new file;
297typing
298.P1
299lc
300.P2
301at the prompt will show all the files in the directory,
302including hopefully the newly written Limbo file.
303.PP
304Type the following command to the shell:
305.P1
306limbo -g myprog.b
307.P2
308If you typed in the example program correctly,
309then you'll get a short pause, and then another shell
310prompt. This indicates a successful compilation (no
311news is good news), in which case you will now have
312two new files in the current directory,
313.CW myprog.sbl
314and
315.CW myprog.dis .
316The
317.CW -g
318option to the
319.CW limbo
320command directed it to produce the
321.CW myprog.sbl
322file, which contains symbolic information
323relating the source code to the Dis executable file.
324The
325.CW myprog.dis
326file contains the actual executable file.
327At this point, if you type
328.CW lc ,
329to get a listing of the files in the current directory,
330and then click with button-2 on the
331.CW myprog.dis
332file, and you should see the output ``Hello, world''.
333You could also just type
334.CW myprog
335at the shell prompt.
336.PP
337If you are normal, however, the above compilation
338probably failed because of some mistyped characters
339in the source code; and for larger newly created programs,
340in my experience, this
341is almost invariably the case.
342If you got no errors in the above
343compilation, try changing
344.CW sys->print
345to
346.CW print ,
347saving the file again,
348and continue with the next section.
349.SH
350Finding compilation errors
351.PP
352When the Limbo compiler finds errors, it prints
353the errors, one per line, each one looking something
354like the following:
355.P1
356myprog.b:13: print is not declared
357.P2
358This shows the filename where the error has occurred,
359its line number in the file, and a description of the error.
360Acme's button-3 mouse clicking makes it extremely easy
361to see where in the source code the error has occurred.
362Click with button-3 anywhere in the filename on the
363line of the compilation error, and Acme will automatically
364take the cursor to the file of that name and highlight
365the correct line.
366.PP
367If there had been no currently appropriate open Acme
368window representing the file, then a new one would
369be created, and the appropriate line selected.
370.PP
371Edit
372.CW myprog.b
373until you have a program that compiles successfully
374and produces the ``Hello, world'' output.
375For a program as simple as this, that's all there
376is to it - you now know the essential stages involved in
377writing a Limbo program; there's just the small matter
378of absorbing the Limbo language and familiarising
379yourself with the libraries (``The Limbo Programming Language''
380elsewhere in this volume,
381and
382.I intro (2)
383are the two essential starting points here).
384.SH
385Finding run-time errors
386.PP
387For larger programs, there is the problem of programs
388that die unexpectedly with a run-time error. This
389will happen when, for instance, a Limbo program uses a reference
390that has not been initialised, or refers to an out-of-bounds
391array element.
392.PP
393When a Limbo program dies with a run-time exception,
394it does not go away completely, but remains hanging
395around, dormant, in a
396.I broken
397state; the state that it was in when it died may
398now be examined at leisure. To experiment with this,
399edit the Myprog module above to delete the line
400that loads the
401.CW Sys
402module
403.CW "sys = load Sys" ...), (
404and recompile the program.
405.PP
406This time when you come to run
407.CW myprog ,
408it will die, printing a message like:
409.P1
410sh: 319 "Myprog":module not loaded
411.P2
412The number
413.CW 319
414is the
415.I "process id"
416(or just
417.I pid )
418of the broken process. The command
419.CW ps ,
420which shows all currently running processes,
421can be used at this point - you will see a line like this:
422.P1
423     319      245        rog     broken    64K Myprog
424.P2
425The first number is the pid of the process;
426the second is the
427.I "process group"
428id of the process; the third field gives the
429owner of the process; the fourth gives its state
430(broken, in this case); the fifth shows the current
431size of the process, and the last gives the name
432of the module that the process is currently running.
433.PP
434The
435.CW stack
436command can be used to quickly find the line
437at which the process has broken; type:
438.P1
439	stack \fIpid\fP
440.P2
441where
442.I pid
443is the number mentioned in the ``module not loaded''
444message (319 in this case).
445It produces something like the following output:
446.P1
447init() myprog.b:12.1, 29
448unknown fn() Module /dis/sh.dis PC 1706
449.P2
450As usual, a quick button-3 click on the
451.CW myprog.b
452part of the first line takes you to the appropriate
453part of the source file. The reason that the program
454has died here is that, in Limbo, all external modules
455must be explicitly loaded before they can be used; to
456try to call an uninitialised module is an error
457and causes an exception.
458.SH
459More sophisticated debugging
460.PP
461.CW Stack
462is fine for getting a quick summary of the state
463in which a program has died, but there are
464times when such a simple post-mortem analysis
465is inadequate. The
466.CW wm/deb
467(see
468.I wm-deb\fR(1))\fP
469command provides an interactive windowing
470debugger for such occasions.
471It runs outside Acme,
472in the default window system. A convenient way
473to start debugging an existing process is
474to raise
475.CW wm/task
476(``Task Manager'' on the
477main menu), select with the mouse the process
478to debug, and click ``Debug''. This will start
479.CW wm/deb
480on that process. Before it can start, the debugger will ask
481for the names of any source files that it has not been
482able to find (usually this includes the source for
483the shell, as the module being debugged is often
484started by the shell, and so the top-level function will
485be in the shell's module).
486.PP
487.CW Wm/deb
488can be used to debug multiple threads, to inspect
489the data structures in a thread, and to interactively
490step through the running of a thread (single stepping).
491See
492.I wm-deb (1)
493for details.
494
495\" further afield?
496\" other development tools?
497\" tools to come?
498