1This is emacs-lisp-intro.info, produced by makeinfo version 4.0b from
2emacs-lisp-intro.texi.
3
4INFO-DIR-SECTION Emacs
5START-INFO-DIR-ENTRY
6* Emacs Lisp Intro: (eintr).
7  			A simple introduction to Emacs Lisp programming.
8END-INFO-DIR-ENTRY
9
10   This is an introduction to `Programming in Emacs Lisp', for people
11who are not programmers.
12
13   Edition 2.04, 2001 Dec 17
14
15   Copyright (C) 1990, '91, '92, '93, '94, '95, '97, 2001 Free Software
16Foundation, Inc.
17
18   Permission is granted to copy, distribute and/or modify this document
19under the terms of the GNU Free Documentation License, Version 1.1 or
20any later version published by the Free Software Foundation; with the
21Invariant Section being the Preface, with the Front-Cover Texts being
22no Front-Cover Texts, and with the Back-Cover Texts being no Back-Cover
23Texts.  A copy of the license is included in the section entitled "GNU
24Free Documentation License".
25
26
27File: emacs-lisp-intro.info,  Node: rotate-yk-ptr negative arg,  Prev: rotate-yk-ptr arg,  Up: yank
28
29Passing a negative argument
30...........................
31
32   Finally, the question arises, what happens if either the remainder
33function, `%', or the `nthcdr' function is passed a negative argument,
34as they quite well may?
35
36   The answers can be found by a quick test.  When `(% -1 5)' is
37evaluated, a negative number is returned; and if `nthcdr' is called
38with a negative number, it returns the same value as if it were called
39with a first argument of zero.  This can be seen be evaluating the
40following code.
41
42   Here the `=>' points to the result of evaluating the code preceding
43it.  This was done by positioning the cursor after the code and typing
44`C-x C-e' (`eval-last-sexp') in the usual fashion.  You can do this if
45you are reading this in Info inside of GNU Emacs.
46
47     (% -1 5)
48          => -1
49
50     (setq animals '(cats dogs elephants))
51          => (cats dogs elephants)
52
53     (nthcdr 1 animals)
54          => (dogs elephants)
55
56     (nthcdr 0 animals)
57          => (cats dogs elephants)
58
59     (nthcdr -1 animals)
60          => (cats dogs elephants)
61
62   So, if a minus sign or a negative number is passed to `yank', the
63`kill-ring-yank-point' is rotated backwards until it reaches the
64beginning of the list.  Then it stays there.  Unlike the other case,
65when it jumps from the end of the list to the beginning of the list,
66making a ring, it stops.  This makes sense.  You often want to get back
67to the most recently clipped out piece of text, but you don't usually
68want to insert text from as many as thirty kill commands ago.  So you
69need to work through the ring to get to the end, but won't cycle around
70it inadvertently if you are trying to come back to the beginning.
71
72   Incidentally, any number passed to `yank' with a minus sign
73preceding it will be treated as -1.  This is evidently a simplification
74for writing the program.  You don't need to jump back towards the
75beginning of the kill ring more than one place at a time and doing this
76is easier than writing a function to determine the magnitude of the
77number that follows the minus sign.
78
79
80File: emacs-lisp-intro.info,  Node: yank-pop,  Prev: yank,  Up: Kill Ring
81
82`yank-pop'
83==========
84
85   After understanding `yank', the `yank-pop' function is easy.
86Leaving out the documentation to save space, it looks like this:
87
88     (defun yank-pop (arg)
89       (interactive "*p")
90       (if (not (eq last-command 'yank))
91           (error "Previous command was not a yank"))
92       (setq this-command 'yank)
93       (let ((before (< (point) (mark))))
94         (delete-region (point) (mark))
95         (rotate-yank-pointer arg)
96         (set-mark (point))
97         (insert (car kill-ring-yank-pointer))
98         (if before (exchange-point-and-mark))))
99
100   The function is interactive with a small `p' so the prefix argument
101is processed and passed to the function.  The command can only be used
102after a previous yank; otherwise an error message is sent.  This check
103uses the variable `last-command' which is discussed elsewhere.  (*Note
104copy-region-as-kill::.)
105
106   The `let' clause sets the variable `before' to true or false
107depending whether point is before or after mark and then the region
108between point and mark is deleted.  This is the region that was just
109inserted by the previous yank and it is this text that will be
110replaced.  Next the `kill-ring-yank-pointer' is rotated so that the
111previously inserted text is not reinserted yet again.  Mark is set at
112the beginning of the place the new text will be inserted and then the
113first element to which `kill-ring-yank-pointer' points is inserted.
114This leaves point after the new text.  If in the previous yank, point
115was left before the inserted text, point and mark are now exchanged so
116point is again left in front of the newly inserted text.  That is all
117there is to it!
118
119
120File: emacs-lisp-intro.info,  Node: Full Graph,  Next: GNU Free Documentation License,  Prev: Kill Ring,  Up: Top
121
122A Graph with Labelled Axes
123**************************
124
125   Printed axes help you understand a graph.  They convey scale.  In an
126earlier chapter (*note Readying a Graph: Readying a Graph.), we wrote
127the code to print the body of a graph.  Here we write the code for
128printing and labelling vertical and horizontal axes, along with the
129body itself.
130
131* Menu:
132
133* Labelled Example::
134* print-graph Varlist::         `let' expression in `print-graph'.
135* print-Y-axis::                Print a label for the vertical axis.
136* print-X-axis::                Print a horizontal label.
137* Print Whole Graph::           The function to print a complete graph.
138
139
140File: emacs-lisp-intro.info,  Node: Labelled Example,  Next: print-graph Varlist,  Prev: Full Graph,  Up: Full Graph
141
142Labelled Example Graph
143======================
144
145   Since insertions fill a buffer to the right and below point, the new
146graph printing function should first print the Y or vertical axis, then
147the body of the graph, and finally the X or horizontal axis.  This
148sequence lays out for us the contents of the function:
149
150  1. Set up code.
151
152  2. Print Y axis.
153
154  3. Print body of graph.
155
156  4. Print X axis.
157
158   Here is an example of how a finished graph should look:
159
160         10 -
161                       *
162                       *  *
163                       *  **
164                       *  ***
165          5 -      *   *******
166                 * *** *******
167                 *************
168               ***************
169          1 - ****************
170              |   |    |    |
171              1   5   10   15
172
173In this graph, both the vertical and the horizontal axes are labelled
174with numbers.  However, in some graphs, the horizontal axis is time and
175would be better labelled with months, like this:
176
177          5 -      *
178                 * ** *
179                 *******
180               ********** **
181          1 - **************
182              |    ^      |
183              Jan  June   Jan
184
185   Indeed, with a little thought, we can easily come up with a variety
186of vertical and horizontal labelling schemes.  Our task could become
187complicated.  But complications breed confusion.  Rather than permit
188this, it is better choose a simple labelling scheme for our first
189effort, and to modify or replace it later.
190
191   These considerations suggest the following outline for the
192`print-graph' function:
193
194     (defun print-graph (numbers-list)
195       "DOCUMENTATION..."
196       (let ((height  ...
197             ...))
198         (print-Y-axis height ... )
199         (graph-body-print numbers-list)
200         (print-X-axis ... )))
201
202   We can work on each part of the `print-graph' function definition in
203turn.
204
205
206File: emacs-lisp-intro.info,  Node: print-graph Varlist,  Next: print-Y-axis,  Prev: Labelled Example,  Up: Full Graph
207
208The `print-graph' Varlist
209=========================
210
211   In writing the `print-graph' function, the first task is to write
212the varlist in the `let' expression.  (We will leave aside for the
213moment any thoughts about making the function interactive or about the
214contents of its documentation string.)
215
216   The varlist should set several values.  Clearly, the top of the label
217for the vertical axis must be at least the height of the graph, which
218means that we must obtain this information here.  Note that the
219`print-graph-body' function also requires this information.  There is
220no reason to calculate the height of the graph in two different places,
221so we should change `print-graph-body' from the way we defined it
222earlier to take advantage of the calculation.
223
224   Similarly, both the function for printing the X axis labels and the
225`print-graph-body' function need to learn the value of the width of
226each symbol.  We can perform the calculation here and change the
227definition for `print-graph-body' from the way we defined it in the
228previous chapter.
229
230   The length of the label for the horizontal axis must be at least as
231long as the graph.  However, this information is used only in the
232function that prints the horizontal axis, so it does not need to be
233calculated here.
234
235   These thoughts lead us directly to the following form for the varlist
236in the `let' for `print-graph':
237
238     (let ((height (apply 'max numbers-list)) ; First version.
239           (symbol-width (length graph-blank)))
240
241As we shall see, this expression is not quite right.
242
243
244File: emacs-lisp-intro.info,  Node: print-Y-axis,  Next: print-X-axis,  Prev: print-graph Varlist,  Up: Full Graph
245
246The `print-Y-axis' Function
247===========================
248
249   The job of the `print-Y-axis' function is to print a label for the
250vertical axis that looks like this:
251
252         10 -
253
254
255
256
257          5 -
258
259
260
261          1 -
262
263The function should be passed the height of the graph, and then should
264construct and insert the appropriate numbers and marks.
265
266   It is easy enough to see in the figure what the Y axis label should
267look like; but to say in words, and then to write a function definition
268to do the job is another matter.  It is not quite true to say that we
269want a number and a tic every five lines: there are only three lines
270between the `1' and the `5' (lines 2, 3, and 4), but four lines between
271the `5' and the `10' (lines 6, 7, 8, and 9).  It is better to say that
272we want a number and a tic mark on the base line (number 1) and then
273that we want a number and a tic on the fifth line from the bottom and
274on every line that is a multiple of five.
275
276* Menu:
277
278* Height of label::             What height for the Y axis?
279* Compute a Remainder::         How to compute the remainder of a division.
280* Y Axis Element::              Construct a line for the Y axis.
281* Y-axis-column::               Generate a list of Y axis labels.
282* print-Y-axis Penultimate::    A not quite final version.
283
284
285File: emacs-lisp-intro.info,  Node: Height of label,  Next: Compute a Remainder,  Prev: print-Y-axis,  Up: print-Y-axis
286
287What height should the label be?
288--------------------------------
289
290   The next issue is what height the label should be?  Suppose the
291maximum height of tallest column of the graph is seven.  Should the
292highest label on the Y axis be `5 -', and should the graph stick up
293above the label?  Or should the highest label be `7 -', and mark the
294peak of the graph?  Or should the highest label be `10 -', which is a
295multiple of five, and be higher than the topmost value of the graph?
296
297   The latter form is preferred.  Most graphs are drawn within
298rectangles whose sides are an integral number of steps long--5, 10, 15,
299and so on for a step distance of five.  But as soon as we decide to use
300a step height for the vertical axis, we discover that the simple
301expression in the varlist for computing the height is wrong.  The
302expression is `(apply 'max numbers-list)'.  This returns the precise
303height, not the maximum height plus whatever is necessary to round up
304to the nearest multiple of five.  A more complex expression is required.
305
306   As usual in cases like this, a complex problem becomes simpler if it
307is divided into several smaller problems.
308
309   First, consider the case when the highest value of the graph is an
310integral multiple of five--when it is 5, 10, 15 ,or some higher
311multiple of five.  We can use this value as the Y axis height.
312
313   A fairly simply way to determine whether a number is a multiple of
314five is to divide it by five and see if the division results in a
315remainder.  If there is no remainder, the number is a multiple of five.
316Thus, seven divided by five has a remainder of two, and seven is not
317an integral multiple of five.  Put in slightly different language, more
318reminiscent of the classroom, five goes into seven once, with a
319remainder of two.  However, five goes into ten twice, with no
320remainder: ten is an integral multiple of five.
321
322
323File: emacs-lisp-intro.info,  Node: Compute a Remainder,  Next: Y Axis Element,  Prev: Height of label,  Up: print-Y-axis
324
325Side Trip: Compute a Remainder
326------------------------------
327
328   In Lisp, the function for computing a remainder is `%'.  The
329function returns the remainder of its first argument divided by its
330second argument.  As it happens, `%' is a function in Emacs Lisp that
331you cannot discover using `apropos': you find nothing if you type `M-x
332apropos <RET> remainder <RET>'.  The only way to learn of the existence
333of `%' is to read about it in a book such as this or in the Emacs Lisp
334sources.  The `%' function is used in the code for
335`rotate-yank-pointer', which is described in an appendix.  (*Note The
336Body of `rotate-yank-pointer': rotate-yk-ptr body.)
337
338   You can try the `%' function by evaluating the following two
339expressions:
340
341     (% 7 5)
342
343     (% 10 5)
344
345The first expression returns 2 and the second expression returns 0.
346
347   To test whether the returned value is zero or some other number, we
348can use the `zerop' function.  This function returns `t' if its
349argument, which must be a number, is zero.
350
351     (zerop (% 7 5))
352          => nil
353
354     (zerop (% 10 5))
355          => t
356
357   Thus, the following expression will return `t' if the height of the
358graph is evenly divisible by five:
359
360     (zerop (% height 5))
361
362(The value of `height', of course, can be found from `(apply 'max
363numbers-list)'.)
364
365   On the other hand, if the value of `height' is not a multiple of
366five, we want to reset the value to the next higher multiple of five.
367This is straightforward arithmetic using functions with which we are
368already familiar.  First, we divide the value of `height' by five to
369determine how many times five goes into the number.  Thus, five goes
370into twelve twice.  If we add one to this quotient and multiply by
371five, we will obtain the value of the next multiple of five that is
372larger than the height.  Five goes into twelve twice.  Add one to two,
373and multiply by five; the result is fifteen, which is the next multiple
374of five that is higher than twelve.  The Lisp expression for this is:
375
376     (* (1+ (/ height 5)) 5)
377
378For example, if you evaluate the following, the result is 15:
379
380     (* (1+ (/ 12 5)) 5)
381
382   All through this discussion, we have been using `five' as the value
383for spacing labels on the Y axis; but we may want to use some other
384value.  For generality, we should replace `five' with a variable to
385which we can assign a value.  The best name I can think of for this
386variable is `Y-axis-label-spacing'.
387
388   Using this term, and an `if' expression, we produce the following:
389
390     (if (zerop (% height Y-axis-label-spacing))
391         height
392       ;; else
393       (* (1+ (/ height Y-axis-label-spacing))
394          Y-axis-label-spacing))
395
396This expression returns the value of `height' itself if the height is
397an even multiple of the value of the `Y-axis-label-spacing' or else it
398computes and returns a value of `height' that is equal to the next
399higher multiple of the value of the `Y-axis-label-spacing'.
400
401   We can now include this expression in the `let' expression of the
402`print-graph' function (after first setting the value of
403`Y-axis-label-spacing'):
404
405     (defvar Y-axis-label-spacing 5
406       "Number of lines from one Y axis label to next.")
407
408     ...
409     (let* ((height (apply 'max numbers-list))
410            (height-of-top-line
411             (if (zerop (% height Y-axis-label-spacing))
412                 height
413               ;; else
414               (* (1+ (/ height Y-axis-label-spacing))
415                  Y-axis-label-spacing)))
416            (symbol-width (length graph-blank))))
417     ...
418
419(Note use of the  `let*' function: the initial value of height is
420computed once by the `(apply 'max numbers-list)' expression and then
421the resulting value of  `height' is used to compute its final value.
422*Note The `let*' expression: fwd-para let, for more about `let*'.)
423
424
425File: emacs-lisp-intro.info,  Node: Y Axis Element,  Next: Y-axis-column,  Prev: Compute a Remainder,  Up: print-Y-axis
426
427Construct a Y Axis Element
428--------------------------
429
430   When we print the vertical axis, we want to insert strings such as
431`5 -' and `10 - ' every five lines.  Moreover, we want the numbers and
432dashes to line up, so shorter numbers must be padded with leading
433spaces.  If some of the strings use two digit numbers, the strings with
434single digit numbers must include a leading blank space before the
435number.
436
437   To figure out the length of the number, the `length' function is
438used.  But the `length' function works only with a string, not with a
439number.  So the number has to be converted from being a number to being
440a string.  This is done with the `number-to-string' function.  For
441example,
442
443     (length (number-to-string 35))
444          => 2
445
446     (length (number-to-string 100))
447          => 3
448
449(`number-to-string' is also called `int-to-string'; you will see this
450alternative name in various sources.)
451
452   In addition, in each label, each number is followed by a string such
453as ` - ', which we will call the `Y-axis-tic' marker.  This variable is
454defined with `defvar':
455
456     (defvar Y-axis-tic " - "
457        "String that follows number in a Y axis label.")
458
459   The length of the Y label is the sum of the length of the Y axis tic
460mark and the length of the number of the top of the graph.
461
462     (length (concat (number-to-string height) Y-axis-tic)))
463
464   This value will be calculated by the `print-graph' function in its
465varlist as `full-Y-label-width' and passed on.  (Note that we did not
466think to include this in the varlist when we first proposed it.)
467
468   To make a complete vertical axis label, a tic mark is concatenated
469with a number; and the two together may be preceded by one or more
470spaces depending on how long the number is.  The label consists of
471three parts: the (optional) leading spaces, the number, and the tic
472mark.  The function is passed the value of the number for the specific
473row, and the value of the width of the top line, which is calculated
474(just once) by `print-graph'.
475
476     (defun Y-axis-element (number full-Y-label-width)
477       "Construct a NUMBERed label element.
478     A numbered element looks like this `  5 - ',
479     and is padded as needed so all line up with
480     the element for the largest number."
481       (let* ((leading-spaces
482              (- full-Y-label-width
483                 (length
484                  (concat (number-to-string number)
485                          Y-axis-tic)))))
486         (concat
487          (make-string leading-spaces ? )
488          (number-to-string number)
489          Y-axis-tic)))
490
491   The `Y-axis-element' function concatenates together the leading
492spaces, if any; the number, as a string; and the tic mark.
493
494   To figure out how many leading spaces the label will need, the
495function subtracts the actual length of the label--the length of the
496number plus the length of the tic mark--from the desired label width.
497
498   Blank spaces are inserted using the `make-string' function.  This
499function takes two arguments: the first tells it how long the string
500will be and the second is a symbol for the character to insert, in a
501special format.  The format is a question mark followed by a blank
502space, like this, `? '.  *Note Character Type: (elisp)Character Type,
503for a description of the syntax for characters.
504
505   The `number-to-string' function is used in the concatenation
506expression, to convert the number to a string that is concatenated with
507the leading spaces and the tic mark.
508
509
510File: emacs-lisp-intro.info,  Node: Y-axis-column,  Next: print-Y-axis Penultimate,  Prev: Y Axis Element,  Up: print-Y-axis
511
512Create a Y Axis Column
513----------------------
514
515   The preceding functions provide all the tools needed to construct a
516function that generates a list of numbered and blank strings to insert
517as the label for the vertical axis:
518
519     (defun Y-axis-column (height width-of-label)
520       "Construct list of Y axis labels and blank strings.
521     For HEIGHT of line above base and WIDTH-OF-LABEL."
522       (let (Y-axis)
523         (while (> height 1)
524           (if (zerop (% height Y-axis-label-spacing))
525               ;; Insert label.
526               (setq Y-axis
527                     (cons
528                      (Y-axis-element height width-of-label)
529                      Y-axis))
530             ;; Else, insert blanks.
531             (setq Y-axis
532                   (cons
533                    (make-string width-of-label ? )
534                    Y-axis)))
535           (setq height (1- height)))
536         ;; Insert base line.
537         (setq Y-axis
538               (cons (Y-axis-element 1 width-of-label) Y-axis))
539         (nreverse Y-axis)))
540
541   In this function, we start with the value of `height' and
542repetitively subtract one from its value.  After each subtraction, we
543test to see whether the value is an integral multiple of the
544`Y-axis-label-spacing'.  If it is, we construct a numbered label using
545the `Y-axis-element' function; if not, we construct a blank label using
546the `make-string' function.  The base line consists of the number one
547followed by a tic mark.
548
549
550File: emacs-lisp-intro.info,  Node: print-Y-axis Penultimate,  Prev: Y-axis-column,  Up: print-Y-axis
551
552The Not Quite Final Version of `print-Y-axis'
553---------------------------------------------
554
555   The list constructed by the `Y-axis-column' function is passed to
556the `print-Y-axis' function, which inserts the list as a column.
557
558     (defun print-Y-axis (height full-Y-label-width)
559       "Insert Y axis using HEIGHT and FULL-Y-LABEL-WIDTH.
560     Height must be the maximum height of the graph.
561     Full width is the width of the highest label element."
562     ;; Value of height and full-Y-label-width
563     ;; are passed by `print-graph'.
564       (let ((start (point)))
565         (insert-rectangle
566          (Y-axis-column height full-Y-label-width))
567         ;; Place point ready for inserting graph.
568         (goto-char start)
569         ;; Move point forward by value of full-Y-label-width
570         (forward-char full-Y-label-width)))
571
572   The `print-Y-axis' uses the `insert-rectangle' function to insert
573the Y axis labels created by the `Y-axis-column' function.  In
574addition, it places point at the correct position for printing the body
575of the graph.
576
577   You can test `print-Y-axis':
578
579  1. Install
580
581          Y-axis-label-spacing
582          Y-axis-tic
583          Y-axis-element
584          Y-axis-column
585          print-Y-axis
586
587  2. Copy the following expression:
588
589          (print-Y-axis 12 5)
590
591  3. Switch to the `*scratch*' buffer and place the cursor where you
592     want the axis labels to start.
593
594  4. Type `M-:' (`eval-expression').
595
596  5. Yank the `graph-body-print' expression into the minibuffer with
597     `C-y' (`yank)'.
598
599  6. Press <RET> to evaluate the expression.
600
601   Emacs will print labels vertically, the top one being `10 - '.  (The
602`print-graph' function will pass the value of `height-of-top-line',
603which in this case would end up as 15.)
604
605
606File: emacs-lisp-intro.info,  Node: print-X-axis,  Next: Print Whole Graph,  Prev: print-Y-axis,  Up: Full Graph
607
608The `print-X-axis' Function
609===========================
610
611   X axis labels are much like Y axis labels, except that the tics are
612on a line above the numbers.  Labels should look like this:
613
614         |   |    |    |
615         1   5   10   15
616
617   The first tic is under the first column of the graph and is preceded
618by several blank spaces.  These spaces provide room in rows above for
619the Y axis labels.  The second, third, fourth, and subsequent tics are
620all spaced equally, according to the value of `X-axis-label-spacing'.
621
622   The second row of the X axis consists of numbers, preceded by several
623blank spaces and also separated according to the value of the variable
624`X-axis-label-spacing'.
625
626   The value of the variable `X-axis-label-spacing' should itself be
627measured in units of `symbol-width', since you may want to change the
628width of the symbols that you are using to print the body of the graph
629without changing the ways the graph is labelled.
630
631* Menu:
632
633* Similarities differences::    Much like `print-Y-axis', but not exactly.
634* X Axis Tic Marks::            Create tic marks for the horizontal axis.
635
636
637File: emacs-lisp-intro.info,  Node: Similarities differences,  Next: X Axis Tic Marks,  Prev: print-X-axis,  Up: print-X-axis
638
639Similarities and differences
640----------------------------
641
642   The `print-X-axis' function is constructed in more or less the same
643fashion as the `print-Y-axis' function except that it has two lines:
644the line of tic marks and the numbers.  We will write a separate
645function to print each line and then combine them within the
646`print-X-axis' function.
647
648   This is a three step process:
649
650  1. Write a function to print the X axis tic marks,
651     `print-X-axis-tic-line'.
652
653  2. Write a function to print the X numbers,
654     `print-X-axis-numbered-line'.
655
656  3. Write a function to print both lines, the `print-X-axis' function,
657     using `print-X-axis-tic-line' and `print-X-axis-numbered-line'.
658
659
660File: emacs-lisp-intro.info,  Node: X Axis Tic Marks,  Prev: Similarities differences,  Up: print-X-axis
661
662X Axis Tic Marks
663----------------
664
665   The first function should print the X axis tic marks.  We must
666specify the tic marks themselves and their spacing:
667
668     (defvar X-axis-label-spacing
669       (if (boundp 'graph-blank)
670           (* 5 (length graph-blank)) 5)
671       "Number of units from one X axis label to next.")
672
673(Note that the value of `graph-blank' is set by another `defvar'.  The
674`boundp' predicate checks whether it has already been set; `boundp'
675returns `nil' if it has not.  If `graph-blank' were unbound and we did
676not use this conditional construction, in GNU Emacs 21, we would enter
677the debugger and see an error message saying
678`Debugger entered--Lisp error: (void-variable graph-blank)'.)
679
680   Here is the `defvar' for `X-axis-tic-symbol':
681
682     (defvar X-axis-tic-symbol "|"
683       "String to insert to point to a column in X axis.")
684
685   The goal is to make a line that looks like this:
686
687            |   |    |    |
688
689   The first tic is indented so that it is under the first column,
690which is indented to provide space for the Y axis labels.
691
692   A tic element consists of the blank spaces that stretch from one tic
693to the next plus a tic symbol.  The number of blanks is determined by
694the width of the tic symbol and the `X-axis-label-spacing'.
695
696   The code looks like this:
697
698     ;;; X-axis-tic-element
699     ...
700     (concat
701      (make-string
702       ;; Make a string of blanks.
703       (-  (* symbol-width X-axis-label-spacing)
704           (length X-axis-tic-symbol))
705       ? )
706      ;; Concatenate blanks with tic symbol.
707      X-axis-tic-symbol)
708     ...
709
710   Next, we determine how many blanks are needed to indent the first tic
711mark to the first column of the graph.  This uses the value of
712`full-Y-label-width' passed it by the `print-graph' function.
713
714   The code to make `X-axis-leading-spaces' looks like this:
715
716     ;; X-axis-leading-spaces
717     ...
718     (make-string full-Y-label-width ? )
719     ...
720
721   We also need to determine the length of the horizontal axis, which is
722the length of the numbers list, and the number of tics in the horizontal
723axis:
724
725     ;; X-length
726     ...
727     (length numbers-list)
728
729     ;; tic-width
730     ...
731     (* symbol-width X-axis-label-spacing)
732
733     ;; number-of-X-tics
734     (if (zerop (% (X-length tic-width)))
735         (/ (X-length tic-width))
736       (1+ (/ (X-length tic-width))))
737
738   All this leads us directly to the function for printing the X axis
739tic line:
740
741     (defun print-X-axis-tic-line
742       (number-of-X-tics X-axis-leading-spaces X-axis-tic-element)
743       "Print tics for X axis."
744         (insert X-axis-leading-spaces)
745         (insert X-axis-tic-symbol)  ; Under first column.
746         ;; Insert second tic in the right spot.
747         (insert (concat
748                  (make-string
749                   (-  (* symbol-width X-axis-label-spacing)
750                       ;; Insert white space up to second tic symbol.
751                       (* 2 (length X-axis-tic-symbol)))
752                   ? )
753                  X-axis-tic-symbol))
754         ;; Insert remaining tics.
755         (while (> number-of-X-tics 1)
756           (insert X-axis-tic-element)
757           (setq number-of-X-tics (1- number-of-X-tics))))
758
759   The line of numbers is equally straightforward:
760
761   First, we create a numbered element with blank spaces before each
762number:
763
764     (defun X-axis-element (number)
765       "Construct a numbered X axis element."
766       (let ((leading-spaces
767              (-  (* symbol-width X-axis-label-spacing)
768                  (length (number-to-string number)))))
769         (concat (make-string leading-spaces ? )
770                 (number-to-string number))))
771
772   Next, we create the function to print the numbered line, starting
773with the number "1" under the first column:
774
775     (defun print-X-axis-numbered-line
776       (number-of-X-tics X-axis-leading-spaces)
777       "Print line of X-axis numbers"
778       (let ((number X-axis-label-spacing))
779         (insert X-axis-leading-spaces)
780         (insert "1")
781         (insert (concat
782                  (make-string
783                   ;; Insert white space up to next number.
784                   (-  (* symbol-width X-axis-label-spacing) 2)
785                   ? )
786                  (number-to-string number)))
787         ;; Insert remaining numbers.
788         (setq number (+ number X-axis-label-spacing))
789         (while (> number-of-X-tics 1)
790           (insert (X-axis-element number))
791           (setq number (+ number X-axis-label-spacing))
792           (setq number-of-X-tics (1- number-of-X-tics)))))
793
794   Finally, we need to write the `print-X-axis' that uses
795`print-X-axis-tic-line' and `print-X-axis-numbered-line'.
796
797   The function must determine the local values of the variables used
798by both `print-X-axis-tic-line' and `print-X-axis-numbered-line', and
799then it must call them.  Also, it must print the carriage return that
800separates the two lines.
801
802   The function consists of a varlist that specifies five local
803variables, and calls to each of the two line printing functions:
804
805     (defun print-X-axis (numbers-list)
806       "Print X axis labels to length of NUMBERS-LIST."
807       (let* ((leading-spaces
808               (make-string full-Y-label-width ? ))
809            ;; symbol-width is provided by graph-body-print
810            (tic-width (* symbol-width X-axis-label-spacing))
811            (X-length (length numbers-list))
812            (X-tic
813             (concat
814              (make-string
815               ;; Make a string of blanks.
816               (-  (* symbol-width X-axis-label-spacing)
817                   (length X-axis-tic-symbol))
818               ? )
819              ;; Concatenate blanks with tic symbol.
820              X-axis-tic-symbol))
821            (tic-number
822             (if (zerop (% X-length tic-width))
823                 (/ X-length tic-width)
824               (1+ (/ X-length tic-width)))))
825         (print-X-axis-tic-line tic-number leading-spaces X-tic)
826         (insert "\n")
827         (print-X-axis-numbered-line tic-number leading-spaces)))
828
829   You can test `print-X-axis':
830
831  1. Install `X-axis-tic-symbol', `X-axis-label-spacing',
832     `print-X-axis-tic-line', as well as `X-axis-element',
833     `print-X-axis-numbered-line', and `print-X-axis'.
834
835  2. Copy the following expression:
836
837          (progn
838           (let ((full-Y-label-width 5)
839                 (symbol-width 1))
840             (print-X-axis
841              '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))))
842
843  3. Switch to the `*scratch*' buffer and place the cursor where you
844     want the axis labels to start.
845
846  4. Type `M-:' (`eval-expression').
847
848  5. Yank the test expression into the minibuffer with `C-y' (`yank)'.
849
850  6. Press <RET> to evaluate the expression.
851
852   Emacs will print the horizontal axis like this:
853
854          |   |    |    |    |
855          1   5   10   15   20
856
857
858File: emacs-lisp-intro.info,  Node: Print Whole Graph,  Prev: print-X-axis,  Up: Full Graph
859
860Printing the Whole Graph
861========================
862
863   Now we are nearly ready to print the whole graph.
864
865   The function to print the graph with the proper labels follows the
866outline we created earlier (*note A Graph with Labelled Axes: Full
867Graph.), but with additions.
868
869   Here is the outline:
870
871     (defun print-graph (numbers-list)
872       "DOCUMENTATION..."
873       (let ((height  ...
874             ...))
875         (print-Y-axis height ... )
876         (graph-body-print numbers-list)
877         (print-X-axis ... )))
878
879* Menu:
880
881* The final version::           A few changes.
882* Test print-graph::            Run a short test.
883* Graphing words in defuns::    Executing the final code.
884* lambda::                      How to write an anonymous function.
885* mapcar::                      Apply a function to elements of a list.
886* Another Bug::                 Yet another bug ... most insidious.
887* Final printed graph::         The graph itself!
888
889
890File: emacs-lisp-intro.info,  Node: The final version,  Next: Test print-graph,  Prev: Print Whole Graph,  Up: Print Whole Graph
891
892Changes for the Final Version
893-----------------------------
894
895   The final version is different from what we planned in two ways:
896first, it contains additional values calculated once in the varlist;
897second, it carries an option to specify the labels' increment per row.
898This latter feature turns out to be essential; otherwise, a graph may
899have more rows than fit on a display or on a sheet of paper.
900
901   This new feature requires a change to the `Y-axis-column' function,
902to add `vertical-step' to it.  The function looks like this:
903
904     ;;; Final version.
905     (defun Y-axis-column
906       (height width-of-label &optional vertical-step)
907       "Construct list of labels for Y axis.
908     HEIGHT is maximum height of graph.
909     WIDTH-OF-LABEL is maximum width of label.
910     VERTICAL-STEP, an option, is a positive integer
911     that specifies how much a Y axis label increments
912     for each line.  For example, a step of 5 means
913     that each line is five units of the graph."
914       (let (Y-axis
915             (number-per-line (or vertical-step 1)))
916         (while (> height 1)
917           (if (zerop (% height Y-axis-label-spacing))
918               ;; Insert label.
919               (setq Y-axis
920                     (cons
921                      (Y-axis-element
922                       (* height number-per-line)
923                       width-of-label)
924                      Y-axis))
925             ;; Else, insert blanks.
926             (setq Y-axis
927                   (cons
928                    (make-string width-of-label ? )
929                    Y-axis)))
930           (setq height (1- height)))
931         ;; Insert base line.
932         (setq Y-axis (cons (Y-axis-element
933                             (or vertical-step 1)
934                             width-of-label)
935                            Y-axis))
936         (nreverse Y-axis)))
937
938   The values for the maximum height of graph and the width of a symbol
939are computed by `print-graph' in its `let' expression; so
940`graph-body-print' must be changed to accept them.
941
942     ;;; Final version.
943     (defun graph-body-print (numbers-list height symbol-width)
944       "Print a bar graph of the NUMBERS-LIST.
945     The numbers-list consists of the Y-axis values.
946     HEIGHT is maximum height of graph.
947     SYMBOL-WIDTH is number of each column."
948       (let (from-position)
949         (while numbers-list
950           (setq from-position (point))
951           (insert-rectangle
952            (column-of-graph height (car numbers-list)))
953           (goto-char from-position)
954           (forward-char symbol-width)
955           ;; Draw graph column by column.
956           (sit-for 0)
957           (setq numbers-list (cdr numbers-list)))
958         ;; Place point for X axis labels.
959         (forward-line height)
960         (insert "\n")))
961
962   Finally, the code for the `print-graph' function:
963
964     ;;; Final version.
965     (defun print-graph
966       (numbers-list &optional vertical-step)
967       "Print labelled bar graph of the NUMBERS-LIST.
968     The numbers-list consists of the Y-axis values.
969
970     Optionally, VERTICAL-STEP, a positive integer,
971     specifies how much a Y axis label increments for
972     each line.  For example, a step of 5 means that
973     each row is five units."
974       (let* ((symbol-width (length graph-blank))
975              ;; `height' is both the largest number
976              ;; and the number with the most digits.
977              (height (apply 'max numbers-list))
978              (height-of-top-line
979               (if (zerop (% height Y-axis-label-spacing))
980                   height
981                 ;; else
982                 (* (1+ (/ height Y-axis-label-spacing))
983                    Y-axis-label-spacing)))
984              (vertical-step (or vertical-step 1))
985              (full-Y-label-width
986               (length
987                (concat
988                 (number-to-string
989                  (* height-of-top-line vertical-step))
990                 Y-axis-tic))))
991
992         (print-Y-axis
993          height-of-top-line full-Y-label-width vertical-step)
994         (graph-body-print
995          numbers-list height-of-top-line symbol-width)
996         (print-X-axis numbers-list)))
997
998
999File: emacs-lisp-intro.info,  Node: Test print-graph,  Next: Graphing words in defuns,  Prev: The final version,  Up: Print Whole Graph
1000
1001Testing `print-graph'
1002---------------------
1003
1004   We can test the `print-graph' function with a short list of numbers:
1005
1006  1. Install the final versions of `Y-axis-column', `graph-body-print',
1007     and `print-graph' (in addition to the rest of the code.)
1008
1009  2. Copy the following expression:
1010
1011          (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1))
1012
1013  3. Switch to the `*scratch*' buffer and place the cursor where you
1014     want the axis labels to start.
1015
1016  4. Type `M-:' (`eval-expression').
1017
1018  5. Yank the test expression into the minibuffer with `C-y' (`yank)'.
1019
1020  6. Press <RET> to evaluate the expression.
1021
1022   Emacs will print a graph that looks like this:
1023
1024     10 -
1025
1026
1027              *
1028             **   *
1029      5 -   ****  *
1030            **** ***
1031          * *********
1032          ************
1033      1 - *************
1034
1035          |   |    |    |
1036          1   5   10   15
1037
1038   On the other hand, if you pass `print-graph' a `vertical-step' value
1039of 2, by evaluating this expression:
1040
1041     (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2)
1042
1043The graph looks like this:
1044
1045     20 -
1046
1047
1048              *
1049             **   *
1050     10 -   ****  *
1051            **** ***
1052          * *********
1053          ************
1054      2 - *************
1055
1056          |   |    |    |
1057          1   5   10   15
1058
1059(A question: is the `2' on the bottom of the vertical axis a bug or a
1060feature?  If you think it is a bug, and should be a `1' instead, (or
1061even a `0'), you can modify the sources.)
1062
1063
1064File: emacs-lisp-intro.info,  Node: Graphing words in defuns,  Next: lambda,  Prev: Test print-graph,  Up: Print Whole Graph
1065
1066Graphing Numbers of Words and Symbols
1067-------------------------------------
1068
1069   Now for the graph for which all this code was written: a graph that
1070shows how many function definitions contain fewer than 10 words and
1071symbols, how many contain between 10 and 19 words and symbols, how many
1072contain between 20 and 29 words and symbols, and so on.
1073
1074   This is a multi-step process.  First make sure you have loaded all
1075the requisite code.
1076
1077   It is a good idea to reset the value of `top-of-ranges' in case you
1078have set it to some different value.  You can evaluate the following:
1079
1080     (setq top-of-ranges
1081      '(10  20  30  40  50
1082        60  70  80  90 100
1083       110 120 130 140 150
1084       160 170 180 190 200
1085       210 220 230 240 250
1086       260 270 280 290 300)
1087
1088Next create a list of the number of words and symbols in each range.
1089
1090Evaluate the following:
1091
1092     (setq list-for-graph
1093            (defuns-per-range
1094              (sort
1095               (recursive-lengths-list-many-files
1096                (directory-files "/usr/local/emacs/lisp"
1097                                 t ".+el$"))
1098               '<)
1099              top-of-ranges))
1100
1101On my machine, this takes about an hour.  It looks though 303 Lisp
1102files in my copy of Emacs version 19.23.  After all that computing, the
1103`list-for-graph' has this value:
1104
1105     (537 1027 955 785 594 483 349 292 224 199 166 120 116 99
1106     90 80 67 48 52 45 41 33 28 26 25 20 12 28 11 13 220)
1107
1108This means that my copy of Emacs has 537 function definitions with
1109fewer than 10 words or symbols in them, 1,027 function definitions with
111010 to 19 words or symbols in them, 955 function definitions with 20 to
111129 words or symbols in them, and so on.
1112
1113   Clearly, just by looking at this list we can see that most function
1114definitions contain ten to thirty words and symbols.
1115
1116   Now for printing.  We do _not_ want to print a graph that is 1,030
1117lines high ...  Instead, we should print a graph that is fewer than
1118twenty-five lines high.  A graph that height can be displayed on almost
1119any monitor, and easily printed on a sheet of paper.
1120
1121   This means that each value in `list-for-graph' must be reduced to
1122one-fiftieth its present value.
1123
1124   Here is a short function to do just that, using two functions we have
1125not yet seen, `mapcar' and `lambda'.
1126
1127     (defun one-fiftieth (full-range)
1128       "Return list, each number one-fiftieth of previous."
1129      (mapcar '(lambda (arg) (/ arg 50)) full-range))
1130
1131
1132File: emacs-lisp-intro.info,  Node: lambda,  Next: mapcar,  Prev: Graphing words in defuns,  Up: Print Whole Graph
1133
1134A `lambda' Expression: Useful Anonymity
1135---------------------------------------
1136
1137   `lambda' is the symbol for an anonymous function, a function without
1138a name.  Every time you use an anonymous function, you need to include
1139its whole body.
1140
1141Thus,
1142
1143     (lambda (arg) (/ arg 50))
1144
1145is a function definition that says `return the value resulting from
1146dividing whatever is passed to me as `arg' by 50'.
1147
1148   Earlier, for example, we had a function `multiply-by-seven'; it
1149multiplied its argument by 7.  This function is similar, except it
1150divides its argument by 50; and, it has no name.  The anonymous
1151equivalent of `multiply-by-seven' is:
1152
1153     (lambda (number) (* 7 number))
1154
1155(*Note The `defun' Special Form: defun.)
1156
1157If we want to multiply 3 by 7, we can write:
1158
1159     (multiply-by-seven 3)
1160      \_______________/ ^
1161              |         |
1162           function  argument
1163
1164
1165
1166
1167This expression returns 21.
1168
1169Similarly, we can write:
1170
1171     ((lambda (number) (* 7 number)) 3)
1172      \____________________________/ ^
1173                    |                |
1174           anonymous function     argument
1175
1176
1177
1178
1179If we want to divide 100 by 50, we can write:
1180
1181     ((lambda (arg) (/ arg 50)) 100)
1182      \______________________/  \_/
1183                  |              |
1184         anonymous function   argument
1185
1186
1187
1188
1189This expression returns 2.  The 100 is passed to the function, which
1190divides that number by 50.
1191
1192   *Note Lambda Expressions: (elisp)Lambda Expressions, for more about
1193`lambda'.  Lisp and lambda expressions derive from the Lambda Calculus.
1194
1195
1196File: emacs-lisp-intro.info,  Node: mapcar,  Next: Another Bug,  Prev: lambda,  Up: Print Whole Graph
1197
1198The `mapcar' Function
1199---------------------
1200
1201   `mapcar' is a function that calls its first argument with each
1202element of its second argument, in turn.  The second argument must be a
1203sequence.
1204
1205   The `map' part of the name comes from the mathematical phrase,
1206`mapping over a domain', meaning to apply a function to each of the
1207elements in a domain.  The mathematical phrase is based on the metaphor
1208of a surveyor walking, one step at a time, over an area he is mapping.
1209And `car', of course, comes from the Lisp notion of the first of a list.
1210
1211For example,
1212
1213     (mapcar '1+ '(2 4 6))
1214          => (3 5 7)
1215
1216The function `1+' which adds one to its argument, is executed on _each_
1217element of the list, and a new list is returned.
1218
1219   Contrast this with `apply', which applies its first argument to all
1220the remaining.  (*Note Readying a Graph: Readying a Graph, for a
1221explanation of `apply'.)
1222
1223   In the definition of `one-fiftieth', the first argument is the
1224anonymous function:
1225
1226     (lambda (arg) (/ arg 50))
1227
1228and the second argument is `full-range', which will be bound to
1229`list-for-graph'.
1230
1231   The whole expression looks like this:
1232
1233     (mapcar '(lambda (arg) (/ arg 50)) full-range))
1234
1235   *Note Mapping Functions: (elisp)Mapping Functions, for more about
1236`mapcar'.
1237
1238   Using the `one-fiftieth' function, we can generate a list in which
1239each element is one-fiftieth the size of the corresponding element in
1240`list-for-graph'.
1241
1242     (setq fiftieth-list-for-graph
1243           (one-fiftieth list-for-graph))
1244
1245   The resulting list looks like this:
1246
1247     (10 20 19 15 11 9 6 5 4 3 3 2 2
1248     1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 4)
1249
1250This, we are almost ready to print!  (We also notice the loss of
1251information: many of the higher ranges are 0, meaning that fewer than
125250 defuns had that many words or symbols--but not necessarily meaning
1253that none had that many words or symbols.)
1254
1255