Mercurial > emacs
changeset 47193:75518c7fea17
Remove emacs-lisp-intro.txt erroneously installed
author | Robert J. Chassell <bob@rattlesnake.com> |
---|---|
date | Sun, 01 Sep 2002 18:54:14 +0000 |
parents | 203aa2716539 |
children | 0b93e51d4568 |
files | lispintro/emacs-lisp-intro.txt |
diffstat | 1 files changed, 0 insertions(+), 16197 deletions(-) [+] |
line wrap: on
line diff
--- a/lispintro/emacs-lisp-intro.txt Sun Sep 01 16:01:07 2002 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16197 +0,0 @@ -START-INFO-DIR-ENTRY -* Emacs Lisp Intro: (eintr). - A simple introduction to Emacs Lisp programming. -END-INFO-DIR-ENTRY - -Short Contents -************** - -An Introduction to Programming in Emacs Lisp -Preface -List Processing -Practicing Evaluation -How To Write Function Definitions -A Few Buffer-Related Functions -A Few More Complex Functions -Narrowing and Widening -`car', `cdr', `cons': Fundamental Functions -Cutting and Storing Text -How Lists are Implemented -Yanking Text Back -Loops and Recursion -Regular Expression Searches -Counting: Repetition and Regexps -Counting Words in a `defun' -Readying a Graph -Your `.emacs' File -Debugging -Conclusion -The `the-the' Function -Handling the Kill Ring -A Graph with Labelled Axes -GNU Free Documentation License -Index -About the Author - - -Table of Contents -***************** - - -An Introduction to Programming in Emacs Lisp - -Preface - Why Study Emacs Lisp? - On Reading this Text - For Whom This is Written - Lisp History - A Note for Novices - Thank You - -List Processing - Lisp Lists - Numbers, Lists inside of Lists - Lisp Atoms - Whitespace in Lists - GNU Emacs Helps You Type Lists - Run a Program - Generate an Error Message - Symbol Names and Function Definitions - The Lisp Interpreter - Complications - Byte Compiling - Evaluation - Evaluating Inner Lists - Variables - `fill-column', an Example Variable - Error Message for a Symbol Without a Function - Error Message for a Symbol Without a Value - Arguments - Arguments' Data Types - An Argument as the Value of a Variable or List - Variable Number of Arguments - Using the Wrong Type Object as an Argument - The `message' Function - Setting the Value of a Variable - Using `set' - Using `setq' - Counting - Summary - Exercises - -Practicing Evaluation - How to Evaluate - Buffer Names - Getting Buffers - Switching Buffers - Buffer Size and the Location of Point - Exercise - -How To Write Function Definitions - An Aside about Primitive Functions - The `defun' Special Form - Install a Function Definition - The effect of installation - Change a Function Definition - Make a Function Interactive - An Interactive `multiply-by-seven', An Overview - An Interactive `multiply-by-seven' - Different Options for `interactive' - Install Code Permanently - `let' - `let' Prevents Confusion - The Parts of a `let' Expression - Sample `let' Expression - Uninitialized Variables in a `let' Statement - The `if' Special Form - `if' in more detail - The `type-of-animal' Function in Detail - If-then-else Expressions - Truth and Falsehood in Emacs Lisp - An explanation of `nil' - `save-excursion' - Point and Mark - Template for a `save-excursion' Expression - Review - Exercises - -A Few Buffer-Related Functions - Finding More Information - A Simplified `beginning-of-buffer' Definition - The Definition of `mark-whole-buffer' - An overview of `mark-whole-buffer' - Body of `mark-whole-buffer' - The Definition of `append-to-buffer' - An Overview of `append-to-buffer' - The `append-to-buffer' Interactive Expression - The Body of `append-to-buffer' - `save-excursion' in `append-to-buffer' - Review - Exercises - -A Few More Complex Functions - The Definition of `copy-to-buffer' - The Definition of `insert-buffer' - The Code for `insert-buffer' - The Interactive Expression in `insert-buffer' - A Read-only Buffer - `b' in an Interactive Expression - The Body of the `insert-buffer' Function - `insert-buffer' With an `if' Instead of an `or' - The `or' in the Body - The `let' Expression in `insert-buffer' - Complete Definition of `beginning-of-buffer' - Optional Arguments - `beginning-of-buffer' with an Argument - Disentangle `beginning-of-buffer' - What happens in a large buffer - What happens in a small buffer - The Complete `beginning-of-buffer' - Review - `optional' Argument Exercise - -Narrowing and Widening - The Advantages of Narrowing - The `save-restriction' Special Form - `what-line' - Exercise with Narrowing - -`car', `cdr', `cons': Fundamental Functions - Strange Names - `car' and `cdr' - `cons' - Build a list - Find the Length of a List: `length' - `nthcdr' - `nth' - `setcar' - `setcdr' - Exercise - -Cutting and Storing Text - Storing Text in a List - `zap-to-char' - The Complete `zap-to-char' Implementation - The `interactive' Expression - The Body of `zap-to-char' - The `search-forward' Function - The `progn' Special Form - Summing up `zap-to-char' - `kill-region' - The Complete `kill-region' Definition - `condition-case' - `delete-and-extract-region' - Digression into C - Initializing a Variable with `defvar' - Seeing the Current Value of a Variable - `defvar' and an asterisk - `copy-region-as-kill' - The complete `copy-region-as-kill' function definition - The Body of `copy-region-as-kill' - `last-command' and `this-command' - The `kill-append' function - The `kill-new' function - Review - Searching Exercises - -How Lists are Implemented - Lists diagrammed - Symbols as a Chest of Drawers - Exercise - -Yanking Text Back - Kill Ring Overview - The `kill-ring-yank-pointer' Variable - Exercises with `yank' and `nthcdr' - -Loops and Recursion - `while' - Looping with `while' - A `while' Loop and a List - An Example: `print-elements-of-list' - A Loop with an Incrementing Counter - Example with incrementing counter - The parts of the function definition - Putting the function definition together - Loop with a Decrementing Counter - Example with decrementing counter - The parts of the function definition - Putting the function definition together - Save your time: `dolist' and `dotimes' - The `dolist' Macro - The `dotimes' Macro - Recursion - Building Robots: Extending the Metaphor - The Parts of a Recursive Definition - Recursion with a List - Recursion in Place of a Counter - An argument of 1 or 2 - An argument of 3 or 4 - Recursion Example Using `cond' - Recursive Patterns - Recursive Pattern: _every_ - Recursive Pattern: _accumulate_ - Recursive Pattern: _keep_ - Recursion without Deferments - No Deferment Solution - Looping Exercise - -Regular Expression Searches - The Regular Expression for `sentence-end' - The `re-search-forward' Function - `forward-sentence' - Complete `forward-sentence' function definition - The `while' loops - The regular expression search - `forward-paragraph': a Goldmine of Functions - Shortened `forward-paragraph' function definition - The `let*' expression - The forward motion `while' loop - Between paragraphs - Within paragraphs - No fill prefix - With a fill prefix - Summary - Create Your Own `TAGS' File - Review - Exercises with `re-search-forward' - -Counting: Repetition and Regexps - Counting words - The `count-words-region' Function - Designing `count-words-region' - The Whitespace Bug in `count-words-region' - Count Words Recursively - Exercise: Counting Punctuation - -Counting Words in a `defun' - Divide and Conquer - What to Count? - What Constitutes a Word or Symbol? - The `count-words-in-defun' Function - Count Several `defuns' Within a File - Find a File - `lengths-list-file' in Detail - Count Words in `defuns' in Different Files - Determine the lengths of `defuns' - The `append' Function - Recursively Count Words in Different Files - Prepare the Data for Display in a Graph - Sorting Lists - Making a List of Files - Counting function definitions - -Readying a Graph - Printing the Columns of a Graph - The `graph-body-print' Function - The `recursive-graph-body-print' Function - Need for Printed Axes - Exercise - -Your `.emacs' File - Emacs' Default Configuration - Site-wide Initialization Files - Specifying Variables using `defcustom' - Beginning a `.emacs' File - Text and Auto Fill Mode - Mail Aliases - Indent Tabs Mode - Some Keybindings - Keymaps - Loading Files - Autoloading - A Simple Extension: `line-to-top-of-window' - X11 Colors - Miscellaneous Settings for a `.emacs' File - A Modified Mode Line - -Debugging - `debug' - `debug-on-entry' - `debug-on-quit' and `(debug)' - The `edebug' Source Level Debugger - Debugging Exercises - -Conclusion - -The `the-the' Function - -Handling the Kill Ring - The `rotate-yank-pointer' Function - `rotate-yank-pointer' in Outline - The Body of `rotate-yank-pointer' - Digression about the word `error' - The else-part of the `if' expression - The `%' remainder function - Using `%' in `rotate-yank-pointer' - Pointing to the last element - `yank' - Passing the argument - Passing a negative argument - `yank-pop' - -A Graph with Labelled Axes - Labelled Example Graph - The `print-graph' Varlist - The `print-Y-axis' Function - What height should the label be? - Side Trip: Compute a Remainder - Construct a Y Axis Element - Create a Y Axis Column - The Not Quite Final Version of `print-Y-axis' - The `print-X-axis' Function - Similarities and differences - X Axis Tic Marks - Printing the Whole Graph - Changes for the Final Version - Testing `print-graph' - Graphing Numbers of Words and Symbols - A `lambda' Expression: Useful Anonymity - The `mapcar' Function - Another Bug ... Most Insidious - The Printed Graph - -GNU Free Documentation License - -Index - -About the Author - - -An Introduction to Programming in Emacs Lisp -******************************************** - -This is an introduction to `Programming in Emacs Lisp', for people -who are not programmers. - -Edition 2.07, 2002 Aug 23 - -Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2002 -Free Software Foundation, Inc. - - -Published by the Free Software Foundation, Inc. -59 Temple Place, Suite 330 -Boston, MA 02111-1307 USA -Edition 2.07, 2002 Aug 23 - -ISBN 1-882114-43-4 - -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.1 or -any later version published by the Free Software Foundation; there -being no Invariant Section, with the Front-Cover Texts being "A GNU -Manual", and with the Back-Cover Texts as in (a) below. A copy of -the license is included in the section entitled "GNU Free -Documentation License". - -(a) The FSF's Back-Cover Text is: "You have freedom to copy and -modify this GNU Manual, like GNU software. Copies published by the -Free Software Foundation raise funds for GNU development." -This master menu first lists each chapter and index; then it lists -every node in every chapter. - -Preface -******* - -Most of the GNU Emacs integrated environment is written in the -programming language called Emacs Lisp. The code written in this -programming language is the software--the sets of instructions--that -tell the computer what to do when you give it commands. Emacs is -designed so that you can write new code in Emacs Lisp and easily -install it as an extension to the editor. - -(GNU Emacs is sometimes called an "extensible editor", but it does -much more than provide editing capabilities. It is better to refer to -Emacs as an "extensible computing environment". However, that phrase -is quite a mouthful. It is easier to refer to Emacs simply as an -editor. Moreover, everything you do in Emacs--find the Mayan date -and phases of the moon, simplify polynomials, debug code, manage -files, read letters, write books--all these activities are kinds of -editing in the most general sense of the word.) - -Why Study Emacs Lisp? -===================== - -Although Emacs Lisp is usually thought of in association only with -Emacs, it is a full computer programming language. You can use Emacs -Lisp as you would any other programming language. - -Perhaps you want to understand programming; perhaps you want to extend -Emacs; or perhaps you want to become a programmer. This introduction -to Emacs Lisp is designed to get you started: to guide you in -learning the fundamentals of programming, and more importantly, to -show you how you can teach yourself to go further. - -On Reading this Text -==================== - -All through this document, you will see little sample programs you can -run inside of Emacs. If you read this document in Info inside of GNU -Emacs, you can run the programs as they appear. (This is easy to do -and is explained when the examples are presented.) Alternatively, -you can read this introduction as a printed book while sitting beside -a computer running Emacs. (This is what I like to do; I like printed -books.) If you don't have a running Emacs beside you, you can still -read this book, but in this case, it is best to treat it as a novel -or as a travel guide to a country not yet visited: interesting, but -not the same as being there. - -Much of this introduction is dedicated to walk-throughs or guided -tours of code used in GNU Emacs. These tours are designed for two -purposes: first, to give you familiarity with real, working code -(code you use every day); and, second, to give you familiarity with -the way Emacs works. It is interesting to see how a working -environment is implemented. Also, I hope that you will pick up the -habit of browsing through source code. You can learn from it and -mine it for ideas. Having GNU Emacs is like having a dragon's cave -of treasures. - -In addition to learning about Emacs as an editor and Emacs Lisp as a -programming language, the examples and guided tours will give you an -opportunity to get acquainted with Emacs as a Lisp programming -environment. GNU Emacs supports programming and provides tools that -you will want to become comfortable using, such as `M-.' (the key -which invokes the `find-tag' command). You will also learn about -buffers and other objects that are part of the environment. Learning -about these features of Emacs is like learning new routes around your -home town. - -Finally, I hope to convey some of the skills for using Emacs to learn -aspects of programming that you don't know. You can often use Emacs -to help you understand what puzzles you or to find out how to do -something new. This self-reliance is not only a pleasure, but an -advantage. - -For Whom This is Written -======================== - -This text is written as an elementary introduction for people who are -not programmers. If you are a programmer, you may not be satisfied -with this primer. The reason is that you may have become expert at -reading reference manuals and be put off by the way this text is -organized. - -An expert programmer who reviewed this text said to me: - - I prefer to learn from reference manuals. I "dive into" each - paragraph, and "come up for air" between paragraphs. - - When I get to the end of a paragraph, I assume that that subject - is done, finished, that I know everything I need (with the - possible exception of the case when the next paragraph starts - talking about it in more detail). I expect that a well written - reference manual will not have a lot of redundancy, and that it - will have excellent pointers to the (one) place where the - information I want is. - -This introduction is not written for this person! - -Firstly, I try to say everything at least three times: first, to -introduce it; second, to show it in context; and third, to show it in -a different context, or to review it. - -Secondly, I hardly ever put all the information about a subject in one -place, much less in one paragraph. To my way of thinking, that -imposes too heavy a burden on the reader. Instead I try to explain -only what you need to know at the time. (Sometimes I include a -little extra information so you won't be surprised later when the -additional information is formally introduced.) - -When you read this text, you are not expected to learn everything the -first time. Frequently, you need only make, as it were, a `nodding -acquaintance' with some of the items mentioned. My hope is that I -have structured the text and given you enough hints that you will be -alert to what is important, and concentrate on it. - -You will need to "dive into" some paragraphs; there is no other way -to read them. But I have tried to keep down the number of such -paragraphs. This book is intended as an approachable hill, rather -than as a daunting mountain. - -This introduction to `Programming in Emacs Lisp' has a companion -document, *Note The GNU Emacs Lisp Reference Manual: (elisp)Top. The -reference manual has more detail than this introduction. In the -reference manual, all the information about one topic is concentrated -in one place. You should turn to it if you are like the programmer -quoted above. And, of course, after you have read this -`Introduction', you will find the `Reference Manual' useful when you -are writing your own programs. - -Lisp History -============ - -Lisp was first developed in the late 1950s at the Massachusetts -Institute of Technology for research in artificial intelligence. The -great power of the Lisp language makes it superior for other purposes -as well, such as writing editor commands and integrated environments. - -GNU Emacs Lisp is largely inspired by Maclisp, which was written at -MIT in the 1960s. It is somewhat inspired by Common Lisp, which -became a standard in the 1980s. However, Emacs Lisp is much simpler -than Common Lisp. (The standard Emacs distribution contains an -optional extensions file, `cl.el', that adds many Common Lisp -features to Emacs Lisp.) - -A Note for Novices -================== - -If you don't know GNU Emacs, you can still read this document -profitably. However, I recommend you learn Emacs, if only to learn to -move around your computer screen. You can teach yourself how to use -Emacs with the on-line tutorial. To use it, type `C-h t'. (This -means you press and release the <CTRL> key and the `h' at the same -time, and then press and release `t'.) - -Also, I often refer to one of Emacs' standard commands by listing the -keys which you press to invoke the command and then giving the name of -the command in parentheses, like this: `M-C-\' (`indent-region'). -What this means is that the `indent-region' command is customarily -invoked by typing `M-C-\'. (You can, if you wish, change the keys -that are typed to invoke the command; this is called "rebinding". -*Note Keymaps: Keymaps.) The abbreviation `M-C-\' means that you -type your <META> key, <CTRL> key and <\> key all at the same time. -(On many modern keyboards the <META> key is labelled <ALT>.) -Sometimes a combination like this is called a keychord, since it is -similar to the way you play a chord on a piano. If your keyboard does -not have a <META> key, the <ESC> key prefix is used in place of it. -In this case, `M-C-\' means that you press and release your <ESC> key -and then type the <CTRL> key and the <\> key at the same time. But -usually `M-C-\' means press the <CTRL> key along with the key that is -labelled <ALT> and, at the same time, press the <\> key. - -In addition to typing a lone keychord, you can prefix what you type -with `C-u', which is called the `universal argument'. The `C-u' -keychord passes an argument to the subsequent command. Thus, to -indent a region of plain text by 6 spaces, mark the region, and then -type `C-u 6 M-C-\'. (If you do not specify a number, Emacs either -passes the number 4 to the command or otherwise runs the command -differently than it would otherwise.) *Note Numeric Arguments: -(emacs)Arguments. - -If you are reading this in Info using GNU Emacs, you can read through -this whole document just by pressing the space bar, <SPC>. (To learn -about Info, type `C-h i' and then select Info.) - -A note on terminology: when I use the word Lisp alone, I often am -referring to the various dialects of Lisp in general, but when I speak -of Emacs Lisp, I am referring to GNU Emacs Lisp in particular. - -Thank You -========= - -My thanks to all who helped me with this book. My especial thanks to -Jim Blandy, Noah Friedman, Jim Kingdon, Roland McGrath, Frank Ritter, -Randy Smith, Richard M. Stallman, and Melissa Weisshaus. My thanks -also go to both Philip Johnson and David Stampe for their patient -encouragement. My mistakes are my own. - - Robert J. Chassell - -List Processing -*************** - -To the untutored eye, Lisp is a strange programming language. In Lisp -code there are parentheses everywhere. Some people even claim that -the name stands for `Lots of Isolated Silly Parentheses'. But the -claim is unwarranted. Lisp stands for LISt Processing, and the -programming language handles _lists_ (and lists of lists) by putting -them between parentheses. The parentheses mark the boundaries of the -list. Sometimes a list is preceded by a single apostrophe or -quotation mark, `''. Lists are the basis of Lisp. - -Lisp Lists -========== - -In Lisp, a list looks like this: `'(rose violet daisy buttercup)'. -This list is preceded by a single apostrophe. It could just as well -be written as follows, which looks more like the kind of list you are -likely to be familiar with: - - '(rose - violet - daisy - buttercup) - -The elements of this list are the names of the four different flowers, -separated from each other by whitespace and surrounded by parentheses, -like flowers in a field with a stone wall around them. - -Numbers, Lists inside of Lists ------------------------------- - -Lists can also have numbers in them, as in this list: `(+ 2 2)'. -This list has a plus-sign, `+', followed by two `2's, each separated -by whitespace. - -In Lisp, both data and programs are represented the same way; that is, -they are both lists of words, numbers, or other lists, separated by -whitespace and surrounded by parentheses. (Since a program looks like -data, one program may easily serve as data for another; this is a very -powerful feature of Lisp.) (Incidentally, these two parenthetical -remarks are _not_ Lisp lists, because they contain `;' and `.' as -punctuation marks.) - -Here is another list, this time with a list inside of it: - - '(this list has (a list inside of it)) - -The components of this list are the words `this', `list', `has', and -the list `(a list inside of it)'. The interior list is made up of -the words `a', `list', `inside', `of', `it'. - -Lisp Atoms ----------- - -In Lisp, what we have been calling words are called "atoms". This -term comes from the historical meaning of the word atom, which means -`indivisible'. As far as Lisp is concerned, the words we have been -using in the lists cannot be divided into any smaller parts and still -mean the same thing as part of a program; likewise with numbers and -single character symbols like `+'. On the other hand, unlike an -atom, a list can be split into parts. (*Note `car' `cdr' & `cons' -Fundamental Functions: car cdr & cons.) - -In a list, atoms are separated from each other by whitespace. They -can be right next to a parenthesis. - -Technically speaking, a list in Lisp consists of parentheses -surrounding atoms separated by whitespace or surrounding other lists -or surrounding both atoms and other lists. A list can have just one -atom in it or have nothing in it at all. A list with nothing in it -looks like this: `()', and is called the "empty list". Unlike -anything else, an empty list is considered both an atom and a list at -the same time. - -The printed representation of both atoms and lists are called -"symbolic expressions" or, more concisely, "s-expressions". The word -"expression" by itself can refer to either the printed -representation, or to the atom or list as it is held internally in the -computer. Often, people use the term "expression" indiscriminately. -(Also, in many texts, the word "form" is used as a synonym for -expression.) - -Incidentally, the atoms that make up our universe were named such when -they were thought to be indivisible; but it has been found that -physical atoms are not indivisible. Parts can split off an atom or -it can fission into two parts of roughly equal size. Physical atoms -were named prematurely, before their truer nature was found. In -Lisp, certain kinds of atom, such as an array, can be separated into -parts; but the mechanism for doing this is different from the -mechanism for splitting a list. As far as list operations are -concerned, the atoms of a list are unsplittable. - -As in English, the meanings of the component letters of a Lisp atom -are different from the meaning the letters make as a word. For -example, the word for the South American sloth, the `ai', is -completely different from the two words, `a', and `i'. - -There are many kinds of atom in nature but only a few in Lisp: for -example, "numbers", such as 37, 511, or 1729, and "symbols", such as -`+', `foo', or `forward-line'. The words we have listed in the -examples above are all symbols. In everyday Lisp conversation, the -word "atom" is not often used, because programmers usually try to be -more specific about what kind of atom they are dealing with. Lisp -programming is mostly about symbols (and sometimes numbers) within -lists. (Incidentally, the preceding three word parenthetical remark -is a proper list in Lisp, since it consists of atoms, which in this -case are symbols, separated by whitespace and enclosed by -parentheses, without any non-Lisp punctuation.) - -In addition, text between double quotation marks--even sentences or -paragraphs--is an atom. Here is an example: - - '(this list includes "text between quotation marks.") - -In Lisp, all of the quoted text including the punctuation mark and the -blank spaces is a single atom. This kind of atom is called a -"string" (for `string of characters') and is the sort of thing that -is used for messages that a computer can print for a human to read. -Strings are a different kind of atom than numbers or symbols and are -used differently. - -Whitespace in Lists -------------------- - -The amount of whitespace in a list does not matter. From the point -of view of the Lisp language, - - '(this list - looks like this) - -is exactly the same as this: - - '(this list looks like this) - -Both examples show what to Lisp is the same list, the list made up of -the symbols `this', `list', `looks', `like', and `this' in that order. - -Extra whitespace and newlines are designed to make a list more -readable by humans. When Lisp reads the expression, it gets rid of -all the extra whitespace (but it needs to have at least one space -between atoms in order to tell them apart.) - -Odd as it seems, the examples we have seen cover almost all of what -Lisp lists look like! Every other list in Lisp looks more or less -like one of these examples, except that the list may be longer and -more complex. In brief, a list is between parentheses, a string is -between quotation marks, a symbol looks like a word, and a number -looks like a number. (For certain situations, square brackets, dots -and a few other special characters may be used; however, we will go -quite far without them.) - -GNU Emacs Helps You Type Lists ------------------------------- - -When you type a Lisp expression in GNU Emacs using either Lisp -Interaction mode or Emacs Lisp mode, you have available to you several -commands to format the Lisp expression so it is easy to read. For -example, pressing the <TAB> key automatically indents the line the -cursor is on by the right amount. A command to properly indent the -code in a region is customarily bound to `M-C-\'. Indentation is -designed so that you can see which elements of a list belong to which -list--elements of a sub-list are indented more than the elements of -the enclosing list. - -In addition, when you type a closing parenthesis, Emacs momentarily -jumps the cursor back to the matching opening parenthesis, so you can -see which one it is. This is very useful, since every list you type -in Lisp must have its closing parenthesis match its opening -parenthesis. (*Note Major Modes: (emacs)Major Modes, for more -information about Emacs' modes.) - -Run a Program -============= - -A list in Lisp--any list--is a program ready to run. If you run it -(for which the Lisp jargon is "evaluate"), the computer will do one -of three things: do nothing except return to you the list itself; send -you an error message; or, treat the first symbol in the list as a -command to do something. (Usually, of course, it is the last of these -three things that you really want!) - -The single apostrophe, `'', that I put in front of some of the -example lists in preceding sections is called a "quote"; when it -precedes a list, it tells Lisp to do nothing with the list, other than -take it as it is written. But if there is no quote preceding a list, -the first item of the list is special: it is a command for the -computer to obey. (In Lisp, these commands are called _functions_.) -The list `(+ 2 2)' shown above did not have a quote in front of it, -so Lisp understands that the `+' is an instruction to do something -with the rest of the list: add the numbers that follow. - -If you are reading this inside of GNU Emacs in Info, here is how you -can evaluate such a list: place your cursor immediately after the -right hand parenthesis of the following list and then type `C-x C-e': - - (+ 2 2) - -You will see the number `4' appear in the echo area. (In the jargon, -what you have just done is "evaluate the list." The echo area is the -line at the bottom of the screen that displays or "echoes" text.) -Now try the same thing with a quoted list: place the cursor right -after the following list and type `C-x C-e': - - '(this is a quoted list) - -You will see `(this is a quoted list)' appear in the echo area. - -In both cases, what you are doing is giving a command to the program -inside of GNU Emacs called the "Lisp interpreter"--giving the -interpreter a command to evaluate the expression. The name of the -Lisp interpreter comes from the word for the task done by a human who -comes up with the meaning of an expression--who "interprets" it. - -You can also evaluate an atom that is not part of a list--one that is -not surrounded by parentheses; again, the Lisp interpreter translates -from the humanly readable expression to the language of the computer. -But before discussing this (*note Variables::), we will discuss what -the Lisp interpreter does when you make an error. - -Generate an Error Message -========================= - -Partly so you won't worry if you do it accidentally, we will now give -a command to the Lisp interpreter that generates an error message. -This is a harmless activity; and indeed, we will often try to generate -error messages intentionally. Once you understand the jargon, error -messages can be informative. Instead of being called "error" -messages, they should be called "help" messages. They are like -signposts to a traveller in a strange country; deciphering them can be -hard, but once understood, they can point the way. - -The error message is generated by a built-in GNU Emacs debugger. We -will `enter the debugger'. You get out of the debugger by typing `q'. - -What we will do is evaluate a list that is not quoted and does not -have a meaningful command as its first element. Here is a list almost -exactly the same as the one we just used, but without the single-quote -in front of it. Position the cursor right after it and type `C-x -C-e': - - (this is an unquoted list) - -What you see depends on which version of Emacs you are running. GNU -Emacs version 21 provides more information than version 20 and before. -First, the more recent result of generating an error; then the -earlier, version 20 result. - -In GNU Emacs version 21, a `*Backtrace*' window will open up and you -will see the following in it: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--Lisp error: (void-function this) - (this is an unquoted list) - eval((this is an unquoted list)) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -Your cursor will be in this window (you may have to wait a few seconds -before it becomes visible). To quit the debugger and make the -debugger window go away, type: - - q - -Please type `q' right now, so you become confident that you can get -out of the debugger. Then, type `C-x C-e' again to re-enter it. - -Based on what we already know, we can almost read this error message. - -You read the `*Backtrace*' buffer from the bottom up; it tells you -what Emacs did. When you typed `C-x C-e', you made an interactive -call to the command `eval-last-sexp'. `eval' is an abbreviation for -`evaluate' and `sexp' is an abbreviation for `symbolic expression'. -The command means `evaluate last symbolic expression', which is the -expression just before your cursor. - -Each line above tells you what the Lisp interpreter evaluated next. -The most recent action is at the top. The buffer is called the -`*Backtrace*' buffer because it enables you to track Emacs backwards. - -At the top of the `*Backtrace*' buffer, you see the line: - - Debugger entered--Lisp error: (void-function this) - -The Lisp interpreter tried to evaluate the first atom of the list, the -word `this'. It is this action that generated the error message -`void-function this'. - -The message contains the words `void-function' and `this'. - -The word `function' was mentioned once before. It is a very -important word. For our purposes, we can define it by saying that a -"function" is a set of instructions to the computer that tell the -computer to do something. - -Now we can begin to understand the error message: `void-function -this'. The function (that is, the word `this') does not have a -definition of any set of instructions for the computer to carry out. - -The slightly odd word, `void-function', is designed to cover the way -Emacs Lisp is implemented, which is that when a symbol does not have -a function definition attached to it, the place that should contain -the instructions is `void'. - -On the other hand, since we were able to add 2 plus 2 successfully, by -evaluating `(+ 2 2)', we can infer that the symbol `+' must have a -set of instructions for the computer to obey and those instructions -must be to add the numbers that follow the `+'. - -In GNU Emacs version 20, and in earlier versions, you will see only -one line of error message; it will appear in the echo area and look -like this: - - Symbol's function definition is void: this - -(Also, your terminal may beep at you--some do, some don't; and others -blink. This is just a device to get your attention.) The message -goes away as soon as you type another key, even just to move the -cursor. - -We know the meaning of the word `Symbol'. It refers to the first -atom of the list, the word `this'. The word `function' refers to the -instructions that tell the computer what to do. (Technically, the -symbol tells the computer where to find the instructions, but this is -a complication we can ignore for the moment.) - -The error message can be understood: `Symbol's function definition is -void: this'. The symbol (that is, the word `this') lacks -instructions for the computer to carry out. - -Symbol Names and Function Definitions -===================================== - -We can articulate another characteristic of Lisp based on what we have -discussed so far--an important characteristic: a symbol, like `+', is -not itself the set of instructions for the computer to carry out. -Instead, the symbol is used, perhaps temporarily, as a way of -locating the definition or set of instructions. What we see is the -name through which the instructions can be found. Names of people -work the same way. I can be referred to as `Bob'; however, I am not -the letters `B', `o', `b' but am the consciousness consistently -associated with a particular life-form. The name is not me, but it -can be used to refer to me. - -In Lisp, one set of instructions can be attached to several names. -For example, the computer instructions for adding numbers can be -linked to the symbol `plus' as well as to the symbol `+' (and are in -some dialects of Lisp). Among humans, I can be referred to as -`Robert' as well as `Bob' and by other words as well. - -On the other hand, a symbol can have only one function definition -attached to it at a time. Otherwise, the computer would be confused -as to which definition to use. If this were the case among people, -only one person in the world could be named `Bob'. However, the -function definition to which the name refers can be changed readily. -(*Note Install a Function Definition: Install.) - -Since Emacs Lisp is large, it is customary to name symbols in a way -that identifies the part of Emacs to which the function belongs. -Thus, all the names for functions that deal with Texinfo start with -`texinfo-' and those for functions that deal with reading mail start -with `rmail-'. - -The Lisp Interpreter -==================== - -Based on what we have seen, we can now start to figure out what the -Lisp interpreter does when we command it to evaluate a list. First, -it looks to see whether there is a quote before the list; if there -is, the interpreter just gives us the list. On the other hand, if -there is no quote, the interpreter looks at the first element in the -list and sees whether it has a function definition. If it does, the -interpreter carries out the instructions in the function definition. -Otherwise, the interpreter prints an error message. - -This is how Lisp works. Simple. There are added complications which -we will get to in a minute, but these are the fundamentals. Of -course, to write Lisp programs, you need to know how to write -function definitions and attach them to names, and how to do this -without confusing either yourself or the computer. - -Complications -------------- - -Now, for the first complication. In addition to lists, the Lisp -interpreter can evaluate a symbol that is not quoted and does not have -parentheses around it. The Lisp interpreter will attempt to determine -the symbol's value as a "variable". This situation is described in -the section on variables. (*Note Variables::.) - -The second complication occurs because some functions are unusual and -do not work in the usual manner. Those that don't are called "special -forms". They are used for special jobs, like defining a function, and -there are not many of them. In the next few chapters, you will be -introduced to several of the more important special forms. - -The third and final complication is this: if the function that the -Lisp interpreter is looking at is not a special form, and if it is -part of a list, the Lisp interpreter looks to see whether the list -has a list inside of it. If there is an inner list, the Lisp -interpreter first figures out what it should do with the inside list, -and then it works on the outside list. If there is yet another list -embedded inside the inner list, it works on that one first, and so -on. It always works on the innermost list first. The interpreter -works on the innermost list first, to evaluate the result of that -list. The result may be used by the enclosing expression. - -Otherwise, the interpreter works left to right, from one expression to -the next. - -Byte Compiling --------------- - -One other aspect of interpreting: the Lisp interpreter is able to -interpret two kinds of entity: humanly readable code, on which we will -focus exclusively, and specially processed code, called "byte -compiled" code, which is not humanly readable. Byte compiled code -runs faster than humanly readable code. - -You can transform humanly readable code into byte compiled code by -running one of the compile commands such as `byte-compile-file'. -Byte compiled code is usually stored in a file that ends with a -`.elc' extension rather than a `.el' extension. You will see both -kinds of file in the `emacs/lisp' directory; the files to read are -those with `.el' extensions. - -As a practical matter, for most things you might do to customize or -extend Emacs, you do not need to byte compile; and I will not discuss -the topic here. *Note Byte Compilation: (elisp)Byte Compilation, for -a full description of byte compilation. - -Evaluation -========== - -When the Lisp interpreter works on an expression, the term for the -activity is called "evaluation". We say that the interpreter -`evaluates the expression'. I've used this term several times before. -The word comes from its use in everyday language, `to ascertain the -value or amount of; to appraise', according to `Webster's New -Collegiate Dictionary'. - -After evaluating an expression, the Lisp interpreter will most likely -"return" the value that the computer produces by carrying out the -instructions it found in the function definition, or perhaps it will -give up on that function and produce an error message. (The -interpreter may also find itself tossed, so to speak, to a different -function or it may attempt to repeat continually what it is doing for -ever and ever in what is called an `infinite loop'. These actions -are less common; and we can ignore them.) Most frequently, the -interpreter returns a value. - -At the same time the interpreter returns a value, it may do something -else as well, such as move a cursor or copy a file; this other kind of -action is called a "side effect". Actions that we humans think are -important, such as printing results, are often "side effects" to the -Lisp interpreter. The jargon can sound peculiar, but it turns out -that it is fairly easy to learn to use side effects. - -In summary, evaluating a symbolic expression most commonly causes the -Lisp interpreter to return a value and perhaps carry out a side -effect; or else produce an error. - -Evaluating Inner Lists ----------------------- - -If evaluation applies to a list that is inside another list, the outer -list may use the value returned by the first evaluation as information -when the outer list is evaluated. This explains why inner expressions -are evaluated first: the values they return are used by the outer -expressions. - -We can investigate this process by evaluating another addition -example. Place your cursor after the following expression and type -`C-x C-e': - - (+ 2 (+ 3 3)) - -The number 8 will appear in the echo area. - -What happens is that the Lisp interpreter first evaluates the inner -expression, `(+ 3 3)', for which the value 6 is returned; then it -evaluates the outer expression as if it were written `(+ 2 6)', which -returns the value 8. Since there are no more enclosing expressions to -evaluate, the interpreter prints that value in the echo area. - -Now it is easy to understand the name of the command invoked by the -keystrokes `C-x C-e': the name is `eval-last-sexp'. The letters -`sexp' are an abbreviation for `symbolic expression', and `eval' is -an abbreviation for `evaluate'. The command means `evaluate last -symbolic expression'. - -As an experiment, you can try evaluating the expression by putting the -cursor at the beginning of the next line immediately following the -expression, or inside the expression. - -Here is another copy of the expression: - - (+ 2 (+ 3 3)) - -If you place the cursor at the beginning of the blank line that -immediately follows the expression and type `C-x C-e', you will still -get the value 8 printed in the echo area. Now try putting the cursor -inside the expression. If you put it right after the next to last -parenthesis (so it appears to sit on top of the last parenthesis), -you will get a 6 printed in the echo area! This is because the -command evaluates the expression `(+ 3 3)'. - -Now put the cursor immediately after a number. Type `C-x C-e' and -you will get the number itself. In Lisp, if you evaluate a number, -you get the number itself--this is how numbers differ from symbols. -If you evaluate a list starting with a symbol like `+', you will get a -value returned that is the result of the computer carrying out the -instructions in the function definition attached to that name. If a -symbol by itself is evaluated, something different happens, as we will -see in the next section. - -Variables -========= - -In Emacs Lisp, a symbol can have a value attached to it just as it can -have a function definition attached to it. The two are different. -The function definition is a set of instructions that a computer will -obey. A value, on the other hand, is something, such as number or a -name, that can vary (which is why such a symbol is called a variable). -The value of a symbol can be any expression in Lisp, such as a symbol, -number, list, or string. A symbol that has a value is often called a -"variable". - -A symbol can have both a function definition and a value attached to -it at the same time. Or it can have just one or the other. The two -are separate. This is somewhat similar to the way the name Cambridge -can refer to the city in Massachusetts and have some information -attached to the name as well, such as "great programming center". - -Another way to think about this is to imagine a symbol as being a -chest of drawers. The function definition is put in one drawer, the -value in another, and so on. What is put in the drawer holding the -value can be changed without affecting the contents of the drawer -holding the function definition, and vice-versa. - -`fill-column', an Example Variable ----------------------------------- - -The variable `fill-column' illustrates a symbol with a value attached -to it: in every GNU Emacs buffer, this symbol is set to some value, -usually 72 or 70, but sometimes to some other value. To find the -value of this symbol, evaluate it by itself. If you are reading this -in Info inside of GNU Emacs, you can do this by putting the cursor -after the symbol and typing `C-x C-e': - - fill-column - -After I typed `C-x C-e', Emacs printed the number 72 in my echo area. -This is the value for which `fill-column' is set for me as I write -this. It may be different for you in your Info buffer. Notice that -the value returned as a variable is printed in exactly the same way -as the value returned by a function carrying out its instructions. -From the point of view of the Lisp interpreter, a value returned is a -value returned. What kind of expression it came from ceases to -matter once the value is known. - -A symbol can have any value attached to it or, to use the jargon, we -can "bind" the variable to a value: to a number, such as 72; to a -string, `"such as this"'; to a list, such as `(spruce pine oak)'; we -can even bind a variable to a function definition. - -A symbol can be bound to a value in several ways. *Note Setting the -Value of a Variable: set & setq, for information about one way to do -this. - -Error Message for a Symbol Without a Function ---------------------------------------------- - -When we evaluated `fill-column' to find its value as a variable, we -did not place parentheses around the word. This is because we did -not intend to use it as a function name. - -If `fill-column' were the first or only element of a list, the Lisp -interpreter would attempt to find the function definition attached to -it. But `fill-column' has no function definition. Try evaluating -this: - - (fill-column) - -In GNU Emacs version 21, you will create a `*Backtrace*' buffer that -says: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--Lisp error: (void-function fill-column) - (fill-column) - eval((fill-column)) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -(Remember, to quit the debugger and make the debugger window go away, -type `q' in the `*Backtrace*' buffer.) - -In GNU Emacs 20 and before, you will produce an error message that -says: - - Symbol's function definition is void: fill-column - -(The message will go away away as soon as you move the cursor or type -another key.) - -Error Message for a Symbol Without a Value ------------------------------------------- - -If you attempt to evaluate a symbol that does not have a value bound -to it, you will receive an error message. You can see this by -experimenting with our 2 plus 2 addition. In the following -expression, put your cursor right after the `+', before the first -number 2, type `C-x C-e': - - (+ 2 2) - -In GNU Emacs 21, you will create a `*Backtrace*' buffer that says: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--Lisp error: (void-variable +) - eval(+) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -(As with the other times we entered the debugger, you can quit by -typing `q' in the `*Backtrace*' buffer.) - -This backtrace is different from the very first error message we saw, -which said, `Debugger entered--Lisp error: (void-function this)'. In -this case, the function does not have a value as a variable; while in -the other error message, the function (the word `this') did not have -a definition. - -In this experiment with the `+', what we did was cause the Lisp -interpreter to evaluate the `+' and look for the value of the -variable instead of the function definition. We did this by placing -the cursor right after the symbol rather than after the parenthesis -of the enclosing list as we did before. As a consequence, the Lisp -interpreter evaluated the preceding s-expression, which in this case -was the `+' by itself. - -Since `+' does not have a value bound to it, just the function -definition, the error message reported that the symbol's value as a -variable was void. - -In GNU Emacs version 20 and before, your error message will say: - - Symbol's value as variable is void: + - -The meaning is the same as in GNU Emacs 21. - -Arguments -========= - -To see how information is passed to functions, let's look again at -our old standby, the addition of two plus two. In Lisp, this is -written as follows: - - (+ 2 2) - -If you evaluate this expression, the number 4 will appear in your echo -area. What the Lisp interpreter does is add the numbers that follow -the `+'. - -The numbers added by `+' are called the "arguments" of the function -`+'. These numbers are the information that is given to or "passed" -to the function. - -The word `argument' comes from the way it is used in mathematics and -does not refer to a disputation between two people; instead it refers -to the information presented to the function, in this case, to the -`+'. In Lisp, the arguments to a function are the atoms or lists -that follow the function. The values returned by the evaluation of -these atoms or lists are passed to the function. Different functions -require different numbers of arguments; some functions require none at -all.(1) - ----------- Footnotes ---------- - -(1) It is curious to track the path by which the word `argument' came -to have two different meanings, one in mathematics and the other in -everyday English. According to the `Oxford English Dictionary', the -word derives from the Latin for `to make clear, prove'; thus it came -to mean, by one thread of derivation, `the evidence offered as -proof', which is to say, `the information offered', which led to its -meaning in Lisp. But in the other thread of derivation, it came to -mean `to assert in a manner against which others may make counter -assertions', which led to the meaning of the word as a disputation. -(Note here that the English word has two different definitions -attached to it at the same time. By contrast, in Emacs Lisp, a -symbol cannot have two different function definitions at the same -time.) - -Arguments' Data Types ---------------------- - -The type of data that should be passed to a function depends on what -kind of information it uses. The arguments to a function such as `+' -must have values that are numbers, since `+' adds numbers. Other -functions use different kinds of data for their arguments. - -For example, the `concat' function links together or unites two or -more strings of text to produce a string. The arguments are strings. -Concatenating the two character strings `abc', `def' produces the -single string `abcdef'. This can be seen by evaluating the following: - - (concat "abc" "def") - -The value produced by evaluating this expression is `"abcdef"'. - -A function such as `substring' uses both a string and numbers as -arguments. The function returns a part of the string, a substring of -the first argument. This function takes three arguments. Its first -argument is the string of characters, the second and third arguments -are numbers that indicate the beginning and end of the substring. The -numbers are a count of the number of characters (including spaces and -punctuations) from the beginning of the string. - -For example, if you evaluate the following: - - (substring "The quick brown fox jumped." 16 19) - -you will see `"fox"' appear in the echo area. The arguments are the -string and the two numbers. - -Note that the string passed to `substring' is a single atom even -though it is made up of several words separated by spaces. Lisp -counts everything between the two quotation marks as part of the -string, including the spaces. You can think of the `substring' -function as a kind of `atom smasher' since it takes an otherwise -indivisible atom and extracts a part. However, `substring' is only -able to extract a substring from an argument that is a string, not -from another type of atom such as a number or symbol. - -An Argument as the Value of a Variable or List ----------------------------------------------- - -An argument can be a symbol that returns a value when it is evaluated. -For example, when the symbol `fill-column' by itself is evaluated, it -returns a number. This number can be used in an addition. - -Position the cursor after the following expression and type `C-x C-e': - - (+ 2 fill-column) - -The value will be a number two more than what you get by evaluating -`fill-column' alone. For me, this is 74, because the value of -`fill-column' is 72. - -As we have just seen, an argument can be a symbol that returns a value -when evaluated. In addition, an argument can be a list that returns a -value when it is evaluated. For example, in the following expression, -the arguments to the function `concat' are the strings `"The "' and -`" red foxes."' and the list `(number-to-string (+ 2 fill-column))'. - - (concat "The " (number-to-string (+ 2 fill-column)) " red foxes.") - -If you evaluate this expression--and if, as with my Emacs, -`fill-column' evaluates to 72--`"The 74 red foxes."' will appear in -the echo area. (Note that you must put spaces after the word `The' -and before the word `red' so they will appear in the final string. -The function `number-to-string' converts the integer that the -addition function returns to a string. `number-to-string' is also -known as `int-to-string'.) - -Variable Number of Arguments ----------------------------- - -Some functions, such as `concat', `+' or `*', take any number of -arguments. (The `*' is the symbol for multiplication.) This can be -seen by evaluating each of the following expressions in the usual -way. What you will see in the echo area is printed in this text -after `=>', which you may read as `evaluates to'. - -In the first set, the functions have no arguments: - - (+) => 0 - - (*) => 1 - -In this set, the functions have one argument each: - - (+ 3) => 3 - - (* 3) => 3 - -In this set, the functions have three arguments each: - - (+ 3 4 5) => 12 - - (* 3 4 5) => 60 - -Using the Wrong Type Object as an Argument ------------------------------------------- - -When a function is passed an argument of the wrong type, the Lisp -interpreter produces an error message. For example, the `+' function -expects the values of its arguments to be numbers. As an experiment -we can pass it the quoted symbol `hello' instead of a number. -Position the cursor after the following expression and type `C-x C-e': - - (+ 2 'hello) - -When you do this you will generate an error message. What has -happened is that `+' has tried to add the 2 to the value returned by -`'hello', but the value returned by `'hello' is the symbol `hello', -not a number. Only numbers can be added. So `+' could not carry out -its addition. - -In GNU Emacs version 21, you will create and enter a `*Backtrace*' -buffer that says: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--Lisp error: - (wrong-type-argument number-or-marker-p hello) - +(2 hello) - eval((+ 2 (quote hello))) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -As usual, the error message tries to be helpful and makes sense after -you learn how to read it. - -The first part of the error message is straightforward; it says -`wrong type argument'. Next comes the mysterious jargon word -`number-or-marker-p'. This word is trying to tell you what kind of -argument the `+' expected. - -The symbol `number-or-marker-p' says that the Lisp interpreter is -trying to determine whether the information presented it (the value of -the argument) is a number or a marker (a special object representing a -buffer position). What it does is test to see whether the `+' is -being given numbers to add. It also tests to see whether the -argument is something called a marker, which is a specific feature of -Emacs Lisp. (In Emacs, locations in a buffer are recorded as markers. -When the mark is set with the `C-@' or `C-<SPC>' command, its -position is kept as a marker. The mark can be considered a -number--the number of characters the location is from the beginning -of the buffer.) In Emacs Lisp, `+' can be used to add the numeric -value of marker positions as numbers. - -The `p' of `number-or-marker-p' is the embodiment of a practice -started in the early days of Lisp programming. The `p' stands for -`predicate'. In the jargon used by the early Lisp researchers, a -predicate refers to a function to determine whether some property is -true or false. So the `p' tells us that `number-or-marker-p' is the -name of a function that determines whether it is true or false that -the argument supplied is a number or a marker. Other Lisp symbols -that end in `p' include `zerop', a function that tests whether its -argument has the value of zero, and `listp', a function that tests -whether its argument is a list. - -Finally, the last part of the error message is the symbol `hello'. -This is the value of the argument that was passed to `+'. If the -addition had been passed the correct type of object, the value passed -would have been a number, such as 37, rather than a symbol like -`hello'. But then you would not have got the error message. - -In GNU Emacs version 20 and before, the echo area displays an error -message that says: - - Wrong type argument: number-or-marker-p, hello - -This says, in different words, the same as the top line of the -`*Backtrace*' buffer. - -The `message' Function ----------------------- - -Like `+', the `message' function takes a variable number of -arguments. It is used to send messages to the user and is so useful -that we will describe it here. - -A message is printed in the echo area. For example, you can print a -message in your echo area by evaluating the following list: - - (message "This message appears in the echo area!") - -The whole string between double quotation marks is a single argument -and is printed in toto. (Note that in this example, the message -itself will appear in the echo area within double quotes; that is -because you see the value returned by the `message' function. In -most uses of `message' in programs that you write, the text will be -printed in the echo area as a side-effect, without the quotes. *Note -`multiply-by-seven' in detail: multiply-by-seven in detail, for an -example of this.) - -However, if there is a `%s' in the quoted string of characters, the -`message' function does not print the `%s' as such, but looks to the -argument that follows the string. It evaluates the second argument -and prints the value at the location in the string where the `%s' is. - -You can see this by positioning the cursor after the following -expression and typing `C-x C-e': - - (message "The name of this buffer is: %s." (buffer-name)) - -In Info, `"The name of this buffer is: *info*."' will appear in the -echo area. The function `buffer-name' returns the name of the buffer -as a string, which the `message' function inserts in place of `%s'. - -To print a value as an integer, use `%d' in the same way as `%s'. -For example, to print a message in the echo area that states the -value of the `fill-column', evaluate the following: - - (message "The value of fill-column is %d." fill-column) - -On my system, when I evaluate this list, `"The value of fill-column -is 72."' appears in my echo area(1). - -If there is more than one `%s' in the quoted string, the value of the -first argument following the quoted string is printed at the location -of the first `%s' and the value of the second argument is printed at -the location of the second `%s', and so on. - -For example, if you evaluate the following, - - (message "There are %d %s in the office!" - (- fill-column 14) "pink elephants") - -a rather whimsical message will appear in your echo area. On my -system it says, `"There are 58 pink elephants in the office!"'. - -The expression `(- fill-column 14)' is evaluated and the resulting -number is inserted in place of the `%d'; and the string in double -quotes, `"pink elephants"', is treated as a single argument and -inserted in place of the `%s'. (That is to say, a string between -double quotes evaluates to itself, like a number.) - -Finally, here is a somewhat complex example that not only illustrates -the computation of a number, but also shows how you can use an -expression within an expression to generate the text that is -substituted for `%s': - - (message "He saw %d %s" - (- fill-column 34) - (concat "red " - (substring - "The quick brown foxes jumped." 16 21) - " leaping.")) - -In this example, `message' has three arguments: the string, `"He saw -%d %s"', the expression, `(- fill-column 32)', and the expression -beginning with the function `concat'. The value resulting from the -evaluation of `(- fill-column 32)' is inserted in place of the `%d'; -and the value returned by the expression beginning with `concat' is -inserted in place of the `%s'. - -When I evaluate the expression, the message `"He saw 38 red foxes -leaping."' appears in my echo area. - ----------- Footnotes ---------- - -(1) Actually, you can use `%s' to print a number. It is -non-specific. `%d' prints only the part of a number left of a -decimal point, and not anything that is not a number. - -Setting the Value of a Variable -=============================== - -There are several ways by which a variable can be given a value. One -of the ways is to use either the function `set' or the function -`setq'. Another way is to use `let' (*note let::). (The jargon for -this process is to "bind" a variable to a value.) - -The following sections not only describe how `set' and `setq' work -but also illustrate how arguments are passed. - -Using `set' ------------ - -To set the value of the symbol `flowers' to the list `'(rose violet -daisy buttercup)', evaluate the following expression by positioning -the cursor after the expression and typing `C-x C-e'. - - (set 'flowers '(rose violet daisy buttercup)) - -The list `(rose violet daisy buttercup)' will appear in the echo -area. This is what is _returned_ by the `set' function. As a side -effect, the symbol `flowers' is bound to the list ; that is, the -symbol `flowers', which can be viewed as a variable, is given the -list as its value. (This process, by the way, illustrates how a side -effect to the Lisp interpreter, setting the value, can be the primary -effect that we humans are interested in. This is because every Lisp -function must return a value if it does not get an error, but it will -only have a side effect if it is designed to have one.) - -After evaluating the `set' expression, you can evaluate the symbol -`flowers' and it will return the value you just set. Here is the -symbol. Place your cursor after it and type `C-x C-e'. - - flowers - -When you evaluate `flowers', the list `(rose violet daisy buttercup)' -appears in the echo area. - -Incidentally, if you evaluate `'flowers', the variable with a quote -in front of it, what you will see in the echo area is the symbol -itself, `flowers'. Here is the quoted symbol, so you can try this: - - 'flowers - -Note also, that when you use `set', you need to quote both arguments -to `set', unless you want them evaluated. Since we do not want -either argument evaluated, neither the variable `flowers' nor the -list `(rose violet daisy buttercup)', both are quoted. (When you use -`set' without quoting its first argument, the first argument is -evaluated before anything else is done. If you did this and -`flowers' did not have a value already, you would get an error -message that the `Symbol's value as variable is void'; on the other -hand, if `flowers' did return a value after it was evaluated, the -`set' would attempt to set the value that was returned. There are -situations where this is the right thing for the function to do; but -such situations are rare.) - -Using `setq' ------------- - -As a practical matter, you almost always quote the first argument to -`set'. The combination of `set' and a quoted first argument is so -common that it has its own name: the special form `setq'. This -special form is just like `set' except that the first argument is -quoted automatically, so you don't need to type the quote mark -yourself. Also, as an added convenience, `setq' permits you to set -several different variables to different values, all in one -expression. - -To set the value of the variable `carnivores' to the list `'(lion -tiger leopard)' using `setq', the following expression is used: - - (setq carnivores '(lion tiger leopard)) - -This is exactly the same as using `set' except the first argument is -automatically quoted by `setq'. (The `q' in `setq' means `quote'.) - -With `set', the expression would look like this: - - (set 'carnivores '(lion tiger leopard)) - -Also, `setq' can be used to assign different values to different -variables. The first argument is bound to the value of the second -argument, the third argument is bound to the value of the fourth -argument, and so on. For example, you could use the following to -assign a list of trees to the symbol `trees' and a list of herbivores -to the symbol `herbivores': - - (setq trees '(pine fir oak maple) - herbivores '(gazelle antelope zebra)) - -(The expression could just as well have been on one line, but it might -not have fit on a page; and humans find it easier to read nicely -formatted lists.) - -Although I have been using the term `assign', there is another way of -thinking about the workings of `set' and `setq'; and that is to say -that `set' and `setq' make the symbol _point_ to the list. This -latter way of thinking is very common and in forthcoming chapters we -shall come upon at least one symbol that has `pointer' as part of its -name. The name is chosen because the symbol has a value, -specifically a list, attached to it; or, expressed another way, the -symbol is set to "point" to the list. - -Counting --------- - -Here is an example that shows how to use `setq' in a counter. You -might use this to count how many times a part of your program repeats -itself. First set a variable to zero; then add one to the number each -time the program repeats itself. To do this, you need a variable that -serves as a counter, and two expressions: an initial `setq' -expression that sets the counter variable to zero; and a second -`setq' expression that increments the counter each time it is -evaluated. - - (setq counter 0) ; Let's call this the initializer. - - (setq counter (+ counter 1)) ; This is the incrementer. - - counter ; This is the counter. - -(The text following the `;' are comments. *Note Change a Function -Definition: Change a defun.) - -If you evaluate the first of these expressions, the initializer, -`(setq counter 0)', and then evaluate the third expression, -`counter', the number `0' will appear in the echo area. If you then -evaluate the second expression, the incrementer, `(setq counter (+ -counter 1))', the counter will get the value 1. So if you again -evaluate `counter', the number `1' will appear in the echo area. -Each time you evaluate the second expression, the value of the -counter will be incremented. - -When you evaluate the incrementer, `(setq counter (+ counter 1))', -the Lisp interpreter first evaluates the innermost list; this is the -addition. In order to evaluate this list, it must evaluate the -variable `counter' and the number `1'. When it evaluates the variable -`counter', it receives its current value. It passes this value and -the number `1' to the `+' which adds them together. The sum is then -returned as the value of the inner list and passed to the `setq' -which sets the variable `counter' to this new value. Thus, the value -of the variable, `counter', is changed. - -Summary -======= - -Learning Lisp is like climbing a hill in which the first part is the -steepest. You have now climbed the most difficult part; what remains -becomes easier as you progress onwards. - -In summary, - - * Lisp programs are made up of expressions, which are lists or - single atoms. - - * Lists are made up of zero or more atoms or inner lists, - separated by whitespace and surrounded by parentheses. A list - can be empty. - - * Atoms are multi-character symbols, like `forward-paragraph', - single character symbols like `+', strings of characters between - double quotation marks, or numbers. - - * A number evaluates to itself. - - * A string between double quotes also evaluates to itself. - - * When you evaluate a symbol by itself, its value is returned. - - * When you evaluate a list, the Lisp interpreter looks at the - first symbol in the list and then at the function definition - bound to that symbol. Then the instructions in the function - definition are carried out. - - * A single-quote, `'', tells the Lisp interpreter that it should - return the following expression as written, and not evaluate it - as it would if the quote were not there. - - * Arguments are the information passed to a function. The - arguments to a function are computed by evaluating the rest of - the elements of the list of which the function is the first - element. - - * A function always returns a value when it is evaluated (unless - it gets an error); in addition, it may also carry out some - action called a "side effect". In many cases, a function's - primary purpose is to create a side effect. - -Exercises -========= - -A few simple exercises: - - * Generate an error message by evaluating an appropriate symbol - that is not within parentheses. - - * Generate an error message by evaluating an appropriate symbol - that is between parentheses. - - * Create a counter that increments by two rather than one. - - * Write an expression that prints a message in the echo area when - evaluated. - -Practicing Evaluation -********************* - -Before learning how to write a function definition in Emacs Lisp, it -is useful to spend a little time evaluating various expressions that -have already been written. These expressions will be lists with the -functions as their first (and often only) element. Since some of the -functions associated with buffers are both simple and interesting, we -will start with those. In this section, we will evaluate a few of -these. In another section, we will study the code of several other -buffer-related functions, to see how they were written. - -How to Evaluate -=============== - -Whenever you give an editing command to Emacs Lisp, such as the -command to move the cursor or to scroll the screen, you are evaluating -an expression, the first element of which is a function. This is how -Emacs works. - -When you type keys, you cause the Lisp interpreter to evaluate an -expression and that is how you get your results. Even typing plain -text involves evaluating an Emacs Lisp function, in this case, one -that uses `self-insert-command', which simply inserts the character -you typed. The functions you evaluate by typing keystrokes are called -"interactive" functions, or "commands"; how you make a function -interactive will be illustrated in the chapter on how to write -function definitions. *Note Making a Function Interactive: -Interactive. - -In addition to typing keyboard commands, we have seen a second way to -evaluate an expression: by positioning the cursor after a list and -typing `C-x C-e'. This is what we will do in the rest of this -section. There are other ways to evaluate an expression as well; -these will be described as we come to them. - -Besides being used for practicing evaluation, the functions shown in -the next few sections are important in their own right. A study of -these functions makes clear the distinction between buffers and -files, how to switch to a buffer, and how to determine a location -within it. - -Buffer Names -============ - -The two functions, `buffer-name' and `buffer-file-name', show the -difference between a file and a buffer. When you evaluate the -following expression, `(buffer-name)', the name of the buffer appears -in the echo area. When you evaluate `(buffer-file-name)', the name -of the file to which the buffer refers appears in the echo area. -Usually, the name returned by `(buffer-name)' is the same as the name -of the file to which it refers, and the name returned by -`(buffer-file-name)' is the full path-name of the file. - -A file and a buffer are two different entities. A file is information -recorded permanently in the computer (unless you delete it). A -buffer, on the other hand, is information inside of Emacs that will -vanish at the end of the editing session (or when you kill the -buffer). Usually, a buffer contains information that you have copied -from a file; we say the buffer is "visiting" that file. This copy is -what you work on and modify. Changes to the buffer do not change the -file, until you save the buffer. When you save the buffer, the -buffer is copied to the file and is thus saved permanently. - -If you are reading this in Info inside of GNU Emacs, you can evaluate -each of the following expressions by positioning the cursor after it -and typing `C-x C-e'. - - (buffer-name) - - (buffer-file-name) - -When I do this, `"introduction.texinfo"' is the value returned by -evaluating `(buffer-name)', and -`"/gnu/work/intro/introduction.texinfo"' is the value returned by -evaluating `(buffer-file-name)'. The former is the name of the -buffer and the latter is the name of the file. (In the expressions, -the parentheses tell the Lisp interpreter to treat `buffer-name' and -`buffer-file-name' as functions; without the parentheses, the -interpreter would attempt to evaluate the symbols as variables. -*Note Variables::.) - -In spite of the distinction between files and buffers, you will often -find that people refer to a file when they mean a buffer and -vice-versa. Indeed, most people say, "I am editing a file," rather -than saying, "I am editing a buffer which I will soon save to a -file." It is almost always clear from context what people mean. -When dealing with computer programs, however, it is important to keep -the distinction in mind, since the computer is not as smart as a -person. - -The word `buffer', by the way, comes from the meaning of the word as a -cushion that deadens the force of a collision. In early computers, a -buffer cushioned the interaction between files and the computer's -central processing unit. The drums or tapes that held a file and the -central processing unit were pieces of equipment that were very -different from each other, working at their own speeds, in spurts. -The buffer made it possible for them to work together effectively. -Eventually, the buffer grew from being an intermediary, a temporary -holding place, to being the place where work is done. This -transformation is rather like that of a small seaport that grew into a -great city: once it was merely the place where cargo was warehoused -temporarily before being loaded onto ships; then it became a business -and cultural center in its own right. - -Not all buffers are associated with files. For example, when you -start an Emacs session by typing the command `emacs' alone, without -naming any files, Emacs will start with the `*scratch*' buffer on the -screen. This buffer is not visiting any file. Similarly, a `*Help*' -buffer is not associated with any file. - -If you switch to the `*scratch*' buffer, type `(buffer-name)', -position the cursor after it, and type `C-x C-e' to evaluate the -expression, the name `"*scratch*"' is returned and will appear in the -echo area. `"*scratch*"' is the name of the buffer. However, if you -type `(buffer-file-name)' in the `*scratch*' buffer and evaluate -that, `nil' will appear in the echo area. `nil' is from the Latin -word for `nothing'; in this case, it means that the `*scratch*' -buffer is not associated with any file. (In Lisp, `nil' is also used -to mean `false' and is a synonym for the empty list, `()'.) - -Incidentally, if you are in the `*scratch*' buffer and want the value -returned by an expression to appear in the `*scratch*' buffer itself -rather than in the echo area, type `C-u C-x C-e' instead of `C-x -C-e'. This causes the value returned to appear after the expression. -The buffer will look like this: - - (buffer-name)"*scratch*" - -You cannot do this in Info since Info is read-only and it will not -allow you to change the contents of the buffer. But you can do this -in any buffer you can edit; and when you write code or documentation -(such as this book), this feature is very useful. - -Getting Buffers -=============== - -The `buffer-name' function returns the _name_ of the buffer; to get -the buffer _itself_, a different function is needed: the -`current-buffer' function. If you use this function in code, what -you get is the buffer itself. - -A name and the object or entity to which the name refers are different -from each other. You are not your name. You are a person to whom -others refer by name. If you ask to speak to George and someone -hands you a card with the letters `G', `e', `o', `r', `g', and `e' -written on it, you might be amused, but you would not be satisfied. -You do not want to speak to the name, but to the person to whom the -name refers. A buffer is similar: the name of the scratch buffer is -`*scratch*', but the name is not the buffer. To get a buffer itself, -you need to use a function such as `current-buffer'. - -However, there is a slight complication: if you evaluate -`current-buffer' in an expression on its own, as we will do here, -what you see is a printed representation of the name of the buffer -without the contents of the buffer. Emacs works this way for two -reasons: the buffer may be thousands of lines long--too long to be -conveniently displayed; and, another buffer may have the same contents -but a different name, and it is important to distinguish between them. - -Here is an expression containing the function: - - (current-buffer) - -If you evaluate the expression in the usual way, `#<buffer *info*>' -appears in the echo area. The special format indicates that the -buffer itself is being returned, rather than just its name. - -Incidentally, while you can type a number or symbol into a program, -you cannot do that with the printed representation of a buffer: the -only way to get a buffer itself is with a function such as -`current-buffer'. - -A related function is `other-buffer'. This returns the most recently -selected buffer other than the one you are in currently. If you have -recently switched back and forth from the `*scratch*' buffer, -`other-buffer' will return that buffer. - -You can see this by evaluating the expression: - - (other-buffer) - -You should see `#<buffer *scratch*>' appear in the echo area, or the -name of whatever other buffer you switched back from most recently(1). - ----------- Footnotes ---------- - -(1) Actually, by default, if the buffer from which you just switched -is visible to you in another window, `other-buffer' will choose the -most recent buffer that you cannot see; this is a subtlety that I -often forget. - -Switching Buffers -================= - -The `other-buffer' function actually provides a buffer when it is -used as an argument to a function that requires one. We can see this -by using `other-buffer' and `switch-to-buffer' to switch to a -different buffer. - -But first, a brief introduction to the `switch-to-buffer' function. -When you switched back and forth from Info to the `*scratch*' buffer -to evaluate `(buffer-name)', you most likely typed `C-x b' and then -typed `*scratch*'(1) when prompted in the minibuffer for the name of -the buffer to which you wanted to switch. The keystrokes, `C-x b', -cause the Lisp interpreter to evaluate the interactive function -`switch-to-buffer'. As we said before, this is how Emacs works: -different keystrokes call or run different functions. For example, -`C-f' calls `forward-char', `M-e' calls `forward-sentence', and so on. - -By writing `switch-to-buffer' in an expression, and giving it a -buffer to switch to, we can switch buffers just the way `C-x b' does. - -Here is the Lisp expression: - - (switch-to-buffer (other-buffer)) - -The symbol `switch-to-buffer' is the first element of the list, so -the Lisp interpreter will treat it as a function and carry out the -instructions that are attached to it. But before doing that, the -interpreter will note that `other-buffer' is inside parentheses and -work on that symbol first. `other-buffer' is the first (and in this -case, the only) element of this list, so the Lisp interpreter calls -or runs the function. It returns another buffer. Next, the -interpreter runs `switch-to-buffer', passing to it, as an argument, -the other buffer, which is what Emacs will switch to. If you are -reading this in Info, try this now. Evaluate the expression. (To -get back, type `C-x b <RET>'.)(2) - -In the programming examples in later sections of this document, you -will see the function `set-buffer' more often than -`switch-to-buffer'. This is because of a difference between computer -programs and humans: humans have eyes and expect to see the buffer on -which they are working on their computer terminals. This is so -obvious, it almost goes without saying. However, programs do not -have eyes. When a computer program works on a buffer, that buffer -does not need to be visible on the screen. - -`switch-to-buffer' is designed for humans and does two different -things: it switches the buffer to which Emacs' attention is directed; -and it switches the buffer displayed in the window to the new buffer. -`set-buffer', on the other hand, does only one thing: it switches the -attention of the computer program to a different buffer. The buffer -on the screen remains unchanged (of course, normally nothing happens -there until the command finishes running). - -Also, we have just introduced another jargon term, the word "call". -When you evaluate a list in which the first symbol is a function, you -are calling that function. The use of the term comes from the notion -of the function as an entity that can do something for you if you -`call' it--just as a plumber is an entity who can fix a leak if you -call him or her. - ----------- Footnotes ---------- - -(1) Or rather, to save typing, you probably typed just part of the -name, such as `*sc', and then pressed your `TAB' key to cause it to -expand to the full name; and then typed your `RET' key. - -(2) Remember, this expression will move you to your most recent other -buffer that you cannot see. If you really want to go to your most -recently selected buffer, even if you can still see it, you need to -evaluate the following more complex expression: - - (switch-to-buffer (other-buffer (current-buffer) t)) - -In this case, the first argument to `other-buffer' tells it which -buffer to skip--the current one--and the second argument tells -`other-buffer' it is OK to switch to a visible buffer. In regular -use, `switch-to-buffer' takes you to an invisible window since you -would most likely use `C-x o' (`other-window') to go to another -visible buffer. - -Buffer Size and the Location of Point -===================================== - -Finally, let's look at several rather simple functions, -`buffer-size', `point', `point-min', and `point-max'. These give -information about the size of a buffer and the location of point -within it. - -The function `buffer-size' tells you the size of the current buffer; -that is, the function returns a count of the number of characters in -the buffer. - - (buffer-size) - -You can evaluate this in the usual way, by positioning the cursor -after the expression and typing `C-x C-e'. - -In Emacs, the current position of the cursor is called "point". The -expression `(point)' returns a number that tells you where the cursor -is located as a count of the number of characters from the beginning -of the buffer up to point. - -You can see the character count for point in this buffer by evaluating -the following expression in the usual way: - - (point) - -As I write this, the value of `point' is 65724. The `point' function -is frequently used in some of the examples later in this book. - -The value of point depends, of course, on its location within the -buffer. If you evaluate point in this spot, the number will be -larger: - - (point) - -For me, the value of point in this location is 66043, which means that -there are 319 characters (including spaces) between the two -expressions. - -The function `point-min' is somewhat similar to `point', but it -returns the value of the minimum permissible value of point in the -current buffer. This is the number 1 unless "narrowing" is in -effect. (Narrowing is a mechanism whereby you can restrict yourself, -or a program, to operations on just a part of a buffer. *Note -Narrowing and Widening: Narrowing & Widening.) Likewise, the -function `point-max' returns the value of the maximum permissible -value of point in the current buffer. - -Exercise -======== - -Find a file with which you are working and move towards its middle. -Find its buffer name, file name, length, and your position in the -file. - -How To Write Function Definitions -********************************* - -When the Lisp interpreter evaluates a list, it looks to see whether -the first symbol on the list has a function definition attached to -it; or, put another way, whether the symbol points to a function -definition. If it does, the computer carries out the instructions in -the definition. A symbol that has a function definition is called, -simply, a function (although, properly speaking, the definition is -the function and the symbol refers to it.) - -An Aside about Primitive Functions -================================== - -All functions are defined in terms of other functions, except for a -few "primitive" functions that are written in the C programming -language. When you write functions' definitions, you will write them -in Emacs Lisp and use other functions as your building blocks. Some -of the functions you will use will themselves be written in Emacs -Lisp (perhaps by you) and some will be primitives written in C. The -primitive functions are used exactly like those written in Emacs Lisp -and behave like them. They are written in C so we can easily run GNU -Emacs on any computer that has sufficient power and can run C. - -Let me re-emphasize this: when you write code in Emacs Lisp, you do -not distinguish between the use of functions written in C and the use -of functions written in Emacs Lisp. The difference is irrelevant. I -mention the distinction only because it is interesting to know. -Indeed, unless you investigate, you won't know whether an -already-written function is written in Emacs Lisp or C. - -The `defun' Special Form -======================== - -In Lisp, a symbol such as `mark-whole-buffer' has code attached to it -that tells the computer what to do when the function is called. This -code is called the "function definition" and is created by evaluating -a Lisp expression that starts with the symbol `defun' (which is an -abbreviation for _define function_). Because `defun' does not -evaluate its arguments in the usual way, it is called a "special -form". - -In subsequent sections, we will look at function definitions from the -Emacs source code, such as `mark-whole-buffer'. In this section, we -will describe a simple function definition so you can see how it -looks. This function definition uses arithmetic because it makes for -a simple example. Some people dislike examples using arithmetic; -however, if you are such a person, do not despair. Hardly any of the -code we will study in the remainder of this introduction involves -arithmetic or mathematics. The examples mostly involve text in one -way or another. - -A function definition has up to five parts following the word `defun': - - 1. The name of the symbol to which the function definition should be - attached. - - 2. A list of the arguments that will be passed to the function. If - no arguments will be passed to the function, this is an empty - list, `()'. - - 3. Documentation describing the function. (Technically optional, - but strongly recommended.) - - 4. Optionally, an expression to make the function interactive so - you can use it by typing `M-x' and then the name of the - function; or by typing an appropriate key or keychord. - - 5. The code that instructs the computer what to do: the "body" of - the function definition. - -It is helpful to think of the five parts of a function definition as -being organized in a template, with slots for each part: - - (defun FUNCTION-NAME (ARGUMENTS...) - "OPTIONAL-DOCUMENTATION..." - (interactive ARGUMENT-PASSING-INFO) ; optional - BODY...) - -As an example, here is the code for a function that multiplies its -argument by 7. (This example is not interactive. *Note Making a -Function Interactive: Interactive, for that information.) - - (defun multiply-by-seven (number) - "Multiply NUMBER by seven." - (* 7 number)) - -This definition begins with a parenthesis and the symbol `defun', -followed by the name of the function. - -The name of the function is followed by a list that contains the -arguments that will be passed to the function. This list is called -the "argument list". In this example, the list has only one element, -the symbol, `number'. When the function is used, the symbol will be -bound to the value that is used as the argument to the function. - -Instead of choosing the word `number' for the name of the argument, I -could have picked any other name. For example, I could have chosen -the word `multiplicand'. I picked the word `number' because it tells -what kind of value is intended for this slot; but I could just as -well have chosen the word `multiplicand' to indicate the role that the -value placed in this slot will play in the workings of the function. -I could have called it `foogle', but that would have been a bad -choice because it would not tell humans what it means. The choice of -name is up to the programmer and should be chosen to make the meaning -of the function clear. - -Indeed, you can choose any name you wish for a symbol in an argument -list, even the name of a symbol used in some other function: the name -you use in an argument list is private to that particular definition. -In that definition, the name refers to a different entity than any use -of the same name outside the function definition. Suppose you have a -nick-name `Shorty' in your family; when your family members refer to -`Shorty', they mean you. But outside your family, in a movie, for -example, the name `Shorty' refers to someone else. Because a name in -an argument list is private to the function definition, you can -change the value of such a symbol inside the body of a function -without changing its value outside the function. The effect is -similar to that produced by a `let' expression. (*Note `let': let.) - -The argument list is followed by the documentation string that -describes the function. This is what you see when you type `C-h f' -and the name of a function. Incidentally, when you write a -documentation string like this, you should make the first line a -complete sentence since some commands, such as `apropos', print only -the first line of a multi-line documentation string. Also, you -should not indent the second line of a documentation string, if you -have one, because that looks odd when you use `C-h f' -(`describe-function'). The documentation string is optional, but it -is so useful, it should be included in almost every function you -write. - -The third line of the example consists of the body of the function -definition. (Most functions' definitions, of course, are longer than -this.) In this function, the body is the list, `(* 7 number)', which -says to multiply the value of NUMBER by 7. (In Emacs Lisp, `*' is -the function for multiplication, just as `+' is the function for -addition.) - -When you use the `multiply-by-seven' function, the argument `number' -evaluates to the actual number you want used. Here is an example -that shows how `multiply-by-seven' is used; but don't try to evaluate -this yet! - - (multiply-by-seven 3) - -The symbol `number', specified in the function definition in the next -section, is given or "bound to" the value 3 in the actual use of the -function. Note that although `number' was inside parentheses in the -function definition, the argument passed to the `multiply-by-seven' -function is not in parentheses. The parentheses are written in the -function definition so the computer can figure out where the argument -list ends and the rest of the function definition begins. - -If you evaluate this example, you are likely to get an error message. -(Go ahead, try it!) This is because we have written the function -definition, but not yet told the computer about the definition--we -have not yet installed (or `loaded') the function definition in Emacs. -Installing a function is the process that tells the Lisp interpreter -the definition of the function. Installation is described in the next -section. - -Install a Function Definition -============================= - -If you are reading this inside of Info in Emacs, you can try out the -`multiply-by-seven' function by first evaluating the function -definition and then evaluating `(multiply-by-seven 3)'. A copy of -the function definition follows. Place the cursor after the last -parenthesis of the function definition and type `C-x C-e'. When you -do this, `multiply-by-seven' will appear in the echo area. (What -this means is that when a function definition is evaluated, the value -it returns is the name of the defined function.) At the same time, -this action installs the function definition. - - (defun multiply-by-seven (number) - "Multiply NUMBER by seven." - (* 7 number)) - -By evaluating this `defun', you have just installed -`multiply-by-seven' in Emacs. The function is now just as much a -part of Emacs as `forward-word' or any other editing function you -use. (`multiply-by-seven' will stay installed until you quit Emacs. -To reload code automatically whenever you start Emacs, see *Note -Installing Code Permanently: Permanent Installation.) - -The effect of installation --------------------------- - -You can see the effect of installing `multiply-by-seven' by -evaluating the following sample. Place the cursor after the following -expression and type `C-x C-e'. The number 21 will appear in the echo -area. - - (multiply-by-seven 3) - -If you wish, you can read the documentation for the function by typing -`C-h f' (`describe-function') and then the name of the function, -`multiply-by-seven'. When you do this, a `*Help*' window will appear -on your screen that says: - - multiply-by-seven: - Multiply NUMBER by seven. - -(To return to a single window on your screen, type `C-x 1'.) - -Change a Function Definition ----------------------------- - -If you want to change the code in `multiply-by-seven', just rewrite -it. To install the new version in place of the old one, evaluate the -function definition again. This is how you modify code in Emacs. It -is very simple. - -As an example, you can change the `multiply-by-seven' function to add -the number to itself seven times instead of multiplying the number by -seven. It produces the same answer, but by a different path. At the -same time, we will add a comment to the code; a comment is text that -the Lisp interpreter ignores, but that a human reader may find useful -or enlightening. The comment is that this is the "second version". - - (defun multiply-by-seven (number) ; Second version. - "Multiply NUMBER by seven." - (+ number number number number number number number)) - -The comment follows a semicolon, `;'. In Lisp, everything on a line -that follows a semicolon is a comment. The end of the line is the -end of the comment. To stretch a comment over two or more lines, -begin each line with a semicolon. - -*Note Beginning a `.emacs' File: Beginning a .emacs File, and *Note -Comments: (elisp)Comments, for more about comments. - -You can install this version of the `multiply-by-seven' function by -evaluating it in the same way you evaluated the first function: place -the cursor after the last parenthesis and type `C-x C-e'. - -In summary, this is how you write code in Emacs Lisp: you write a -function; install it; test it; and then make fixes or enhancements and -install it again. - -Make a Function Interactive -=========================== - -You make a function interactive by placing a list that begins with -the special form `interactive' immediately after the documentation. -A user can invoke an interactive function by typing `M-x' and then -the name of the function; or by typing the keys to which it is bound, -for example, by typing `C-n' for `next-line' or `C-x h' for -`mark-whole-buffer'. - -Interestingly, when you call an interactive function interactively, -the value returned is not automatically displayed in the echo area. -This is because you often call an interactive function for its side -effects, such as moving forward by a word or line, and not for the -value returned. If the returned value were displayed in the echo area -each time you typed a key, it would be very distracting. - -An Interactive `multiply-by-seven', An Overview ------------------------------------------------ - -Both the use of the special form `interactive' and one way to display -a value in the echo area can be illustrated by creating an -interactive version of `multiply-by-seven'. - -Here is the code: - - (defun multiply-by-seven (number) ; Interactive version. - "Multiply NUMBER by seven." - (interactive "p") - (message "The result is %d" (* 7 number))) - -You can install this code by placing your cursor after it and typing -`C-x C-e'. The name of the function will appear in your echo area. -Then, you can use this code by typing `C-u' and a number and then -typing `M-x multiply-by-seven' and pressing <RET>. The phrase `The -result is ...' followed by the product will appear in the echo area. - -Speaking more generally, you invoke a function like this in either of -two ways: - - 1. By typing a prefix argument that contains the number to be - passed, and then typing `M-x' and the name of the function, as - with `C-u 3 M-x forward-sentence'; or, - - 2. By typing whatever key or keychord the function is bound to, as - with `C-u 3 M-e'. - -Both the examples just mentioned work identically to move point -forward three sentences. (Since `multiply-by-seven' is not bound to -a key, it could not be used as an example of key binding.) - -(*Note Some Keybindings: Keybindings, to learn how to bind a command -to a key.) - -A prefix argument is passed to an interactive function by typing the -<META> key followed by a number, for example, `M-3 M-e', or by typing -`C-u' and then a number, for example, `C-u 3 M-e' (if you type `C-u' -without a number, it defaults to 4). - -An Interactive `multiply-by-seven' ----------------------------------- - -Let's look at the use of the special form `interactive' and then at -the function `message' in the interactive version of -`multiply-by-seven'. You will recall that the function definition -looks like this: - - (defun multiply-by-seven (number) ; Interactive version. - "Multiply NUMBER by seven." - (interactive "p") - (message "The result is %d" (* 7 number))) - -In this function, the expression, `(interactive "p")', is a list of -two elements. The `"p"' tells Emacs to pass the prefix argument to -the function and use its value for the argument of the function. - -The argument will be a number. This means that the symbol `number' -will be bound to a number in the line: - - (message "The result is %d" (* 7 number)) - -For example, if your prefix argument is 5, the Lisp interpreter will -evaluate the line as if it were: - - (message "The result is %d" (* 7 5)) - -(If you are reading this in GNU Emacs, you can evaluate this -expression yourself.) First, the interpreter will evaluate the inner -list, which is `(* 7 5)'. This returns a value of 35. Next, it will -evaluate the outer list, passing the values of the second and -subsequent elements of the list to the function `message'. - -As we have seen, `message' is an Emacs Lisp function especially -designed for sending a one line message to a user. (*Note The -`message' function: message.) In summary, the `message' function -prints its first argument in the echo area as is, except for -occurrences of `%d', `%s', or `%c'. When it sees one of these -control sequences, the function looks to the second and subsequent -arguments and prints the value of the argument in the location in the -string where the control sequence is located. - -In the interactive `multiply-by-seven' function, the control string -is `%d', which requires a number, and the value returned by -evaluating `(* 7 5)' is the number 35. Consequently, the number 35 -is printed in place of the `%d' and the message is `The result is 35'. - -(Note that when you call the function `multiply-by-seven', the -message is printed without quotes, but when you call `message', the -text is printed in double quotes. This is because the value returned -by `message' is what appears in the echo area when you evaluate an -expression whose first element is `message'; but when embedded in a -function, `message' prints the text as a side effect without quotes.) - -Different Options for `interactive' -=================================== - -In the example, `multiply-by-seven' used `"p"' as the argument to -`interactive'. This argument told Emacs to interpret your typing -either `C-u' followed by a number or <META> followed by a number as a -command to pass that number to the function as its argument. Emacs -has more than twenty characters predefined for use with -`interactive'. In almost every case, one of these options will -enable you to pass the right information interactively to a function. -(*Note Code Characters for `interactive': (elisp)Interactive Codes.) - -For example, the character `r' causes Emacs to pass the beginning and -end of the region (the current values of point and mark) to the -function as two separate arguments. It is used as follows: - - (interactive "r") - -On the other hand, a `B' tells Emacs to ask for the name of a buffer -that will be passed to the function. When it sees a `B', Emacs will -ask for the name by prompting the user in the minibuffer, using a -string that follows the `B', as in `"BAppend to buffer: "'. Not only -will Emacs prompt for the name, but Emacs will complete the name if -you type enough of it and press <TAB>. - -A function with two or more arguments can have information passed to -each argument by adding parts to the string that follows -`interactive'. When you do this, the information is passed to each -argument in the same order it is specified in the `interactive' list. -In the string, each part is separated from the next part by a `\n', -which is a newline. For example, you could follow `"BAppend to -buffer: "' with a `\n') and an `r'. This would cause Emacs to pass -the values of point and mark to the function as well as prompt you -for the buffer--three arguments in all. - -In this case, the function definition would look like the following, -where `buffer', `start', and `end' are the symbols to which -`interactive' binds the buffer and the current values of the -beginning and ending of the region: - - (defun NAME-OF-FUNCTION (buffer start end) - "DOCUMENTATION..." - (interactive "BAppend to buffer: \nr") - BODY-OF-FUNCTION...) - -(The space after the colon in the prompt makes it look better when you -are prompted. The `append-to-buffer' function looks exactly like -this. *Note The Definition of `append-to-buffer': append-to-buffer.) - -If a function does not have arguments, then `interactive' does not -require any. Such a function contains the simple expression -`(interactive)'. The `mark-whole-buffer' function is like this. - -Alternatively, if the special letter-codes are not right for your -application, you can pass your own arguments to `interactive' as a -list. *Note Using `Interactive': (elisp)interactive, for more -information about this advanced technique. - -Install Code Permanently -======================== - -When you install a function definition by evaluating it, it will stay -installed until you quit Emacs. The next time you start a new session -of Emacs, the function will not be installed unless you evaluate the -function definition again. - -At some point, you may want to have code installed automatically -whenever you start a new session of Emacs. There are several ways of -doing this: - - * If you have code that is just for yourself, you can put the code - for the function definition in your `.emacs' initialization - file. When you start Emacs, your `.emacs' file is automatically - evaluated and all the function definitions within it are - installed. *Note Your `.emacs' File: Emacs Initialization. - - * Alternatively, you can put the function definitions that you want - installed in one or more files of their own and use the `load' - function to cause Emacs to evaluate and thereby install each of - the functions in the files. *Note Loading Files: Loading Files. - - * On the other hand, if you have code that your whole site will - use, it is usual to put it in a file called `site-init.el' that - is loaded when Emacs is built. This makes the code available to - everyone who uses your machine. (See the `INSTALL' file that is - part of the Emacs distribution.) - -Finally, if you have code that everyone who uses Emacs may want, you -can post it on a computer network or send a copy to the Free Software -Foundation. (When you do this, please license the code and its -documentation under a license that permits other people to run, copy, -study, modify, and redistribute the code and which protects you from -having your work taken from you.) If you send a copy of your code to -the Free Software Foundation, and properly protect yourself and -others, it may be included in the next release of Emacs. In large -part, this is how Emacs has grown over the past years, by donations. - -`let' -===== - -The `let' expression is a special form in Lisp that you will need to -use in most function definitions. - -`let' is used to attach or bind a symbol to a value in such a way -that the Lisp interpreter will not confuse the variable with a -variable of the same name that is not part of the function. - -To understand why the `let' special form is necessary, consider the -situation in which you own a home that you generally refer to as `the -house', as in the sentence, "The house needs painting." If you are -visiting a friend and your host refers to `the house', he is likely -to be referring to _his_ house, not yours, that is, to a different -house. - -If your friend is referring to his house and you think he is referring -to your house, you may be in for some confusion. The same thing could -happen in Lisp if a variable that is used inside of one function has -the same name as a variable that is used inside of another function, -and the two are not intended to refer to the same value. The `let' -special form prevents this kind of confusion. - -`let' Prevents Confusion ------------------------- - -The `let' special form prevents confusion. `let' creates a name for -a "local variable" that overshadows any use of the same name outside -the `let' expression. This is like understanding that whenever your -host refers to `the house', he means his house, not yours. (Symbols -used in argument lists work the same way. *Note The `defun' Special -Form: defun.) - -Local variables created by a `let' expression retain their value -_only_ within the `let' expression itself (and within expressions -called within the `let' expression); the local variables have no -effect outside the `let' expression. - -Another way to think about `let' is that it is like a `setq' that is -temporary and local. The values set by `let' are automatically -undone when the `let' is finished. The setting only affects -expressions that are inside the bounds of the `let' expression. In -computer science jargon, we would say "the binding of a symbol is -visible only in functions called in the `let' form; in Emacs Lisp, -scoping is dynamic, not lexical." - -`let' can create more than one variable at once. Also, `let' gives -each variable it creates an initial value, either a value specified -by you, or `nil'. (In the jargon, this is called `binding the -variable to the value'.) After `let' has created and bound the -variables, it executes the code in the body of the `let', and returns -the value of the last expression in the body, as the value of the -whole `let' expression. (`Execute' is a jargon term that means to -evaluate a list; it comes from the use of the word meaning `to give -practical effect to' (`Oxford English Dictionary'). Since you -evaluate an expression to perform an action, `execute' has evolved as -a synonym to `evaluate'.) - -The Parts of a `let' Expression -------------------------------- - -A `let' expression is a list of three parts. The first part is the -symbol `let'. The second part is a list, called a "varlist", each -element of which is either a symbol by itself or a two-element list, -the first element of which is a symbol. The third part of the `let' -expression is the body of the `let'. The body usually consists of -one or more lists. - -A template for a `let' expression looks like this: - - (let VARLIST BODY...) - -The symbols in the varlist are the variables that are given initial -values by the `let' special form. Symbols by themselves are given -the initial value of `nil'; and each symbol that is the first element -of a two-element list is bound to the value that is returned when the -Lisp interpreter evaluates the second element. - -Thus, a varlist might look like this: `(thread (needles 3))'. In -this case, in a `let' expression, Emacs binds the symbol `thread' to -an initial value of `nil', and binds the symbol `needles' to an -initial value of 3. - -When you write a `let' expression, what you do is put the appropriate -expressions in the slots of the `let' expression template. - -If the varlist is composed of two-element lists, as is often the case, -the template for the `let' expression looks like this: - - (let ((VARIABLE VALUE) - (VARIABLE VALUE) - ...) - BODY...) - -Sample `let' Expression ------------------------ - -The following expression creates and gives initial values to the two -variables `zebra' and `tiger'. The body of the `let' expression is a -list which calls the `message' function. - - (let ((zebra 'stripes) - (tiger 'fierce)) - (message "One kind of animal has %s and another is %s." - zebra tiger)) - -Here, the varlist is `((zebra 'stripes) (tiger 'fierce))'. - -The two variables are `zebra' and `tiger'. Each variable is the -first element of a two-element list and each value is the second -element of its two-element list. In the varlist, Emacs binds the -variable `zebra' to the value `stripes', and binds the variable -`tiger' to the value `fierce'. In this example, both values are -symbols preceded by a quote. The values could just as well have been -another list or a string. The body of the `let' follows after the -list holding the variables. In this example, the body is a list that -uses the `message' function to print a string in the echo area. - -You may evaluate the example in the usual fashion, by placing the -cursor after the last parenthesis and typing `C-x C-e'. When you do -this, the following will appear in the echo area: - - "One kind of animal has stripes and another is fierce." - -As we have seen before, the `message' function prints its first -argument, except for `%s'. In this example, the value of the variable -`zebra' is printed at the location of the first `%s' and the value of -the variable `tiger' is printed at the location of the second `%s'. - -Uninitialized Variables in a `let' Statement --------------------------------------------- - -If you do not bind the variables in a `let' statement to specific -initial values, they will automatically be bound to an initial value -of `nil', as in the following expression: - - (let ((birch 3) - pine - fir - (oak 'some)) - (message - "Here are %d variables with %s, %s, and %s value." - birch pine fir oak)) - -Here, the varlist is `((birch 3) pine fir (oak 'some))'. - -If you evaluate this expression in the usual way, the following will -appear in your echo area: - - "Here are 3 variables with nil, nil, and some value." - -In this example, Emacs binds the symbol `birch' to the number 3, -binds the symbols `pine' and `fir' to `nil', and binds the symbol -`oak' to the value `some'. - -Note that in the first part of the `let', the variables `pine' and -`fir' stand alone as atoms that are not surrounded by parentheses; -this is because they are being bound to `nil', the empty list. But -`oak' is bound to `some' and so is a part of the list `(oak 'some)'. -Similarly, `birch' is bound to the number 3 and so is in a list with -that number. (Since a number evaluates to itself, the number does -not need to be quoted. Also, the number is printed in the message -using a `%d' rather than a `%s'.) The four variables as a group are -put into a list to delimit them from the body of the `let'. - -The `if' Special Form -===================== - -A third special form, in addition to `defun' and `let', is the -conditional `if'. This form is used to instruct the computer to make -decisions. You can write function definitions without using `if', -but it is used often enough, and is important enough, to be included -here. It is used, for example, in the code for the function -`beginning-of-buffer'. - -The basic idea behind an `if', is that "_if_ a test is true, _then_ -an expression is evaluated." If the test is not true, the expression -is not evaluated. For example, you might make a decision such as, -"if it is warm and sunny, then go to the beach!" - -`if' in more detail -------------------- - -An `if' expression written in Lisp does not use the word `then'; the -test and the action are the second and third elements of the list -whose first element is `if'. Nonetheless, the test part of an `if' -expression is often called the "if-part" and the second argument is -often called the "then-part". - -Also, when an `if' expression is written, the true-or-false-test is -usually written on the same line as the symbol `if', but the action -to carry out if the test is true, the "then-part", is written on the -second and subsequent lines. This makes the `if' expression easier -to read. - - (if TRUE-OR-FALSE-TEST - ACTION-TO-CARRY-OUT-IF-TEST-IS-TRUE) - -The true-or-false-test will be an expression that is evaluated by the -Lisp interpreter. - -Here is an example that you can evaluate in the usual manner. The -test is whether the number 5 is greater than the number 4. Since it -is, the message `5 is greater than 4!' will be printed. - - (if (> 5 4) ; if-part - (message "5 is greater than 4!")) ; then-part - -(The function `>' tests whether its first argument is greater than -its second argument and returns true if it is.) - -Of course, in actual use, the test in an `if' expression will not be -fixed for all time as it is by the expression `(> 5 4)'. Instead, at -least one of the variables used in the test will be bound to a value -that is not known ahead of time. (If the value were known ahead of -time, we would not need to run the test!) - -For example, the value may be bound to an argument of a function -definition. In the following function definition, the character of -the animal is a value that is passed to the function. If the value -bound to `characteristic' is `fierce', then the message, `It's a -tiger!' will be printed; otherwise, `nil' will be returned. - - (defun type-of-animal (characteristic) - "Print message in echo area depending on CHARACTERISTIC. - If the CHARACTERISTIC is the symbol `fierce', - then warn of a tiger." - (if (equal characteristic 'fierce) - (message "It's a tiger!"))) - -If you are reading this inside of GNU Emacs, you can evaluate the -function definition in the usual way to install it in Emacs, and then -you can evaluate the following two expressions to see the results: - - (type-of-animal 'fierce) - - (type-of-animal 'zebra) - -When you evaluate `(type-of-animal 'fierce)', you will see the -following message printed in the echo area: `"It's a tiger!"'; and -when you evaluate `(type-of-animal 'zebra)' you will see `nil' -printed in the echo area. - -The `type-of-animal' Function in Detail ---------------------------------------- - -Let's look at the `type-of-animal' function in detail. - -The function definition for `type-of-animal' was written by filling -the slots of two templates, one for a function definition as a whole, -and a second for an `if' expression. - -The template for every function that is not interactive is: - - (defun NAME-OF-FUNCTION (ARGUMENT-LIST) - "DOCUMENTATION..." - BODY...) - -The parts of the function that match this template look like this: - - (defun type-of-animal (characteristic) - "Print message in echo area depending on CHARACTERISTIC. - If the CHARACTERISTIC is the symbol `fierce', - then warn of a tiger." - BODY: THE `if' EXPRESSION) - -The name of function is `type-of-animal'; it is passed the value of -one argument. The argument list is followed by a multi-line -documentation string. The documentation string is included in the -example because it is a good habit to write documentation string for -every function definition. The body of the function definition -consists of the `if' expression. - -The template for an `if' expression looks like this: - - (if TRUE-OR-FALSE-TEST - ACTION-TO-CARRY-OUT-IF-THE-TEST-RETURNS-TRUE) - -In the `type-of-animal' function, the code for the `if' looks like -this: - - (if (equal characteristic 'fierce) - (message "It's a tiger!"))) - -Here, the true-or-false-test is the expression: - - (equal characteristic 'fierce) - -In Lisp, `equal' is a function that determines whether its first -argument is equal to its second argument. The second argument is the -quoted symbol `'fierce' and the first argument is the value of the -symbol `characteristic'--in other words, the argument passed to this -function. - -In the first exercise of `type-of-animal', the argument `fierce' is -passed to `type-of-animal'. Since `fierce' is equal to `fierce', the -expression, `(equal characteristic 'fierce)', returns a value of -true. When this happens, the `if' evaluates the second argument or -then-part of the `if': `(message "It's tiger!")'. - -On the other hand, in the second exercise of `type-of-animal', the -argument `zebra' is passed to `type-of-animal'. `zebra' is not equal -to `fierce', so the then-part is not evaluated and `nil' is returned -by the `if' expression. - -If-then-else Expressions -======================== - -An `if' expression may have an optional third argument, called the -"else-part", for the case when the true-or-false-test returns false. -When this happens, the second argument or then-part of the overall -`if' expression is _not_ evaluated, but the third or else-part _is_ -evaluated. You might think of this as the cloudy day alternative for -the decision `if it is warm and sunny, then go to the beach, else -read a book!". - -The word "else" is not written in the Lisp code; the else-part of an -`if' expression comes after the then-part. In the written Lisp, the -else-part is usually written to start on a line of its own and is -indented less than the then-part: - - (if TRUE-OR-FALSE-TEST - ACTION-TO-CARRY-OUT-IF-THE-TEST-RETURNS-TRUE - ACTION-TO-CARRY-OUT-IF-THE-TEST-RETURNS-FALSE) - -For example, the following `if' expression prints the message `4 is -not greater than 5!' when you evaluate it in the usual way: - - (if (> 4 5) ; if-part - (message "5 is greater than 4!") ; then-part - (message "4 is not greater than 5!")) ; else-part - -Note that the different levels of indentation make it easy to -distinguish the then-part from the else-part. (GNU Emacs has several -commands that automatically indent `if' expressions correctly. *Note -GNU Emacs Helps You Type Lists: Typing Lists.) - -We can extend the `type-of-animal' function to include an else-part -by simply incorporating an additional part to the `if' expression. - -You can see the consequences of doing this if you evaluate the -following version of the `type-of-animal' function definition to -install it and then evaluate the two subsequent expressions to pass -different arguments to the function. - - (defun type-of-animal (characteristic) ; Second version. - "Print message in echo area depending on CHARACTERISTIC. - If the CHARACTERISTIC is the symbol `fierce', - then warn of a tiger; - else say it's not fierce." - (if (equal characteristic 'fierce) - (message "It's a tiger!") - (message "It's not fierce!"))) - - - (type-of-animal 'fierce) - - (type-of-animal 'zebra) - -When you evaluate `(type-of-animal 'fierce)', you will see the -following message printed in the echo area: `"It's a tiger!"'; but -when you evaluate `(type-of-animal 'zebra)', you will see `"It's not -fierce!"'. - -(Of course, if the CHARACTERISTIC were `ferocious', the message -`"It's not fierce!"' would be printed; and it would be misleading! -When you write code, you need to take into account the possibility -that some such argument will be tested by the `if' and write your -program accordingly.) - -Truth and Falsehood in Emacs Lisp -================================= - -There is an important aspect to the truth test in an `if' expression. -So far, we have spoken of `true' and `false' as values of predicates -as if they were new kinds of Emacs Lisp objects. In fact, `false' is -just our old friend `nil'. Anything else--anything at all--is `true'. - -The expression that tests for truth is interpreted as "true" if the -result of evaluating it is a value that is not `nil'. In other -words, the result of the test is considered true if the value -returned is a number such as 47, a string such as `"hello"', or a -symbol (other than `nil') such as `flowers', or a list, or even a -buffer! - -An explanation of `nil' ------------------------ - -Before illustrating a test for truth, we need an explanation of `nil'. - -In Emacs Lisp, the symbol `nil' has two meanings. First, it means the -empty list. Second, it means false and is the value returned when a -true-or-false-test tests false. `nil' can be written as an empty -list, `()', or as `nil'. As far as the Lisp interpreter is -concerned, `()' and `nil' are the same. Humans, however, tend to use -`nil' for false and `()' for the empty list. - -In Emacs Lisp, any value that is not `nil'--is not the empty list--is -considered true. This means that if an evaluation returns something -that is not an empty list, an `if' expression will test true. For -example, if a number is put in the slot for the test, it will be -evaluated and will return itself, since that is what numbers do when -evaluated. In this conditional, the `if' expression will test true. -The expression tests false only when `nil', an empty list, is -returned by evaluating the expression. - -You can see this by evaluating the two expressions in the following -examples. - -In the first example, the number 4 is evaluated as the test in the -`if' expression and returns itself; consequently, the then-part of -the expression is evaluated and returned: `true' appears in the echo -area. In the second example, the `nil' indicates false; -consequently, the else-part of the expression is evaluated and -returned: `false' appears in the echo area. - - (if 4 - 'true - 'false) - - (if nil - 'true - 'false) - -Incidentally, if some other useful value is not available for a test -that returns true, then the Lisp interpreter will return the symbol -`t' for true. For example, the expression `(> 5 4)' returns `t' when -evaluated, as you can see by evaluating it in the usual way: - - (> 5 4) - -On the other hand, this function returns `nil' if the test is false. - - (> 4 5) - -`save-excursion' -================ - -The `save-excursion' function is the fourth and final special form -that we will discuss in this chapter. - -In Emacs Lisp programs used for editing, the `save-excursion' -function is very common. It saves the location of point and mark, -executes the body of the function, and then restores point and mark to -their previous positions if their locations were changed. Its primary -purpose is to keep the user from being surprised and disturbed by -unexpected movement of point or mark. - -Point and Mark --------------- - -Before discussing `save-excursion', however, it may be useful first -to review what point and mark are in GNU Emacs. "Point" is the -current location of the cursor. Wherever the cursor is, that is -point. More precisely, on terminals where the cursor appears to be -on top of a character, point is immediately before the character. In -Emacs Lisp, point is an integer. The first character in a buffer is -number one, the second is number two, and so on. The function -`point' returns the current position of the cursor as a number. Each -buffer has its own value for point. - -The "mark" is another position in the buffer; its value can be set -with a command such as `C-<SPC>' (`set-mark-command'). If a mark has -been set, you can use the command `C-x C-x' -(`exchange-point-and-mark') to cause the cursor to jump to the mark -and set the mark to be the previous position of point. In addition, -if you set another mark, the position of the previous mark is saved -in the mark ring. Many mark positions can be saved this way. You -can jump the cursor to a saved mark by typing `C-u C-<SPC>' one or -more times. - -The part of the buffer between point and mark is called "the region". -Numerous commands work on the region, including `center-region', -`count-lines-region', `kill-region', and `print-region'. - -The `save-excursion' special form saves the locations of point and -mark and restores those positions after the code within the body of -the special form is evaluated by the Lisp interpreter. Thus, if -point were in the beginning of a piece of text and some code moved -point to the end of the buffer, the `save-excursion' would put point -back to where it was before, after the expressions in the body of the -function were evaluated. - -In Emacs, a function frequently moves point as part of its internal -workings even though a user would not expect this. For example, -`count-lines-region' moves point. To prevent the user from being -bothered by jumps that are both unexpected and (from the user's point -of view) unnecessary, `save-excursion' is often used to keep point and -mark in the location expected by the user. The use of -`save-excursion' is good housekeeping. - -To make sure the house stays clean, `save-excursion' restores the -values of point and mark even if something goes wrong in the code -inside of it (or, to be more precise and to use the proper jargon, -"in case of abnormal exit"). This feature is very helpful. - -In addition to recording the values of point and mark, -`save-excursion' keeps track of the current buffer, and restores it, -too. This means you can write code that will change the buffer and -have `save-excursion' switch you back to the original buffer. This -is how `save-excursion' is used in `append-to-buffer'. (*Note The -Definition of `append-to-buffer': append-to-buffer.) - -Template for a `save-excursion' Expression ------------------------------------------- - -The template for code using `save-excursion' is simple: - - (save-excursion - BODY...) - -The body of the function is one or more expressions that will be -evaluated in sequence by the Lisp interpreter. If there is more than -one expression in the body, the value of the last one will be returned -as the value of the `save-excursion' function. The other expressions -in the body are evaluated only for their side effects; and -`save-excursion' itself is used only for its side effect (which is -restoring the positions of point and mark). - -In more detail, the template for a `save-excursion' expression looks -like this: - - (save-excursion - FIRST-EXPRESSION-IN-BODY - SECOND-EXPRESSION-IN-BODY - THIRD-EXPRESSION-IN-BODY - ... - LAST-EXPRESSION-IN-BODY) - -An expression, of course, may be a symbol on its own or a list. - -In Emacs Lisp code, a `save-excursion' expression often occurs within -the body of a `let' expression. It looks like this: - - (let VARLIST - (save-excursion - BODY...)) - -Review -====== - -In the last few chapters we have introduced a fair number of functions -and special forms. Here they are described in brief, along with a few -similar functions that have not been mentioned yet. - -`eval-last-sexp' - Evaluate the last symbolic expression before the current - location of point. The value is printed in the echo area unless - the function is invoked with an argument; in that case, the - output is printed in the current buffer. This command is - normally bound to `C-x C-e'. - -`defun' - Define function. This special form has up to five parts: the - name, a template for the arguments that will be passed to the - function, documentation, an optional interactive declaration, - and the body of the definition. - - For example: - - (defun back-to-indentation () - "Move point to first visible character on line." - (interactive) - (beginning-of-line 1) - (skip-chars-forward " \t")) - -`interactive' - Declare to the interpreter that the function can be used - interactively. This special form may be followed by a string - with one or more parts that pass the information to the - arguments of the function, in sequence. These parts may also - tell the interpreter to prompt for information. Parts of the - string are separated by newlines, `\n'. - - Common code characters are: - - `b' - The name of an existing buffer. - - `f' - The name of an existing file. - - `p' - The numeric prefix argument. (Note that this `p' is lower - case.) - - `r' - Point and the mark, as two numeric arguments, smallest - first. This is the only code letter that specifies two - successive arguments rather than one. - - *Note Code Characters for `interactive': (elisp)Interactive - Codes, for a complete list of code characters. - -`let' - Declare that a list of variables is for use within the body of - the `let' and give them an initial value, either `nil' or a - specified value; then evaluate the rest of the expressions in - the body of the `let' and return the value of the last one. - Inside the body of the `let', the Lisp interpreter does not see - the values of the variables of the same names that are bound - outside of the `let'. - - For example, - - (let ((foo (buffer-name)) - (bar (buffer-size))) - (message - "This buffer is %s and has %d characters." - foo bar)) - -`save-excursion' - Record the values of point and mark and the current buffer before - evaluating the body of this special form. Restore the values of - point and mark and buffer afterward. - - For example, - - (message "We are %d characters into this buffer." - (- (point) - (save-excursion - (goto-char (point-min)) (point)))) - -`if' - Evaluate the first argument to the function; if it is true, - evaluate the second argument; else evaluate the third argument, - if there is one. - - The `if' special form is called a "conditional". There are - other conditionals in Emacs Lisp, but `if' is perhaps the most - commonly used. - - For example, - - (if (string-equal - (number-to-string 21) - (substring (emacs-version) 10 12)) - (message "This is version 21 Emacs") - (message "This is not version 21 Emacs")) - -`equal' -`eq' - Test whether two objects are the same. `equal' uses one meaning - of the word `same' and `eq' uses another: `equal' returns true - if the two objects have a similar structure and contents, such as - two copies of the same book. On the other hand, `eq', returns - true if both arguments are actually the same object. - -`<' -`>' -`<=' -`>=' - The `<' function tests whether its first argument is smaller than - its second argument. A corresponding function, `>', tests - whether the first argument is greater than the second. - Likewise, `<=' tests whether the first argument is less than or - equal to the second and `>=' tests whether the first argument is - greater than or equal to the second. In all cases, both - arguments must be numbers or markers (markers indicate positions - in buffers). - -`string<' -`string-lessp' -`string=' -`string-equal' - The `string-lessp' function tests whether its first argument is - smaller than the second argument. A shorter, alternative name - for the same function (a `defalias') is `string<'. - - The arguments to `string-lessp' must be strings or symbols; the - ordering is lexicographic, so case is significant. The print - names of symbols are used instead of the symbols themselves. - - An empty string, `""', a string with no characters in it, is - smaller than any string of characters. - - `string-equal' provides the corresponding test for equality. Its - shorter, alternative name is `string='. There are no string test - functions that correspond to >, `>=', or `<='. - -`message' - Print a message in the echo area. The first argument is a string - that can contain `%s', `%d', or `%c' to print the value of - arguments that follow the string. The argument used by `%s' must - be a string or a symbol; the argument used by `%d' must be a - number. The argument used by `%c' must be an ascii code number; - it will be printed as the character with that ASCII code. - -`setq' -`set' - The `setq' function sets the value of its first argument to the - value of the second argument. The first argument is - automatically quoted by `setq'. It does the same for succeeding - pairs of arguments. Another function, `set', takes only two - arguments and evaluates both of them before setting the value - returned by its first argument to the value returned by its - second argument. - -`buffer-name' - Without an argument, return the name of the buffer, as a string. - -`buffer-file-name' - Without an argument, return the name of the file the buffer is - visiting. - -`current-buffer' - Return the buffer in which Emacs is active; it may not be the - buffer that is visible on the screen. - -`other-buffer' - Return the most recently selected buffer (other than the buffer - passed to `other-buffer' as an argument and other than the - current buffer). - -`switch-to-buffer' - Select a buffer for Emacs to be active in and display it in the - current window so users can look at it. Usually bound to `C-x - b'. - -`set-buffer' - Switch Emacs' attention to a buffer on which programs will run. - Don't alter what the window is showing. - -`buffer-size' - Return the number of characters in the current buffer. - -`point' - Return the value of the current position of the cursor, as an - integer counting the number of characters from the beginning of - the buffer. - -`point-min' - Return the minimum permissible value of point in the current - buffer. This is 1, unless narrowing is in effect. - -`point-max' - Return the value of the maximum permissible value of point in the - current buffer. This is the end of the buffer, unless narrowing - is in effect. - -Exercises -========= - - * Write a non-interactive function that doubles the value of its - argument, a number. Make that function interactive. - - * Write a function that tests whether the current value of - `fill-column' is greater than the argument passed to the - function, and if so, prints an appropriate message. - -A Few Buffer-Related Functions -****************************** - -In this chapter we study in detail several of the functions used in -GNU Emacs. This is called a "walk-through". These functions are -used as examples of Lisp code, but are not imaginary examples; with -the exception of the first, simplified function definition, these -functions show the actual code used in GNU Emacs. You can learn a -great deal from these definitions. The functions described here are -all related to buffers. Later, we will study other functions. - -Finding More Information -======================== - -In this walk-through, I will describe each new function as we come to -it, sometimes in detail and sometimes briefly. If you are interested, -you can get the full documentation of any Emacs Lisp function at any -time by typing `C-h f' and then the name of the function (and then -<RET>). Similarly, you can get the full documentation for a variable -by typing `C-h v' and then the name of the variable (and then <RET>). - -In versions 20 and higher, when a function is written in Emacs Lisp, -`describe-function' will also tell you the location of the function -definition. If you move point over the file name and press the <RET> -key, which is this case means `help-follow' rather than `return' or -`enter', Emacs will take you directly to the function definition. - -More generally, if you want to see a function in its original source -file, you can use the `find-tags' function to jump to it. -`find-tags' works with a wide variety of languages, not just Lisp, -and C, and it works with non-programming text as well. For example, -`find-tags' will jump to the various nodes in the Texinfo source file -of this document. - -The `find-tags' function depends on `tags tables' that record the -locations of the functions, variables, and other items to which -`find-tags' jumps. - -To use the `find-tags' command, type `M-.' (i.e., type the <META> -key and the period key at the same time, or else type the <ESC> key -and then type the period key), and then, at the prompt, type in the -name of the function whose source code you want to see, such as -`mark-whole-buffer', and then type <RET>. Emacs will switch buffers -and display the source code for the function on your screen. To -switch back to your current buffer, type `C-x b <RET>'. (On some -keyboards, the <META> key is labelled <ALT>.) - -Depending on how the initial default values of your copy of Emacs are -set, you may also need to specify the location of your `tags table', -which is a file called `TAGS'. For example, if you are interested in -Emacs sources, the tags table you will most likely want, if it has -already been created for you, will be in a subdirectory of the -`/usr/local/share/emacs/' directory; thus you would use the `M-x -visit-tags-table' command and specify a pathname such as -`/usr/local/share/emacs/21.0.100/lisp/TAGS' or -`/usr/local/src/emacs/lisp/TAGS'. If the tags table has not already -been created, you will have to create it yourself. - -To create a `TAGS' file in a specific directory, switch to that -directory in Emacs using `M-x cd' command, or list the directory with -`C-x d' (`dired'). Then run the compile command, with `etags *.el' -as the command to execute - - M-x compile RET etags *.el RET - -For more information, see *Note Create Your Own `TAGS' File: etags. - -After you become more familiar with Emacs Lisp, you will find that -you will frequently use `find-tags' to navigate your way around -source code; and you will create your own `TAGS' tables. - -Incidentally, the files that contain Lisp code are conventionally -called "libraries". The metaphor is derived from that of a -specialized library, such as a law library or an engineering library, -rather than a general library. Each library, or file, contains -functions that relate to a particular topic or activity, such as -`abbrev.el' for handling abbreviations and other typing shortcuts, -and `help.el' for on-line help. (Sometimes several libraries provide -code for a single activity, as the various `rmail...' files provide -code for reading electronic mail.) In `The GNU Emacs Manual', you -will see sentences such as "The `C-h p' command lets you search the -standard Emacs Lisp libraries by topic keywords." - -A Simplified `beginning-of-buffer' Definition -============================================= - -The `beginning-of-buffer' command is a good function to start with -since you are likely to be familiar with it and it is easy to -understand. Used as an interactive command, `beginning-of-buffer' -moves the cursor to the beginning of the buffer, leaving the mark at -the previous position. It is generally bound to `M-<'. - -In this section, we will discuss a shortened version of the function -that shows how it is most frequently used. This shortened function -works as written, but it does not contain the code for a complex -option. In another section, we will describe the entire function. -(*Note Complete Definition of `beginning-of-buffer': -beginning-of-buffer.) - -Before looking at the code, let's consider what the function -definition has to contain: it must include an expression that makes -the function interactive so it can be called by typing `M-x -beginning-of-buffer' or by typing a keychord such as `M-<'; it must -include code to leave a mark at the original position in the buffer; -and it must include code to move the cursor to the beginning of the -buffer. - -Here is the complete text of the shortened version of the function: - - (defun simplified-beginning-of-buffer () - "Move point to the beginning of the buffer; - leave mark at previous position." - (interactive) - (push-mark) - (goto-char (point-min))) - -Like all function definitions, this definition has five parts -following the special form `defun': - - 1. The name: in this example, `simplified-beginning-of-buffer'. - - 2. A list of the arguments: in this example, an empty list, `()', - - 3. The documentation string. - - 4. The interactive expression. - - 5. The body. - -In this function definition, the argument list is empty; this means -that this function does not require any arguments. (When we look at -the definition for the complete function, we will see that it may be -passed an optional argument.) - -The interactive expression tells Emacs that the function is intended -to be used interactively. In this example, `interactive' does not -have an argument because `simplified-beginning-of-buffer' does not -require one. - -The body of the function consists of the two lines: - - (push-mark) - (goto-char (point-min)) - -The first of these lines is the expression, `(push-mark)'. When this -expression is evaluated by the Lisp interpreter, it sets a mark at -the current position of the cursor, wherever that may be. The -position of this mark is saved in the mark ring. - -The next line is `(goto-char (point-min))'. This expression jumps -the cursor to the minimum point in the buffer, that is, to the -beginning of the buffer (or to the beginning of the accessible portion -of the buffer if it is narrowed. *Note Narrowing and Widening: -Narrowing & Widening.) - -The `push-mark' command sets a mark at the place where the cursor was -located before it was moved to the beginning of the buffer by the -`(goto-char (point-min))' expression. Consequently, you can, if you -wish, go back to where you were originally by typing `C-x C-x'. - -That is all there is to the function definition! - -When you are reading code such as this and come upon an unfamiliar -function, such as `goto-char', you can find out what it does by using -the `describe-function' command. To use this command, type `C-h f' -and then type in the name of the function and press <RET>. The -`describe-function' command will print the function's documentation -string in a `*Help*' window. For example, the documentation for -`goto-char' is: - - One arg, a number. Set point to that number. - Beginning of buffer is position (point-min), - end is (point-max). - -(The prompt for `describe-function' will offer you the symbol under -or preceding the cursor, so you can save typing by positioning the -cursor right over or after the function and then typing `C-h f -<RET>'.) - -The `end-of-buffer' function definition is written in the same way as -the `beginning-of-buffer' definition except that the body of the -function contains the expression `(goto-char (point-max))' in place -of `(goto-char (point-min))'. - -The Definition of `mark-whole-buffer' -===================================== - -The `mark-whole-buffer' function is no harder to understand than the -`simplified-beginning-of-buffer' function. In this case, however, we -will look at the complete function, not a shortened version. - -The `mark-whole-buffer' function is not as commonly used as the -`beginning-of-buffer' function, but is useful nonetheless: it marks a -whole buffer as a region by putting point at the beginning and a mark -at the end of the buffer. It is generally bound to `C-x h'. - -An overview of `mark-whole-buffer' ----------------------------------- - -In GNU Emacs 20, the code for the complete function looks like this: - - (defun mark-whole-buffer () - "Put point at beginning and mark at end of buffer." - (interactive) - (push-mark (point)) - (push-mark (point-max)) - (goto-char (point-min))) - -Like all other functions, the `mark-whole-buffer' function fits into -the template for a function definition. The template looks like this: - - (defun NAME-OF-FUNCTION (ARGUMENT-LIST) - "DOCUMENTATION..." - (INTERACTIVE-EXPRESSION...) - BODY...) - -Here is how the function works: the name of the function is -`mark-whole-buffer'; it is followed by an empty argument list, `()', -which means that the function does not require arguments. The -documentation comes next. - -The next line is an `(interactive)' expression that tells Emacs that -the function will be used interactively. These details are similar -to the `simplified-beginning-of-buffer' function described in the -previous section. - -Body of `mark-whole-buffer' ---------------------------- - -The body of the `mark-whole-buffer' function consists of three lines -of code: - - (push-mark (point)) - (push-mark (point-max)) - (goto-char (point-min)) - -The first of these lines is the expression, `(push-mark (point))'. - -This line does exactly the same job as the first line of the body of -the `simplified-beginning-of-buffer' function, which is written -`(push-mark)'. In both cases, the Lisp interpreter sets a mark at -the current position of the cursor. - -I don't know why the expression in `mark-whole-buffer' is written -`(push-mark (point))' and the expression in `beginning-of-buffer' is -written `(push-mark)'. Perhaps whoever wrote the code did not know -that the arguments for `push-mark' are optional and that if -`push-mark' is not passed an argument, the function automatically -sets mark at the location of point by default. Or perhaps the -expression was written so as to parallel the structure of the next -line. In any case, the line causes Emacs to determine the position -of point and set a mark there. - -The next line of `mark-whole-buffer' is `(push-mark (point-max)'. -This expression sets a mark at the point in the buffer that has the -highest number. This will be the end of the buffer (or, if the -buffer is narrowed, the end of the accessible portion of the buffer. -*Note Narrowing and Widening: Narrowing & Widening, for more about -narrowing.) After this mark has been set, the previous mark, the one -set at point, is no longer set, but Emacs remembers its position, -just as all other recent marks are always remembered. This means -that you can, if you wish, go back to that position by typing `C-u -C-<SPC>' twice. - -(In GNU Emacs 21, the `(push-mark (point-max)' is slightly more -complicated than shown here. The line reads - - (push-mark (point-max) nil t) - -(The expression works nearly the same as before. It sets a mark at -the highest numbered place in the buffer that it can. However, in -this version, `push-mark' has two additional arguments. The second -argument to `push-mark' is `nil'. This tells the function it -_should_ display a message that says `Mark set' when it pushes the -mark. The third argument is `t'. This tells `push-mark' to activate -the mark when Transient Mark mode is turned on. Transient Mark mode -highlights the currently active region. It is usually turned off.) - -Finally, the last line of the function is `(goto-char (point-min)))'. -This is written exactly the same way as it is written in -`beginning-of-buffer'. The expression moves the cursor to the -minimum point in the buffer, that is, to the beginning of the buffer -(or to the beginning of the accessible portion of the buffer). As a -result of this, point is placed at the beginning of the buffer and -mark is set at the end of the buffer. The whole buffer is, -therefore, the region. - -The Definition of `append-to-buffer' -==================================== - -The `append-to-buffer' command is very nearly as simple as the -`mark-whole-buffer' command. What it does is copy the region (that -is, the part of the buffer between point and mark) from the current -buffer to a specified buffer. - -An Overview of `append-to-buffer' ---------------------------------- - -The `append-to-buffer' command uses the `insert-buffer-substring' -function to copy the region. `insert-buffer-substring' is described -by its name: it takes a string of characters from part of a buffer, a -"substring", and inserts them into another buffer. Most of -`append-to-buffer' is concerned with setting up the conditions for -`insert-buffer-substring' to work: the code must specify both the -buffer to which the text will go and the region that will be copied. -Here is the complete text of the function: - - (defun append-to-buffer (buffer start end) - "Append to specified buffer the text of the region. - It is inserted into that buffer before its point. - - When calling from a program, give three arguments: - a buffer or the name of one, and two character numbers - specifying the portion of the current buffer to be copied." - (interactive "BAppend to buffer: \nr") - (let ((oldbuf (current-buffer))) - (save-excursion - (set-buffer (get-buffer-create buffer)) - (insert-buffer-substring oldbuf start end)))) - -The function can be understood by looking at it as a series of -filled-in templates. - -The outermost template is for the function definition. In this -function, it looks like this (with several slots filled in): - - (defun append-to-buffer (buffer start end) - "DOCUMENTATION..." - (interactive "BAppend to buffer: \nr") - BODY...) - -The first line of the function includes its name and three arguments. -The arguments are the `buffer' to which the text will be copied, and -the `start' and `end' of the region in the current buffer that will -be copied. - -The next part of the function is the documentation, which is clear and -complete. - -The `append-to-buffer' Interactive Expression ---------------------------------------------- - -Since the `append-to-buffer' function will be used interactively, the -function must have an `interactive' expression. (For a review of -`interactive', see *Note Making a Function Interactive: Interactive.) -The expression reads as follows: - - (interactive "BAppend to buffer: \nr") - -This expression has an argument inside of quotation marks and that -argument has two parts, separated by `\n'. - -The first part is `BAppend to buffer: '. Here, the `B' tells Emacs -to ask for the name of the buffer that will be passed to the -function. Emacs will ask for the name by prompting the user in the -minibuffer, using the string following the `B', which is the string -`Append to buffer: '. Emacs then binds the variable `buffer' in the -function's argument list to the specified buffer. - -The newline, `\n', separates the first part of the argument from the -second part. It is followed by an `r' that tells Emacs to bind the -two arguments that follow the symbol `buffer' in the function's -argument list (that is, `start' and `end') to the values of point and -mark. - -The Body of `append-to-buffer' ------------------------------- - -The body of the `append-to-buffer' function begins with `let'. - -As we have seen before (*note `let': let.), the purpose of a `let' -expression is to create and give initial values to one or more -variables that will only be used within the body of the `let'. This -means that such a variable will not be confused with any variable of -the same name outside the `let' expression. - -We can see how the `let' expression fits into the function as a whole -by showing a template for `append-to-buffer' with the `let' -expression in outline: - - (defun append-to-buffer (buffer start end) - "DOCUMENTATION..." - (interactive "BAppend to buffer: \nr") - (let ((VARIABLE VALUE)) - BODY...) - -The `let' expression has three elements: - - 1. The symbol `let'; - - 2. A varlist containing, in this case, a single two-element list, - `(VARIABLE VALUE)'; - - 3. The body of the `let' expression. - -In the `append-to-buffer' function, the varlist looks like this: - - (oldbuf (current-buffer)) - -In this part of the `let' expression, the one variable, `oldbuf', is -bound to the value returned by the `(current-buffer)' expression. -The variable, `oldbuf', is used to keep track of the buffer in which -you are working and from which you will copy. - -The element or elements of a varlist are surrounded by a set of -parentheses so the Lisp interpreter can distinguish the varlist from -the body of the `let'. As a consequence, the two-element list within -the varlist is surrounded by a circumscribing set of parentheses. -The line looks like this: - - (let ((oldbuf (current-buffer))) - ... ) - -The two parentheses before `oldbuf' might surprise you if you did not -realize that the first parenthesis before `oldbuf' marks the boundary -of the varlist and the second parenthesis marks the beginning of the -two-element list, `(oldbuf (current-buffer))'. - -`save-excursion' in `append-to-buffer' --------------------------------------- - -The body of the `let' expression in `append-to-buffer' consists of a -`save-excursion' expression. - -The `save-excursion' function saves the locations of point and mark, -and restores them to those positions after the expressions in the -body of the `save-excursion' complete execution. In addition, -`save-excursion' keeps track of the original buffer, and restores it. -This is how `save-excursion' is used in `append-to-buffer'. - -Incidentally, it is worth noting here that a Lisp function is normally -formatted so that everything that is enclosed in a multi-line spread -is indented more to the right than the first symbol. In this function -definition, the `let' is indented more than the `defun', and the -`save-excursion' is indented more than the `let', like this: - - (defun ... - ... - ... - (let... - (save-excursion - ... - -This formatting convention makes it easy to see that the two lines in -the body of the `save-excursion' are enclosed by the parentheses -associated with `save-excursion', just as the `save-excursion' itself -is enclosed by the parentheses associated with the `let': - - (let ((oldbuf (current-buffer))) - (save-excursion - (set-buffer (get-buffer-create buffer)) - (insert-buffer-substring oldbuf start end)))) - -The use of the `save-excursion' function can be viewed as a process -of filling in the slots of a template: - - (save-excursion - FIRST-EXPRESSION-IN-BODY - SECOND-EXPRESSION-IN-BODY - ... - LAST-EXPRESSION-IN-BODY) - -In this function, the body of the `save-excursion' contains only two -expressions. The body looks like this: - - (set-buffer (get-buffer-create buffer)) - (insert-buffer-substring oldbuf start end) - -When the `append-to-buffer' function is evaluated, the two -expressions in the body of the `save-excursion' are evaluated in -sequence. The value of the last expression is returned as the value -of the `save-excursion' function; the other expression is evaluated -only for its side effects. - -The first line in the body of the `save-excursion' uses the -`set-buffer' function to change the current buffer to the one -specified in the first argument to `append-to-buffer'. (Changing the -buffer is the side effect; as we have said before, in Lisp, a side -effect is often the primary thing we want.) The second line does the -primary work of the function. - -The `set-buffer' function changes Emacs' attention to the buffer to -which the text will be copied and from which `save-excursion' will -return. - -The line looks like this: - - (set-buffer (get-buffer-create buffer)) - -The innermost expression of this list is `(get-buffer-create -buffer)'. This expression uses the `get-buffer-create' function, -which either gets the named buffer, or if it does not exist, creates -one with the given name. This means you can use `append-to-buffer' to -put text into a buffer that did not previously exist. - -`get-buffer-create' also keeps `set-buffer' from getting an -unnecessary error: `set-buffer' needs a buffer to go to; if you were -to specify a buffer that does not exist, Emacs would baulk. Since -`get-buffer-create' will create a buffer if none exists, `set-buffer' -is always provided with a buffer. - -The last line of `append-to-buffer' does the work of appending the -text: - - (insert-buffer-substring oldbuf start end) - -The `insert-buffer-substring' function copies a string _from_ the -buffer specified as its first argument and inserts the string into -the present buffer. In this case, the argument to -`insert-buffer-substring' is the value of the variable created and -bound by the `let', namely the value of `oldbuf', which was the -current buffer when you gave the `append-to-buffer' command. - -After `insert-buffer-substring' has done its work, `save-excursion' -will restore the action to the original buffer and `append-to-buffer' -will have done its job. - -Written in skeletal form, the workings of the body look like this: - - (let (BIND-`oldbuf'-TO-VALUE-OF-`current-buffer') - (save-excursion ; Keep track of buffer. - CHANGE-BUFFER - INSERT-SUBSTRING-FROM-`oldbuf'-INTO-BUFFER) - - CHANGE-BACK-TO-ORIGINAL-BUFFER-WHEN-FINISHED - LET-THE-LOCAL-MEANING-OF-`oldbuf'-DISAPPEAR-WHEN-FINISHED - -In summary, `append-to-buffer' works as follows: it saves the value -of the current buffer in the variable called `oldbuf'. It gets the -new buffer, creating one if need be, and switches Emacs to it. Using -the value of `oldbuf', it inserts the region of text from the old -buffer into the new buffer; and then using `save-excursion', it -brings you back to your original buffer. - -In looking at `append-to-buffer', you have explored a fairly complex -function. It shows how to use `let' and `save-excursion', and how to -change to and come back from another buffer. Many function -definitions use `let', `save-excursion', and `set-buffer' this way. - -Review -====== - -Here is a brief summary of the various functions discussed in this -chapter. - -`describe-function' -`describe-variable' - Print the documentation for a function or variable. - Conventionally bound to `C-h f' and `C-h v'. - -`find-tag' - Find the file containing the source for a function or variable - and switch buffers to it, positioning point at the beginning of - the item. Conventionally bound to `M-.' (that's a period - following the <META> key). - -`save-excursion' - Save the location of point and mark and restore their values - after the arguments to `save-excursion' have been evaluated. - Also, remember the current buffer and return to it. - -`push-mark' - Set mark at a location and record the value of the previous mark - on the mark ring. The mark is a location in the buffer that - will keep its relative position even if text is added to or - removed from the buffer. - -`goto-char' - Set point to the location specified by the value of the - argument, which can be a number, a marker, or an expression - that returns the number of a position, such as `(point-min)'. - -`insert-buffer-substring' - Copy a region of text from a buffer that is passed to the - function as an argument and insert the region into the current - buffer. - -`mark-whole-buffer' - Mark the whole buffer as a region. Normally bound to `C-x h'. - -`set-buffer' - Switch the attention of Emacs to another buffer, but do not - change the window being displayed. Used when the program rather - than a human is to work on a different buffer. - -`get-buffer-create' -`get-buffer' - Find a named buffer or create one if a buffer of that name does - not exist. The `get-buffer' function returns `nil' if the named - buffer does not exist. - -Exercises -========= - - * Write your own `simplified-end-of-buffer' function definition; - then test it to see whether it works. - - * Use `if' and `get-buffer' to write a function that prints a - message telling you whether a buffer exists. - - * Using `find-tag', find the source for the `copy-to-buffer' - function. - -A Few More Complex Functions -**************************** - -In this chapter, we build on what we have learned in previous chapters -by looking at more complex functions. The `copy-to-buffer' function -illustrates use of two `save-excursion' expressions in one -definition, while the `insert-buffer' function illustrates use of an -asterisk in an `interactive' expression, use of `or', and the -important distinction between a name and the object to which the name -refers. - -The Definition of `copy-to-buffer' -================================== - -After understanding how `append-to-buffer' works, it is easy to -understand `copy-to-buffer'. This function copies text into a -buffer, but instead of adding to the second buffer, it replaces the -previous text in the second buffer. The code for the -`copy-to-buffer' function is almost the same as the code for -`append-to-buffer', except that `erase-buffer' and a second -`save-excursion' are used. (*Note The Definition of -`append-to-buffer': append-to-buffer, for the description of -`append-to-buffer'.) - -The body of `copy-to-buffer' looks like this - - ... - (interactive "BCopy to buffer: \nr") - (let ((oldbuf (current-buffer))) - (save-excursion - (set-buffer (get-buffer-create buffer)) - (erase-buffer) - (save-excursion - (insert-buffer-substring oldbuf start end))))) - -This code is similar to the code in `append-to-buffer': it is only -after changing to the buffer to which the text will be copied that -the definition for this function diverges from the definition for -`append-to-buffer': the `copy-to-buffer' function erases the buffer's -former contents. (This is what is meant by `replacement'; to replace -text, Emacs erases the previous text and then inserts new text.) -After erasing the previous contents of the buffer, `save-excursion' -is used for a second time and the new text is inserted. - -Why is `save-excursion' used twice? Consider again what the function -does. - -In outline, the body of `copy-to-buffer' looks like this: - - (let (BIND-`oldbuf'-TO-VALUE-OF-`current-buffer') - (save-excursion ; First use of `save-excursion'. - CHANGE-BUFFER - (erase-buffer) - (save-excursion ; Second use of `save-excursion'. - INSERT-SUBSTRING-FROM-`oldbuf'-INTO-BUFFER))) - -The first use of `save-excursion' returns Emacs to the buffer from -which the text is being copied. That is clear, and is just like its -use in `append-to-buffer'. Why the second use? The reason is that -`insert-buffer-substring' always leaves point at the _end_ of the -region being inserted. The second `save-excursion' causes Emacs to -leave point at the beginning of the text being inserted. In most -circumstances, users prefer to find point at the beginning of -inserted text. (Of course, the `copy-to-buffer' function returns the -user to the original buffer when done--but if the user _then_ -switches to the copied-to buffer, point will go to the beginning of -the text. Thus, this use of a second `save-excursion' is a little -nicety.) - -The Definition of `insert-buffer' -================================= - -`insert-buffer' is yet another buffer-related function. This command -copies another buffer _into_ the current buffer. It is the reverse -of `append-to-buffer' or `copy-to-buffer', since they copy a region -of text _from_ the current buffer to another buffer. - -In addition, this code illustrates the use of `interactive' with a -buffer that might be "read-only" and the important distinction -between the name of an object and the object actually referred to. - -The Code for `insert-buffer' ----------------------------- - -Here is the code: - - (defun insert-buffer (buffer) - "Insert after point the contents of BUFFER. - Puts mark after the inserted text. - BUFFER may be a buffer or a buffer name." - (interactive "*bInsert buffer: ") - (or (bufferp buffer) - (setq buffer (get-buffer buffer))) - (let (start end newmark) - (save-excursion - (save-excursion - (set-buffer buffer) - (setq start (point-min) end (point-max))) - (insert-buffer-substring buffer start end) - (setq newmark (point))) - (push-mark newmark))) - -As with other function definitions, you can use a template to see an -outline of the function: - - (defun insert-buffer (buffer) - "DOCUMENTATION..." - (interactive "*bInsert buffer: ") - BODY...) - -The Interactive Expression in `insert-buffer' ---------------------------------------------- - -In `insert-buffer', the argument to the `interactive' declaration has -two parts, an asterisk, `*', and `bInsert buffer: '. - -A Read-only Buffer -.................. - -The asterisk is for the situation when the current buffer is a -read-only buffer--a buffer that cannot be modified. If -`insert-buffer' is called when the current buffer is read-only, a -message to this effect is printed in the echo area and the terminal -may beep or blink at you; you will not be permitted to insert anything -into current buffer. The asterisk does not need to be followed by a -newline to separate it from the next argument. - -`b' in an Interactive Expression -................................ - -The next argument in the interactive expression starts with a lower -case `b'. (This is different from the code for `append-to-buffer', -which uses an upper-case `B'. *Note The Definition of -`append-to-buffer': append-to-buffer.) The lower-case `b' tells the -Lisp interpreter that the argument for `insert-buffer' should be an -existing buffer or else its name. (The upper-case `B' option -provides for the possibility that the buffer does not exist.) Emacs -will prompt you for the name of the buffer, offering you a default -buffer, with name completion enabled. If the buffer does not exist, -you receive a message that says "No match"; your terminal may beep at -you as well. - -The Body of the `insert-buffer' Function ----------------------------------------- - -The body of the `insert-buffer' function has two major parts: an `or' -expression and a `let' expression. The purpose of the `or' -expression is to ensure that the argument `buffer' is bound to a -buffer and not just the name of a buffer. The body of the `let' -expression contains the code which copies the other buffer into the -current buffer. - -In outline, the two expressions fit into the `insert-buffer' function -like this: - - (defun insert-buffer (buffer) - "DOCUMENTATION..." - (interactive "*bInsert buffer: ") - (or ... - ... - (let (VARLIST) - BODY-OF-`let'... ) - -To understand how the `or' expression ensures that the argument -`buffer' is bound to a buffer and not to the name of a buffer, it is -first necessary to understand the `or' function. - -Before doing this, let me rewrite this part of the function using -`if' so that you can see what is done in a manner that will be -familiar. - -`insert-buffer' With an `if' Instead of an `or' ------------------------------------------------ - -The job to be done is to make sure the value of `buffer' is a buffer -itself and not the name of a buffer. If the value is the name, then -the buffer itself must be got. - -You can imagine yourself at a conference where an usher is wandering -around holding a list with your name on it and looking for you: the -usher is "bound" to your name, not to you; but when the usher finds -you and takes your arm, the usher becomes "bound" to you. - -In Lisp, you might describe this situation like this: - - (if (not (holding-on-to-guest)) - (find-and-take-arm-of-guest)) - -We want to do the same thing with a buffer--if we do not have the -buffer itself, we want to get it. - -Using a predicate called `bufferp' that tells us whether we have a -buffer (rather than its name), we can write the code like this: - - (if (not (bufferp buffer)) ; if-part - (setq buffer (get-buffer buffer))) ; then-part - -Here, the true-or-false-test of the `if' expression is -`(not (bufferp buffer))'; and the then-part is the expression -`(setq buffer (get-buffer buffer))'. - -In the test, the function `bufferp' returns true if its argument is a -buffer--but false if its argument is the name of the buffer. (The -last character of the function name `bufferp' is the character `p'; -as we saw earlier, such use of `p' is a convention that indicates -that the function is a predicate, which is a term that means that the -function will determine whether some property is true or false. -*Note Using the Wrong Type Object as an Argument: Wrong Type of -Argument.) - -The function `not' precedes the expression `(bufferp buffer)', so the -true-or-false-test looks like this: - - (not (bufferp buffer)) - -`not' is a function that returns true if its argument is false and -false if its argument is true. So if `(bufferp buffer)' returns -true, the `not' expression returns false and vice-versa: what is "not -true" is false and what is "not false" is true. - -Using this test, the `if' expression works as follows: when the value -of the variable `buffer' is actually a buffer rather then its name, -the true-or-false-test returns false and the `if' expression does not -evaluate the then-part. This is fine, since we do not need to do -anything to the variable `buffer' if it really is a buffer. - -On the other hand, when the value of `buffer' is not a buffer itself, -but the name of a buffer, the true-or-false-test returns true and the -then-part of the expression is evaluated. In this case, the -then-part is `(setq buffer (get-buffer buffer))'. This expression -uses the `get-buffer' function to return an actual buffer itself, -given its name. The `setq' then sets the variable `buffer' to the -value of the buffer itself, replacing its previous value (which was -the name of the buffer). - -The `or' in the Body --------------------- - -The purpose of the `or' expression in the `insert-buffer' function is -to ensure that the argument `buffer' is bound to a buffer and not -just to the name of a buffer. The previous section shows how the job -could have been done using an `if' expression. However, the -`insert-buffer' function actually uses `or'. To understand this, it -is necessary to understand how `or' works. - -An `or' function can have any number of arguments. It evaluates each -argument in turn and returns the value of the first of its arguments -that is not `nil'. Also, and this is a crucial feature of `or', it -does not evaluate any subsequent arguments after returning the first -non-`nil' value. - -The `or' expression looks like this: - - (or (bufferp buffer) - (setq buffer (get-buffer buffer))) - -The first argument to `or' is the expression `(bufferp buffer)'. -This expression returns true (a non-`nil' value) if the buffer is -actually a buffer, and not just the name of a buffer. In the `or' -expression, if this is the case, the `or' expression returns this -true value and does not evaluate the next expression--and this is fine -with us, since we do not want to do anything to the value of `buffer' -if it really is a buffer. - -On the other hand, if the value of `(bufferp buffer)' is `nil', which -it will be if the value of `buffer' is the name of a buffer, the Lisp -interpreter evaluates the next element of the `or' expression. This -is the expression `(setq buffer (get-buffer buffer))'. This -expression returns a non-`nil' value, which is the value to which it -sets the variable `buffer'--and this value is a buffer itself, not -the name of a buffer. - -The result of all this is that the symbol `buffer' is always bound to -a buffer itself rather than to the name of a buffer. All this is -necessary because the `set-buffer' function in a following line only -works with a buffer itself, not with the name to a buffer. - -Incidentally, using `or', the situation with the usher would be -written like this: - - (or (holding-on-to-guest) (find-and-take-arm-of-guest)) - -The `let' Expression in `insert-buffer' ---------------------------------------- - -After ensuring that the variable `buffer' refers to a buffer itself -and not just to the name of a buffer, the `insert-buffer function' -continues with a `let' expression. This specifies three local -variables, `start', `end', and `newmark' and binds them to the -initial value `nil'. These variables are used inside the remainder -of the `let' and temporarily hide any other occurrence of variables -of the same name in Emacs until the end of the `let'. - -The body of the `let' contains two `save-excursion' expressions. -First, we will look at the inner `save-excursion' expression in -detail. The expression looks like this: - - (save-excursion - (set-buffer buffer) - (setq start (point-min) end (point-max))) - -The expression `(set-buffer buffer)' changes Emacs' attention from -the current buffer to the one from which the text will copied. In -that buffer, the variables `start' and `end' are set to the beginning -and end of the buffer, using the commands `point-min' and -`point-max'. Note that we have here an illustration of how `setq' is -able to set two variables in the same expression. The first argument -of `setq' is set to the value of its second, and its third argument -is set to the value of its fourth. - -After the body of the inner `save-excursion' is evaluated, the -`save-excursion' restores the original buffer, but `start' and `end' -remain set to the values of the beginning and end of the buffer from -which the text will be copied. - -The outer `save-excursion' expression looks like this: - - (save-excursion - (INNER-`save-excursion'-EXPRESSION - (GO-TO-NEW-BUFFER-AND-SET-`start'-AND-`end') - (insert-buffer-substring buffer start end) - (setq newmark (point))) - -The `insert-buffer-substring' function copies the text _into_ the -current buffer _from_ the region indicated by `start' and `end' in -`buffer'. Since the whole of the second buffer lies between `start' -and `end', the whole of the second buffer is copied into the buffer -you are editing. Next, the value of point, which will be at the end -of the inserted text, is recorded in the variable `newmark'. - -After the body of the outer `save-excursion' is evaluated, point and -mark are relocated to their original places. - -However, it is convenient to locate a mark at the end of the newly -inserted text and locate point at its beginning. The `newmark' -variable records the end of the inserted text. In the last line of -the `let' expression, the `(push-mark newmark)' expression function -sets a mark to this location. (The previous location of the mark is -still accessible; it is recorded on the mark ring and you can go back -to it with `C-u C-<SPC>'.) Meanwhile, point is located at the -beginning of the inserted text, which is where it was before you -called the insert function. - -The whole `let' expression looks like this: - - (let (start end newmark) - (save-excursion - (save-excursion - (set-buffer buffer) - (setq start (point-min) end (point-max))) - (insert-buffer-substring buffer start end) - (setq newmark (point))) - (push-mark newmark)) - -Like the `append-to-buffer' function, the `insert-buffer' function -uses `let', `save-excursion', and `set-buffer'. In addition, the -function illustrates one way to use `or'. All these functions are -building blocks that we will find and use again and again. - -Complete Definition of `beginning-of-buffer' -============================================ - -The basic structure of the `beginning-of-buffer' function has already -been discussed. (*Note A Simplified `beginning-of-buffer' -Definition: simplified-beginning-of-buffer.) This section describes -the complex part of the definition. - -As previously described, when invoked without an argument, -`beginning-of-buffer' moves the cursor to the beginning of the -buffer, leaving the mark at the previous position. However, when the -command is invoked with a number between one and ten, the function -considers that number to be a fraction of the length of the buffer, -measured in tenths, and Emacs moves the cursor that fraction of the -way from the beginning of the buffer. Thus, you can either call this -function with the key command `M-<', which will move the cursor to -the beginning of the buffer, or with a key command such as `C-u 7 -M-<' which will move the cursor to a point 70% of the way through the -buffer. If a number bigger than ten is used for the argument, it -moves to the end of the buffer. - -The `beginning-of-buffer' function can be called with or without an -argument. The use of the argument is optional. - -Optional Arguments ------------------- - -Unless told otherwise, Lisp expects that a function with an argument -in its function definition will be called with a value for that -argument. If that does not happen, you get an error and a message -that says `Wrong number of arguments'. - -However, optional arguments are a feature of Lisp: a "keyword" may be -used to tell the Lisp interpreter that an argument is optional. The -keyword is `&optional'. (The `&' in front of `optional' is part of -the keyword.) In a function definition, if an argument follows the -keyword `&optional', a value does not need to be passed to that -argument when the function is called. - -The first line of the function definition of `beginning-of-buffer' -therefore looks like this: - - (defun beginning-of-buffer (&optional arg) - -In outline, the whole function looks like this: - - (defun beginning-of-buffer (&optional arg) - "DOCUMENTATION..." - (interactive "P") - (push-mark) - (goto-char - (IF-THERE-IS-AN-ARGUMENT - FIGURE-OUT-WHERE-TO-GO - ELSE-GO-TO - (point-min)))) - -The function is similar to the `simplified-beginning-of-buffer' -function except that the `interactive' expression has `"P"' as an -argument and the `goto-char' function is followed by an if-then-else -expression that figures out where to put the cursor if there is an -argument. - -The `"P"' in the `interactive' expression tells Emacs to pass a -prefix argument, if there is one, to the function. A prefix argument -is made by typing the <META> key followed by a number, or by typing -`C-u' and then a number (if you don't type a number, `C-u' defaults -to 4). - -The true-or-false-test of the `if' expression is simple: it is simply -the argument `arg'. If `arg' has a value that is not `nil', which -will be the case if `beginning-of-buffer' is called with an argument, -then this true-or-false-test will return true and the then-part of -the `if' expression will be evaluated. On the other hand, if -`beginning-of-buffer' is not called with an argument, the value of -`arg' will be `nil' and the else-part of the `if' expression will be -evaluated. The else-part is simply `point-min', and when this is the -outcome, the whole `goto-char' expression is `(goto-char -(point-min))', which is how we saw the `beginning-of-buffer' function -in its simplified form. - -`beginning-of-buffer' with an Argument --------------------------------------- - -When `beginning-of-buffer' is called with an argument, an expression -is evaluated which calculates what value to pass to `goto-char'. -This expression is rather complicated at first sight. It includes an -inner `if' expression and much arithmetic. It looks like this: - - (if (> (buffer-size) 10000) - ;; Avoid overflow for large buffer sizes! - (* (prefix-numeric-value arg) (/ (buffer-size) 10)) - (/ - (+ 10 - (* - (buffer-size) (prefix-numeric-value arg))) 10)) - -Disentangle `beginning-of-buffer' -................................. - -Like other complex-looking expressions, the conditional expression -within `beginning-of-buffer' can be disentangled by looking at it as -parts of a template, in this case, the template for an if-then-else -expression. In skeletal form, the expression looks like this: - - (if (BUFFER-IS-LARGE - DIVIDE-BUFFER-SIZE-BY-10-AND-MULTIPLY-BY-ARG - ELSE-USE-ALTERNATE-CALCULATION - -The true-or-false-test of this inner `if' expression checks the size -of the buffer. The reason for this is that the old Version 18 Emacs -used numbers that are no bigger than eight million or so and in the -computation that followed, the programmer feared that Emacs might try -to use over-large numbers if the buffer were large. The term -`overflow', mentioned in the comment, means numbers that are over -large. Version 21 Emacs uses larger numbers, but this code has not -been touched, if only because people now look at buffers that are far, -far larger than ever before. - -There are two cases: if the buffer is large and if it is not. - -What happens in a large buffer -.............................. - -In `beginning-of-buffer', the inner `if' expression tests whether the -size of the buffer is greater than 10,000 characters. To do this, it -uses the `>' function and the `buffer-size' function. - -The line looks like this: - - (if (> (buffer-size) 10000) - -When the buffer is large, the then-part of the `if' expression is -evaluated. It reads like this (after formatting for easy reading): - - (* - (prefix-numeric-value arg) - (/ (buffer-size) 10)) - -This expression is a multiplication, with two arguments to the -function `*'. - -The first argument is `(prefix-numeric-value arg)'. When `"P"' is -used as the argument for `interactive', the value passed to the -function as its argument is passed a "raw prefix argument", and not a -number. (It is a number in a list.) To perform the arithmetic, a -conversion is necessary, and `prefix-numeric-value' does the job. - -The second argument is `(/ (buffer-size) 10)'. This expression -divides the numeric value of the buffer by ten. This produces a -number that tells how many characters make up one tenth of the buffer -size. (In Lisp, `/' is used for division, just as `*' is used for -multiplication.) - -In the multiplication expression as a whole, this amount is multiplied -by the value of the prefix argument--the multiplication looks like -this: - - (* NUMERIC-VALUE-OF-PREFIX-ARG - NUMBER-OF-CHARACTERS-IN-ONE-TENTH-OF-THE-BUFFER) - -If, for example, the prefix argument is `7', the one-tenth value will -be multiplied by 7 to give a position 70% of the way through the -buffer. - -The result of all this is that if the buffer is large, the -`goto-char' expression reads like this: - - (goto-char (* (prefix-numeric-value arg) - (/ (buffer-size) 10))) - -This puts the cursor where we want it. - -What happens in a small buffer -.............................. - -If the buffer contains fewer than 10,000 characters, a slightly -different computation is performed. You might think this is not -necessary, since the first computation could do the job. However, in -a small buffer, the first method may not put the cursor on exactly the -desired line; the second method does a better job. - -The code looks like this: - - (/ (+ 10 (* (buffer-size) (prefix-numeric-value arg))) 10)) - -This is code in which you figure out what happens by discovering how -the functions are embedded in parentheses. It is easier to read if -you reformat it with each expression indented more deeply than its -enclosing expression: - - (/ - (+ 10 - (* - (buffer-size) - (prefix-numeric-value arg))) - 10)) - -Looking at parentheses, we see that the innermost operation is -`(prefix-numeric-value arg)', which converts the raw argument to a -number. This number is multiplied by the buffer size in the following -expression: - - (* (buffer-size) (prefix-numeric-value arg) - -This multiplication creates a number that may be larger than the size -of the buffer--seven times larger if the argument is 7, for example. -Ten is then added to this number and finally the large number is -divided by ten to provide a value that is one character larger than -the percentage position in the buffer. - -The number that results from all this is passed to `goto-char' and -the cursor is moved to that point. - -The Complete `beginning-of-buffer' ----------------------------------- - -Here is the complete text of the `beginning-of-buffer' function: - - (defun beginning-of-buffer (&optional arg) - "Move point to the beginning of the buffer; - leave mark at previous position. - With arg N, put point N/10 of the way - from the true beginning. - Don't use this in Lisp programs! - \(goto-char (point-min)) is faster - and does not set the mark." - (interactive "P") - (push-mark) - (goto-char - (if arg - (if (> (buffer-size) 10000) - ;; Avoid overflow for large buffer sizes! - (* (prefix-numeric-value arg) - (/ (buffer-size) 10)) - (/ (+ 10 (* (buffer-size) - (prefix-numeric-value arg))) - 10)) - (point-min))) - (if arg (forward-line 1))) - -Except for two small points, the previous discussion shows how this -function works. The first point deals with a detail in the -documentation string, and the second point concerns the last line of -the function. - -In the documentation string, there is reference to an expression: - - \(goto-char (point-min)) - -A `\' is used before the first parenthesis of this expression. This -`\' tells the Lisp interpreter that the expression should be printed -as shown in the documentation rather than evaluated as a symbolic -expression, which is what it looks like. - -Finally, the last line of the `beginning-of-buffer' command says to -move point to the beginning of the next line if the command is -invoked with an argument: - - (if arg (forward-line 1))) - -This puts the cursor at the beginning of the first line after the -appropriate tenths position in the buffer. This is a flourish that -means that the cursor is always located _at least_ the requested -tenths of the way through the buffer, which is a nicety that is, -perhaps, not necessary, but which, if it did not occur, would be sure -to draw complaints. - -Review -====== - -Here is a brief summary of some of the topics covered in this chapter. - -`or' - Evaluate each argument in sequence, and return the value of the - first argument that is not `nil'; if none return a value that is - not `nil', return `nil'. In brief, return the first true value - of the arguments; return a true value if one _or_ any of the - other are true. - -`and' - Evaluate each argument in sequence, and if any are `nil', return - `nil'; if none are `nil', return the value of the last argument. - In brief, return a true value only if all the arguments are - true; return a true value if one _and_ each of the others is - true. - -`&optional' - A keyword used to indicate that an argument to a function - definition is optional; this means that the function can be - evaluated without the argument, if desired. - -`prefix-numeric-value' - Convert the `raw prefix argument' produced by `(interactive - "P")' to a numeric value. - -`forward-line' - Move point forward to the beginning of the next line, or if the - argument is greater than one, forward that many lines. If it - can't move as far forward as it is supposed to, `forward-line' - goes forward as far as it can and then returns a count of the - number of additional lines it was supposed to move but couldn't. - -`erase-buffer' - Delete the entire contents of the current buffer. - -`bufferp' - Return `t' if its argument is a buffer; otherwise return `nil'. - -`optional' Argument Exercise -============================ - -Write an interactive function with an optional argument that tests -whether its argument, a number, is greater or less than the value of -`fill-column', and tells you which, in a message. However, if you do -not pass an argument to the function, use 56 as a default value. - -Narrowing and Widening -********************** - -Narrowing is a feature of Emacs that makes it possible for you to -focus on a specific part of a buffer, and work without accidentally -changing other parts. Narrowing is normally disabled since it can -confuse novices. - -The Advantages of Narrowing -=========================== - -With narrowing, the rest of a buffer is made invisible, as if it -weren't there. This is an advantage if, for example, you want to -replace a word in one part of a buffer but not in another: you narrow -to the part you want and the replacement is carried out only in that -section, not in the rest of the buffer. Searches will only work -within a narrowed region, not outside of one, so if you are fixing a -part of a document, you can keep yourself from accidentally finding -parts you do not need to fix by narrowing just to the region you want. -(The key binding for `narrow-to-region' is `C-x n n'.) - -However, narrowing does make the rest of the buffer invisible, which -can scare people who inadvertently invoke narrowing and think they -have deleted a part of their file. Moreover, the `undo' command -(which is usually bound to `C-x u') does not turn off narrowing (nor -should it), so people can become quite desperate if they do not know -that they can return the rest of a buffer to visibility with the -`widen' command. (The key binding for `widen' is `C-x n w'.) - -Narrowing is just as useful to the Lisp interpreter as to a human. -Often, an Emacs Lisp function is designed to work on just part of a -buffer; or conversely, an Emacs Lisp function needs to work on all of -a buffer that has been narrowed. The `what-line' function, for -example, removes the narrowing from a buffer, if it has any narrowing -and when it has finished its job, restores the narrowing to what it -was. On the other hand, the `count-lines' function, which is called -by `what-line', uses narrowing to restrict itself to just that portion -of the buffer in which it is interested and then restores the previous -situation. - -The `save-restriction' Special Form -=================================== - -In Emacs Lisp, you can use the `save-restriction' special form to -keep track of whatever narrowing is in effect, if any. When the Lisp -interpreter meets with `save-restriction', it executes the code in -the body of the `save-restriction' expression, and then undoes any -changes to narrowing that the code caused. If, for example, the -buffer is narrowed and the code that follows `save-restriction' gets -rid of the narrowing, `save-restriction' returns the buffer to its -narrowed region afterwards. In the `what-line' command, any -narrowing the buffer may have is undone by the `widen' command that -immediately follows the `save-restriction' command. Any original -narrowing is restored just before the completion of the function. - -The template for a `save-restriction' expression is simple: - - (save-restriction - BODY... ) - -The body of the `save-restriction' is one or more expressions that -will be evaluated in sequence by the Lisp interpreter. - -Finally, a point to note: when you use both `save-excursion' and -`save-restriction', one right after the other, you should use -`save-excursion' outermost. If you write them in reverse order, you -may fail to record narrowing in the buffer to which Emacs switches -after calling `save-excursion'. Thus, when written together, -`save-excursion' and `save-restriction' should be written like this: - - (save-excursion - (save-restriction - BODY...)) - -In other circumstances, when not written together, the -`save-excursion' and `save-restriction' special forms must be written -in the order appropriate to the function. - -For example, - - (save-restriction - (widen) - (save-excursion - BODY...)) - -`what-line' -=========== - -The `what-line' command tells you the number of the line in which the -cursor is located. The function illustrates the use of the -`save-restriction' and `save-excursion' commands. Here is the text -of the function in full: - - (defun what-line () - "Print the current line number (in the buffer) of point." - (interactive) - (save-restriction - (widen) - (save-excursion - (beginning-of-line) - (message "Line %d" - (1+ (count-lines 1 (point))))))) - -The function has a documentation line and is interactive, as you would -expect. The next two lines use the functions `save-restriction' and -`widen'. - -The `save-restriction' special form notes whatever narrowing is in -effect, if any, in the current buffer and restores that narrowing -after the code in the body of the `save-restriction' has been -evaluated. - -The `save-restriction' special form is followed by `widen'. This -function undoes any narrowing the current buffer may have had when -`what-line' was called. (The narrowing that was there is the -narrowing that `save-restriction' remembers.) This widening makes it -possible for the line counting commands to count from the beginning -of the buffer. Otherwise, they would have been limited to counting -within the accessible region. Any original narrowing is restored -just before the completion of the function by the `save-restriction' -special form. - -The call to `widen' is followed by `save-excursion', which saves the -location of the cursor (i.e., of point) and of the mark, and restores -them after the code in the body of the `save-excursion' uses the -`beginning-of-line' function to move point. - -(Note that the `(widen)' expression comes between the -`save-restriction' and `save-excursion' special forms. When you -write the two `save- ...' expressions in sequence, write -`save-excursion' outermost.) - -The last two lines of the `what-line' function are functions to count -the number of lines in the buffer and then print the number in the -echo area. - - (message "Line %d" - (1+ (count-lines 1 (point))))))) - -The `message' function prints a one-line message at the bottom of the -Emacs screen. The first argument is inside of quotation marks and is -printed as a string of characters. However, it may contain `%d', -`%s', or `%c' to print arguments that follow the string. `%d' prints -the argument as a decimal, so the message will say something such as -`Line 243'. - -The number that is printed in place of the `%d' is computed by the -last line of the function: - - (1+ (count-lines 1 (point))) - -What this does is count the lines from the first position of the -buffer, indicated by the `1', up to `(point)', and then add one to -that number. (The `1+' function adds one to its argument.) We add -one to it because line 2 has only one line before it, and -`count-lines' counts only the lines _before_ the current line. - -After `count-lines' has done its job, and the message has been -printed in the echo area, the `save-excursion' restores point and -mark to their original positions; and `save-restriction' restores the -original narrowing, if any. - -Exercise with Narrowing -======================= - -Write a function that will display the first 60 characters of the -current buffer, even if you have narrowed the buffer to its latter -half so that the first line is inaccessible. Restore point, mark, -and narrowing. For this exercise, you need to use -`save-restriction', `widen', `goto-char', `point-min', -`buffer-substring', `message', and other functions, a whole potpourri. - -`car', `cdr', `cons': Fundamental Functions -******************************************* - -In Lisp, `car', `cdr', and `cons' are fundamental functions. The -`cons' function is used to construct lists, and the `car' and `cdr' -functions are used to take them apart. - -In the walk through of the `copy-region-as-kill' function, we will -see `cons' as well as two variants on `cdr', namely, `setcdr' and -`nthcdr'. (*Note copy-region-as-kill::.) - -Strange Names -============= - -The name of the `cons' function is not unreasonable: it is an -abbreviation of the word `construct'. The origins of the names for -`car' and `cdr', on the other hand, are esoteric: `car' is an acronym -from the phrase `Contents of the Address part of the Register'; and -`cdr' (pronounced `could-er') is an acronym from the phrase `Contents -of the Decrement part of the Register'. These phrases refer to -specific pieces of hardware on the very early computer on which the -original Lisp was developed. Besides being obsolete, the phrases -have been completely irrelevant for more than 25 years to anyone -thinking about Lisp. Nonetheless, although a few brave scholars have -begun to use more reasonable names for these functions, the old terms -are still in use. In particular, since the terms are used in the -Emacs Lisp source code, we will use them in this introduction. - -`car' and `cdr' -=============== - -The CAR of a list is, quite simply, the first item in the list. Thus -the CAR of the list `(rose violet daisy buttercup)' is `rose'. - -If you are reading this in Info in GNU Emacs, you can see this by -evaluating the following: - - (car '(rose violet daisy buttercup)) - -After evaluating the expression, `rose' will appear in the echo area. - -Clearly, a more reasonable name for the `car' function would be -`first' and this is often suggested. - -`car' does not remove the first item from the list; it only reports -what it is. After `car' has been applied to a list, the list is -still the same as it was. In the jargon, `car' is `non-destructive'. -This feature turns out to be important. - -The CDR of a list is the rest of the list, that is, the `cdr' -function returns the part of the list that follows the first item. -Thus, while the CAR of the list `'(rose violet daisy buttercup)' is -`rose', the rest of the list, the value returned by the `cdr' -function, is `(violet daisy buttercup)'. - -You can see this by evaluating the following in the usual way: - - (cdr '(rose violet daisy buttercup)) - -When you evaluate this, `(violet daisy buttercup)' will appear in the -echo area. - -Like `car', `cdr' does not remove any elements from the list--it just -returns a report of what the second and subsequent elements are. - -Incidentally, in the example, the list of flowers is quoted. If it -were not, the Lisp interpreter would try to evaluate the list by -calling `rose' as a function. In this example, we do not want to do -that. - -Clearly, a more reasonable name for `cdr' would be `rest'. - -(There is a lesson here: when you name new functions, consider very -carefully what you are doing, since you may be stuck with the names -for far longer than you expect. The reason this document perpetuates -these names is that the Emacs Lisp source code uses them, and if I did -not use them, you would have a hard time reading the code; but do, -please, try to avoid using these terms yourself. The people who come -after you will be grateful to you.) - -When `car' and `cdr' are applied to a list made up of symbols, such -as the list `(pine fir oak maple)', the element of the list returned -by the function `car' is the symbol `pine' without any parentheses -around it. `pine' is the first element in the list. However, the -CDR of the list is a list itself, `(fir oak maple)', as you can see -by evaluating the following expressions in the usual way: - - (car '(pine fir oak maple)) - - (cdr '(pine fir oak maple)) - -On the other hand, in a list of lists, the first element is itself a -list. `car' returns this first element as a list. For example, the -following list contains three sub-lists, a list of carnivores, a list -of herbivores and a list of sea mammals: - - (car '((lion tiger cheetah) - (gazelle antelope zebra) - (whale dolphin seal))) - -In this example, the first element or CAR of the list is the list of -carnivores, `(lion tiger cheetah)', and the rest of the list is -`((gazelle antelope zebra) (whale dolphin seal))'. - - (cdr '((lion tiger cheetah) - (gazelle antelope zebra) - (whale dolphin seal))) - -It is worth saying again that `car' and `cdr' are -non-destructive--that is, they do not modify or change lists to which -they are applied. This is very important for how they are used. - -Also, in the first chapter, in the discussion about atoms, I said that -in Lisp, "certain kinds of atom, such as an array, can be separated -into parts; but the mechanism for doing this is different from the -mechanism for splitting a list. As far as Lisp is concerned, the -atoms of a list are unsplittable." (*Note Lisp Atoms::.) The `car' -and `cdr' functions are used for splitting lists and are considered -fundamental to Lisp. Since they cannot split or gain access to the -parts of an array, an array is considered an atom. Conversely, the -other fundamental function, `cons', can put together or construct a -list, but not an array. (Arrays are handled by array-specific -functions. *Note Arrays: (elisp)Arrays.) - -`cons' -====== - -The `cons' function constructs lists; it is the inverse of `car' and -`cdr'. For example, `cons' can be used to make a four element list -from the three element list, `(fir oak maple)': - - (cons 'pine '(fir oak maple)) - -After evaluating this list, you will see - - (pine fir oak maple) - -appear in the echo area. `cons' causes the creation of a new list in -which the element is followed by the elements of the original list. - -We often say that ``cons' puts a new element at the beginning of a -list; it attaches or pushes elements onto the list', but this -phrasing can be misleading, since `cons' does not change an existing -list, but creates a new one. - -Like `car' and `cdr', `cons' is non-destructive. - -Build a list ------------- - -`cons' must have a list to attach to.(1) You cannot start from -absolutely nothing. If you are building a list, you need to provide -at least an empty list at the beginning. Here is a series of `cons' -expressions that build up a list of flowers. If you are reading this -in Info in GNU Emacs, you can evaluate each of the expressions in the -usual way; the value is printed in this text after `=>', which you -may read as `evaluates to'. - - (cons 'buttercup ()) - => (buttercup) - - (cons 'daisy '(buttercup)) - => (daisy buttercup) - - (cons 'violet '(daisy buttercup)) - => (violet daisy buttercup) - - (cons 'rose '(violet daisy buttercup)) - => (rose violet daisy buttercup) - -In the first example, the empty list is shown as `()' and a list made -up of `buttercup' followed by the empty list is constructed. As you -can see, the empty list is not shown in the list that was -constructed. All that you see is `(buttercup)'. The empty list is -not counted as an element of a list because there is nothing in an -empty list. Generally speaking, an empty list is invisible. - -The second example, `(cons 'daisy '(buttercup))' constructs a new, -two element list by putting `daisy' in front of `buttercup'; and the -third example constructs a three element list by putting `violet' in -front of `daisy' and `buttercup'. - ----------- Footnotes ---------- - -(1) Actually, you can `cons' an element to an atom to produce a -dotted pair. Dotted pairs are not discussed here; see *Note Dotted -Pair Notation: (elisp)Dotted Pair Notation. - -Find the Length of a List: `length' ------------------------------------ - -You can find out how many elements there are in a list by using the -Lisp function `length', as in the following examples: - - (length '(buttercup)) - => 1 - - (length '(daisy buttercup)) - => 2 - - (length (cons 'violet '(daisy buttercup))) - => 3 - -In the third example, the `cons' function is used to construct a -three element list which is then passed to the `length' function as -its argument. - -We can also use `length' to count the number of elements in an empty -list: - - (length ()) - => 0 - -As you would expect, the number of elements in an empty list is zero. - -An interesting experiment is to find out what happens if you try to -find the length of no list at all; that is, if you try to call -`length' without giving it an argument, not even an empty list: - - (length ) - -What you see, if you evaluate this, is the error message - - Wrong number of arguments: #<subr length>, 0 - -This means that the function receives the wrong number of arguments, -zero, when it expects some other number of arguments. In this case, -one argument is expected, the argument being a list whose length the -function is measuring. (Note that _one_ list is _one_ argument, even -if the list has many elements inside it.) - -The part of the error message that says `#<subr length>' is the name -of the function. This is written with a special notation, `#<subr', -that indicates that the function `length' is one of the primitive -functions written in C rather than in Emacs Lisp. (`subr' is an -abbreviation for `subroutine'.) *Note What Is a Function?: -(elisp)What Is a Function, for more about subroutines. - -`nthcdr' -======== - -The `nthcdr' function is associated with the `cdr' function. What it -does is take the CDR of a list repeatedly. - -If you take the CDR of the list `(pine fir oak maple)', you will be -returned the list `(fir oak maple)'. If you repeat this on what was -returned, you will be returned the list `(oak maple)'. (Of course, -repeated CDRing on the original list will just give you the original -CDR since the function does not change the list. You need to -evaluate the CDR of the CDR and so on.) If you continue this, -eventually you will be returned an empty list, which in this case, -instead of being shown as `()' is shown as `nil'. - -For review, here is a series of repeated CDRs, the text following the -`=>' shows what is returned. - - (cdr '(pine fir oak maple)) - =>(fir oak maple) - - (cdr '(fir oak maple)) - => (oak maple) - - (cdr '(oak maple)) - =>(maple) - - (cdr '(maple)) - => nil - - (cdr 'nil) - => nil - - (cdr ()) - => nil - -You can also do several CDRs without printing the values in between, -like this: - - (cdr (cdr '(pine fir oak maple))) - => (oak maple) - -In this example, the Lisp interpreter evaluates the innermost list -first. The innermost list is quoted, so it just passes the list as -it is to the innermost `cdr'. This `cdr' passes a list made up of the -second and subsequent elements of the list to the outermost `cdr', -which produces a list composed of the third and subsequent elements of -the original list. In this example, the `cdr' function is repeated -and returns a list that consists of the original list without its -first two elements. - -The `nthcdr' function does the same as repeating the call to `cdr'. -In the following example, the argument 2 is passed to the function -`nthcdr', along with the list, and the value returned is the list -without its first two items, which is exactly the same as repeating -`cdr' twice on the list: - - (nthcdr 2 '(pine fir oak maple)) - => (oak maple) - -Using the original four element list, we can see what happens when -various numeric arguments are passed to `nthcdr', including 0, 1, and -5: - - ;; Leave the list as it was. - (nthcdr 0 '(pine fir oak maple)) - => (pine fir oak maple) - - ;; Return a copy without the first element. - (nthcdr 1 '(pine fir oak maple)) - => (fir oak maple) - - ;; Return a copy of the list without three elements. - (nthcdr 3 '(pine fir oak maple)) - => (maple) - - ;; Return a copy lacking all four elements. - (nthcdr 4 '(pine fir oak maple)) - => nil - - ;; Return a copy lacking all elements. - (nthcdr 5 '(pine fir oak maple)) - => nil - -`nth' -===== - -The `nthcdr' function takes the CDR of a list repeatedly. The `nth' -function takes the CAR of the result returned by `nthcdr'. It -returns the Nth element of the list. - -Thus, if it were not defined in C for speed, the definition of `nth' -would be: - - (defun nth (n list) - "Returns the Nth element of LIST. - N counts from zero. If LIST is not that long, nil is returned." - (car (nthcdr n list))) - -(Originally, `nth' was defined in Emacs Lisp in `subr.el', but its -definition was redone in C in the 1980s.) - -The `nth' function returns a single element of a list. This can be -very convenient. - -Note that the elements are numbered from zero, not one. That is to -say, the first element of a list, its CAR is the zeroth element. -This is called `zero-based' counting and often bothers people who are -accustomed to the first element in a list being number one, which is -`one-based'. - -For example: - - (nth 0 '("one" "two" "three")) - => "one" - - (nth 1 '("one" "two" "three")) - => "two" - -It is worth mentioning that `nth', like `nthcdr' and `cdr', does not -change the original list--the function is non-destructive. This is -in sharp contrast to the `setcar' and `setcdr' functions. - -`setcar' -======== - -As you might guess from their names, the `setcar' and `setcdr' -functions set the CAR or the CDR of a list to a new value. They -actually change the original list, unlike `car' and `cdr' which leave -the original list as it was. One way to find out how this works is -to experiment. We will start with the `setcar' function. - -First, we can make a list and then set the value of a variable to the -list, using the `setq' function. Here is a list of animals: - - (setq animals '(antelope giraffe lion tiger)) - -If you are reading this in Info inside of GNU Emacs, you can evaluate -this expression in the usual fashion, by positioning the cursor after -the expression and typing `C-x C-e'. (I'm doing this right here as I -write this. This is one of the advantages of having the interpreter -built into the computing environment.) - -When we evaluate the variable `animals', we see that it is bound to -the list `(antelope giraffe lion tiger)': - - animals - => (antelope giraffe lion tiger) - -Put another way, the variable `animals' points to the list `(antelope -giraffe lion tiger)'. - -Next, evaluate the function `setcar' while passing it two arguments, -the variable `animals' and the quoted symbol `hippopotamus'; this is -done by writing the three element list `(setcar animals -'hippopotamus)' and then evaluating it in the usual fashion: - - (setcar animals 'hippopotamus) - -After evaluating this expression, evaluate the variable `animals' -again. You will see that the list of animals has changed: - - animals - => (hippopotamus giraffe lion tiger) - -The first element on the list, `antelope' is replaced by -`hippopotamus'. - -So we can see that `setcar' did not add a new element to the list as -`cons' would have; it replaced `giraffe' with `hippopotamus'; it -_changed_ the list. - -`setcdr' -======== - -The `setcdr' function is similar to the `setcar' function, except -that the function replaces the second and subsequent elements of a -list rather than the first element. - -To see how this works, set the value of the variable to a list of -domesticated animals by evaluating the following expression: - - (setq domesticated-animals '(horse cow sheep goat)) - -If you now evaluate the list, you will be returned the list `(horse -cow sheep goat)': - - domesticated-animals - => (horse cow sheep goat) - -Next, evaluate `setcdr' with two arguments, the name of the variable -which has a list as its value, and the list to which the CDR of the -first list will be set; - - (setcdr domesticated-animals '(cat dog)) - -If you evaluate this expression, the list `(cat dog)' will appear in -the echo area. This is the value returned by the function. The -result we are interested in is the "side effect", which we can see by -evaluating the variable `domesticated-animals': - - domesticated-animals - => (horse cat dog) - -Indeed, the list is changed from `(horse cow sheep goat)' to `(horse -cat dog)'. The CDR of the list is changed from `(cow sheep goat)' to -`(cat dog)'. - -Exercise -======== - -Construct a list of four birds by evaluating several expressions with -`cons'. Find out what happens when you `cons' a list onto itself. -Replace the first element of the list of four birds with a fish. -Replace the rest of that list with a list of other fish. - -Cutting and Storing Text -************************ - -Whenever you cut or clip text out of a buffer with a `kill' command in -GNU Emacs, it is stored in a list and you can bring it back with a -`yank' command. - -(The use of the word `kill' in Emacs for processes which specifically -_do not_ destroy the values of the entities is an unfortunate -historical accident. A much more appropriate word would be `clip' -since that is what the kill commands do; they clip text out of a -buffer and put it into storage from which it can be brought back. I -have often been tempted to replace globally all occurrences of `kill' -in the Emacs sources with `clip' and all occurrences of `killed' with -`clipped'.) - -Storing Text in a List -====================== - -When text is cut out of a buffer, it is stored on a list. Successive -pieces of text are stored on the list successively, so the list might -look like this: - - ("a piece of text" "previous piece") - -The function `cons' can be used to to create a new list from a piece -of text (an `atom', to use the jargon) and an existing list, like -this: - - (cons "another piece" - '("a piece of text" "previous piece")) - -If you evaluate this expression, a list of three elements will appear -in the echo area: - - ("another piece" "a piece of text" "previous piece") - -With the `car' and `nthcdr' functions, you can retrieve whichever -piece of text you want. For example, in the following code, `nthcdr -1 ...' returns the list with the first item removed; and the `car' -returns the first element of that remainder--the second element of -the original list: - - (car (nthcdr 1 '("another piece" - "a piece of text" - "previous piece"))) - => "a piece of text" - -The actual functions in Emacs are more complex than this, of course. -The code for cutting and retrieving text has to be written so that -Emacs can figure out which element in the list you want--the first, -second, third, or whatever. In addition, when you get to the end of -the list, Emacs should give you the first element of the list, rather -than nothing at all. - -The list that holds the pieces of text is called the "kill ring". -This chapter leads up to a description of the kill ring and how it is -used by first tracing how the `zap-to-char' function works. This -function uses (or `calls') a function that invokes a function that -manipulates the kill ring. Thus, before reaching the mountains, we -climb the foothills. - -A subsequent chapter describes how text that is cut from the buffer is -retrieved. *Note Yanking Text Back: Yanking. - -`zap-to-char' -============= - -The `zap-to-char' function barely changed between GNU Emacs version -19 and GNU Emacs version 21. However, `zap-to-char' calls another -function, `kill-region', which enjoyed a major rewrite on the way to -version 21. - -The `kill-region' function in Emacs 19 is complex, but does not use -code that is important at this time. We will skip it. - -The `kill-region' function in Emacs 21 is easier to read than the -same function in Emacs 19 and introduces a very important concept, -that of error handling. We will walk through the function. - -But first, let us look at the interactive `zap-to-char' function. - -The Complete `zap-to-char' Implementation ------------------------------------------ - -The GNU Emacs version 19 and version 21 implementations of the -`zap-to-char' function are nearly identical in form, and they work -alike. The function removes the text in the region between the -location of the cursor (i.e., of point) up to and including the next -occurrence of a specified character. The text that `zap-to-char' -removes is put in the kill ring; and it can be retrieved from the kill -ring by typing `C-y' (`yank'). If the command is given an argument, -it removes text through that number of occurrences. Thus, if the -cursor were at the beginning of this sentence and the character were -`s', `Thus' would be removed. If the argument were two, `Thus, if -the curs' would be removed, up to and including the `s' in `cursor'. - -If the specified character is not found, `zap-to-char' will say -"Search failed", tell you the character you typed, and not remove any -text. - -In order to determine how much text to remove, `zap-to-char' uses a -search function. Searches are used extensively in code that -manipulates text, and we will focus attention on them as well as on -the deletion command. - -Here is the complete text of the version 19 implementation of the -function: - - (defun zap-to-char (arg char) ; version 19 implementation - "Kill up to and including ARG'th occurrence of CHAR. - Goes backward if ARG is negative; error if CHAR not found." - (interactive "*p\ncZap to char: ") - (kill-region (point) - (progn - (search-forward - (char-to-string char) nil nil arg) - (point)))) - -The `interactive' Expression ----------------------------- - -The interactive expression in the `zap-to-char' command looks like -this: - - (interactive "*p\ncZap to char: ") - -The part within quotation marks, `"*p\ncZap to char: "', specifies -three different things. First, and most simply, the asterisk, `*', -causes an error to be signalled if the buffer is read-only. This -means that if you try `zap-to-char' in a read-only buffer you will -not be able to remove text, and you will receive a message that says -"Buffer is read-only"; your terminal may beep at you as well. - -The version 21 implementation does not have the asterisk, `*'. The -function works the same as in version 19: in both cases, it cannot -remove text from a read-only buffer but the function does copy the -text that would have been removed to the kill ring. Also, in both -cases, you see an error message. - -However, the version 19 implementation copies text from a read-only -buffer only because of a mistake in the implementation of -`interactive'. According to the documentation for `interactive', the -asterisk, `*', should prevent the `zap-to-char' function from doing -anything at all when the buffer is read only. The function should -not copy the text to the kill ring. It is a bug that it does. - -In version 21, `interactive' is implemented correctly. So the -asterisk, `*', had to be removed from the interactive specification. -If you insert an `*' and evaluate the function definition, then the -next time you run the `zap-to-char' function on a read-only buffer, -you will not copy any text. - -That change aside, and a change to the documentation, the two versions -of the `zap-to-char' function are identical. - -Let us continue with the interactive specification. - -The second part of `"*p\ncZap to char: "' is the `p'. This part is -separated from the next part by a newline, `\n'. The `p' means that -the first argument to the function will be passed the value of a -`processed prefix'. The prefix argument is passed by typing `C-u' -and a number, or `M-' and a number. If the function is called -interactively without a prefix, 1 is passed to this argument. - -The third part of `"*p\ncZap to char: "' is `cZap to char: '. In -this part, the lower case `c' indicates that `interactive' expects a -prompt and that the argument will be a character. The prompt follows -the `c' and is the string `Zap to char: ' (with a space after the -colon to make it look good). - -What all this does is prepare the arguments to `zap-to-char' so they -are of the right type, and give the user a prompt. - -The Body of `zap-to-char' -------------------------- - -The body of the `zap-to-char' function contains the code that kills -(that is, removes) the text in the region from the current position -of the cursor up to and including the specified character. The first -part of the code looks like this: - - (kill-region (point) ... - -`(point)' is the current position of the cursor. - -The next part of the code is an expression using `progn'. The body -of the `progn' consists of calls to `search-forward' and `point'. - -It is easier to understand how `progn' works after learning about -`search-forward', so we will look at `search-forward' and then at -`progn'. - -The `search-forward' Function ------------------------------ - -The `search-forward' function is used to locate the -zapped-for-character in `zap-to-char'. If the search is successful, -`search-forward' leaves point immediately after the last character in -the target string. (In `zap-to-char', the target string is just one -character long.) If the search is backwards, `search-forward' leaves -point just before the first character in the target. Also, -`search-forward' returns `t' for true. (Moving point is therefore a -`side effect'.) - -In `zap-to-char', the `search-forward' function looks like this: - - (search-forward (char-to-string char) nil nil arg) - -The `search-forward' function takes four arguments: - - 1. The first argument is the target, what is searched for. This - must be a string, such as `"z"'. - - As it happens, the argument passed to `zap-to-char' is a single - character. Because of the way computers are built, the Lisp - interpreter may treat a single character as being different from - a string of characters. Inside the computer, a single character - has a different electronic format than a string of one - character. (A single character can often be recorded in the - computer using exactly one byte; but a string may be longer, and - the computer needs to be ready for this.) Since the - `search-forward' function searches for a string, the character - that the `zap-to-char' function receives as its argument must be - converted inside the computer from one format to the other; - otherwise the `search-forward' function will fail. The - `char-to-string' function is used to make this conversion. - - 2. The second argument bounds the search; it is specified as a - position in the buffer. In this case, the search can go to the - end of the buffer, so no bound is set and the second argument is - `nil'. - - 3. The third argument tells the function what it should do if the - search fails--it can signal an error (and print a message) or it - can return `nil'. A `nil' as the third argument causes the - function to signal an error when the search fails. - - 4. The fourth argument to `search-forward' is the repeat count--how - many occurrences of the string to look for. This argument is - optional and if the function is called without a repeat count, - this argument is passed the value 1. If this argument is - negative, the search goes backwards. - -In template form, a `search-forward' expression looks like this: - - (search-forward "TARGET-STRING" - LIMIT-OF-SEARCH - WHAT-TO-DO-IF-SEARCH-FAILS - REPEAT-COUNT) - -We will look at `progn' next. - -The `progn' Special Form ------------------------- - -`progn' is a special form that causes each of its arguments to be -evaluated in sequence and then returns the value of the last one. The -preceding expressions are evaluated only for the side effects they -perform. The values produced by them are discarded. - -The template for a `progn' expression is very simple: - - (progn - BODY...) - -In `zap-to-char', the `progn' expression has to do two things: put -point in exactly the right position; and return the location of point -so that `kill-region' will know how far to kill to. - -The first argument to the `progn' is `search-forward'. When -`search-forward' finds the string, the function leaves point -immediately after the last character in the target string. (In this -case the target string is just one character long.) If the search is -backwards, `search-forward' leaves point just before the first -character in the target. The movement of point is a side effect. - -The second and last argument to `progn' is the expression `(point)'. -This expression returns the value of point, which in this case will -be the location to which it has been moved by `search-forward'. This -value is returned by the `progn' expression and is passed to -`kill-region' as `kill-region''s second argument. - -Summing up `zap-to-char' ------------------------- - -Now that we have seen how `search-forward' and `progn' work, we can -see how the `zap-to-char' function works as a whole. - -The first argument to `kill-region' is the position of the cursor -when the `zap-to-char' command is given--the value of point at that -time. Within the `progn', the search function then moves point to -just after the zapped-to-character and `point' returns the value of -this location. The `kill-region' function puts together these two -values of point, the first one as the beginning of the region and the -second one as the end of the region, and removes the region. - -The `progn' special form is necessary because the `kill-region' -command takes two arguments; and it would fail if `search-forward' -and `point' expressions were written in sequence as two additional -arguments. The `progn' expression is a single argument to -`kill-region' and returns the one value that `kill-region' needs for -its second argument. - -`kill-region' -============= - -The `zap-to-char' function uses the `kill-region' function. This -function clips text from a region and copies that text to the kill -ring, from which it may be retrieved. - -The Emacs 21 version of that function uses `condition-case' and -`copy-region-as-kill', both of which we will explain. -`condition-case' is an important special form. - -In essence, the `kill-region' function calls `condition-case', which -takes three arguments. In this function, the first argument does -nothing. The second argument contains the code that does the work -when all goes well. The third argument contains the code that is -called in the event of an error. - -The Complete `kill-region' Definition -------------------------------------- - -We will go through the `condition-case' code in a moment. First, let -us look at the complete definition of `kill-region', with comments -added: - - (defun kill-region (beg end) - "Kill between point and mark. - The text is deleted but saved in the kill ring." - (interactive "r") - - ;; 1. `condition-case' takes three arguments. - ;; If the first argument is nil, as it is here, - ;; information about the error signal is not - ;; stored for use by another function. - (condition-case nil - - ;; 2. The second argument to `condition-case' - ;; tells the Lisp interpreter what to do when all goes well. - - ;; The `delete-and-extract-region' function usually does the - ;; work. If the beginning and ending of the region are both - ;; the same, then the variable `string' will be empty, or nil - (let ((string (delete-and-extract-region beg end))) - - ;; `when' is an `if' clause that cannot take an `else-part'. - ;; Emacs normally sets the value of `last-command' to the - ;; previous command. - ;; `kill-append' concatenates the new string and the old. - ;; `kill-new' inserts text into a new item in the kill ring. - (when string - (if (eq last-command 'kill-region) - ;; if true, prepend string - (kill-append string (< end beg)) - (kill-new string))) - (setq this-command 'kill-region)) - - ;; 3. The third argument to `condition-case' tells the interpreter - ;; what to do with an error. - ;; The third argument has a conditions part and a body part. - ;; If the conditions are met (in this case, - ;; if text or buffer is read-only) - ;; then the body is executed. - ((buffer-read-only text-read-only) ;; this is the if-part - ;; then... - (copy-region-as-kill beg end) - (if kill-read-only-ok ;; usually this variable is nil - (message "Read only text copied to kill ring") - ;; or else, signal an error if the buffer is read-only; - (barf-if-buffer-read-only) - ;; and, in any case, signal that the text is read-only. - (signal 'text-read-only (list (current-buffer))))))) - -`condition-case' ----------------- - -As we have seen earlier (*note Generate an Error Message: Making -Errors.), when the Emacs Lisp interpreter has trouble evaluating an -expression, it provides you with help; in the jargon, this is called -"signaling an error". Usually, the computer stops the program and -shows you a message. - -However, some programs undertake complicated actions. They should not -simply stop on an error. In the `kill-region' function, the most -likely error is that you will try to kill text that is read-only and -cannot be removed. So the `kill-region' function contains code to -handle this circumstance. This code, which makes up the body of the -`kill-region' function, is inside of a `condition-case' special form. - -The template for `condition-case' looks like this: - - (condition-case - VAR - BODYFORM - ERROR-HANDLER...) - -The second argument, BODYFORM, is straightforward. The -`condition-case' special form causes the Lisp interpreter to evaluate -the code in BODYFORM. If no error occurs, the special form returns -the code's value and produces the side-effects, if any. - -In short, the BODYFORM part of a `condition-case' expression -determines what should happen when everything works correctly. - -However, if an error occurs, among its other actions, the function -generating the error signal will define one or more error condition -names. - -An error handler is the third argument to `condition case'. An error -handler has two parts, a CONDITION-NAME and a BODY. If the -CONDITION-NAME part of an error handler matches a condition name -generated by an error, then the BODY part of the error handler is run. - -As you will expect, the CONDITION-NAME part of an error handler may -be either a single condition name or a list of condition names. - -Also, a complete `condition-case' expression may contain more than -one error handler. When an error occurs, the first applicable -handler is run. - -Lastly, the first argument to the `condition-case' expression, the -VAR argument, is sometimes bound to a variable that contains -information about the error. However, if that argument is nil, as is -the case in `kill-region', that information is discarded. - -In brief, in the `kill-region' function, the code `condition-case' -works like this: - - IF NO ERRORS, RUN ONLY THIS CODE - BUT, IF ERRORS, RUN THIS OTHER CODE. - -`delete-and-extract-region' ---------------------------- - -A `condition-case' expression has two parts, a part that is evaluated -in the expectation that all will go well, but which may generate an -error; and a part that is evaluated when there is an error. - -First, let us look at the code in `kill-region' that is run in the -expectation that all goes well. This is the core of the function. -The code looks like this: - - (let ((string (delete-and-extract-region beg end))) - (when string - (if (eq last-command 'kill-region) - (kill-append string (< end beg)) - (kill-new string))) - (setq this-command 'kill-region)) - -It looks complicated because we have the new functions -`delete-and-extract-region', `kill-append', and `kill-new' as well as -the new variables, `last-command' and `this-command'. - -The `delete-and-extract-region' function is straightforward. It is a -built-in function that deletes the text in a region (a side effect) -and also returns that text. This is the function that actually -removes the text. (And if it cannot do that, it signals the error.) - -In this `let' expression, the text that `delete-and-extract-region' -returns is placed in the local variable called `string'. This is the -text that is removed from the buffer. (To be more precise, the -variable is set to point to the address of the extracted text; to say -it is `placed in' the variable is simply a shorthand.) - -If the variable `string' does point to text, that text is added to -the kill ring. The variable will have a `nil' value if no text was -removed. - -The code uses `when' to determine whether the variable `string' -points to text. A `when' statement is simply a programmers' -convenience. A `when' statement is an `if' statement without the -possibility of an else clause. In your mind, you can replace `when' -with `if' and understand what goes on. That is what the Lisp -interpreter does. - -Technically speaking, `when' is a Lisp macro. A Lisp "macro" enables -you to define new control constructs and other language features. It -tells the interpreter how to compute another Lisp expression which -will in turn compute the value. In this case, the `other expression' -is an `if' expression. For more about Lisp macros, see *Note Macros: -(elisp)Macros. The C programming language also provides macros. -These are different, but also useful. We will briefly look at C -macros in *Note Digression into C::. - -If the string has content, then another conditional expression is -executed. This is an `if' with both a then-part and an else-part. - - (if (eq last-command 'kill-region) - (kill-append string (< end beg)) - (kill-new string))) - -The then-part is evaluated if the previous command was another call to -`kill-region'; if not, the else-part is evaluated. - -`last-command' is a variable that comes with Emacs that we have not -seen before. Normally, whenever a function is executed, Emacs sets -the value of `last-command' to the previous command. - -In this segment of the definition, the `if' expression checks whether -the previous command was `kill-region'. If it was, - - (kill-append string (< end beg)) - -concatenates a copy of the newly clipped text to the just previously -clipped text in the kill ring. (If the `(< end beg))' expression is -true, `kill-append' prepends the string to the just previously -clipped text. For a detailed discussion, see *Note The `kill-append' -function: kill-append function.) - -If you then yank back the text, i.e., `paste' it, you get both pieces -of text at once. That way, if you delete two words in a row, and -then yank them back, you get both words, in their proper order, with -one yank. (The `(< end beg))' expression makes sure the order is -correct.) - -On the other hand, if the previous command is not `kill-region', then -the `kill-new' function is called, which adds the text to the kill -ring as the latest item, and sets the `kill-ring-yank-pointer' -variable to point to it. - -Digression into C -================= - -The `zap-to-char' command uses the `delete-and-extract-region' -function, which in turn uses two other functions, -`copy-region-as-kill' and `del_range_1'. The `copy-region-as-kill' -function will be described in a following section; it puts a copy of -the region in the kill ring so it can be yanked back. (*Note -`copy-region-as-kill': copy-region-as-kill.) - -The `delete-and-extract-region' function removes the contents of a -region and you cannot get them back. - -Unlike the other code discussed here, `delete-and-extract-region' is -not written in Emacs Lisp; it is written in C and is one of the -primitives of the GNU Emacs system. Since it is very simple, I will -digress briefly from Lisp and describe it here. - -Like many of the other Emacs primitives, `delete-and-extract-region' -is written as an instance of a C macro, a macro being a template for -code. The complete macro looks like this: - - DEFUN ("delete-and-extract-region", Fdelete_and_extract_region, - Sdelete_and_extract_region, 2, 2, 0, - "Delete the text between START and END and return it.") - (start, end) - Lisp_Object start, end; - { - validate_region (&start, &end); - return del_range_1 (XINT (start), XINT (end), 1, 1); - } - -Without going into the details of the macro writing process, let me -point out that this macro starts with the word `DEFUN'. The word -`DEFUN' was chosen since the code serves the same purpose as `defun' -does in Lisp. The word `DEFUN' is followed by seven parts inside of -parentheses: - - * The first part is the name given to the function in Lisp, - `delete-and-extract-region'. - - * The second part is the name of the function in C, - `Fdelete_and_extract_region'. By convention, it starts with - `F'. Since C does not use hyphens in names, underscores are used - instead. - - * The third part is the name for the C constant structure that - records information on this function for internal use. It is - the name of the function in C but begins with an `S' instead of - an `F'. - - * The fourth and fifth parts specify the minimum and maximum - number of arguments the function can have. This function - demands exactly 2 arguments. - - * The sixth part is nearly like the argument that follows the - `interactive' declaration in a function written in Lisp: a letter - followed, perhaps, by a prompt. The only difference from the - Lisp is when the macro is called with no arguments. Then you - write a `0' (which is a `null string'), as in this macro. - - If you were to specify arguments, you would place them between - quotation marks. The C macro for `goto-char' includes `"NGoto - char: "' in this position to indicate that the function expects - a raw prefix, in this case, a numerical location in a buffer, - and provides a prompt. - - * The seventh part is a documentation string, just like the one - for a function written in Emacs Lisp, except that every newline - must be written explicitly as `\n' followed by a backslash and - carriage return. - - Thus, the first two lines of documentation for `goto-char' are - written like this: - - "Set point to POSITION, a number or marker.\n\ - Beginning of buffer is position (point-min), end is (point-max). - -In a C macro, the formal parameters come next, with a statement of -what kind of object they are, followed by what might be called the -`body' of the macro. For `delete-and-extract-region' the `body' -consists of the following two lines: - - validate_region (&start, &end); - return del_range_1 (XINT (start), XINT (end), 1, 1); - -The first function, `validate_region' checks whether the values -passed as the beginning and end of the region are the proper type and -are within range. The second function, `del_range_1', actually -deletes the text. - -`del_range_1' is a complex function we will not look into. It -updates the buffer and does other things. - -However, it is worth looking at the two arguments passed to -`del_range'. These are `XINT (start)' and `XINT (end)'. - -As far as the C language is concerned, `start' and `end' are two -integers that mark the beginning and end of the region to be -deleted(1). - -In early versions of Emacs, these two numbers were thirty-two bits -long, but the code is slowly being generalized to handle other -lengths. Three of the available bits are used to specify the type of -information and a fourth bit is used for handling the computer's -memory; the remaining bits are used as `content'. - -`XINT' is a C macro that extracts the relevant number from the longer -collection of bits; the four other bits are discarded. - -The command in `delete-and-extract-region' looks like this: - - del_range_1 (XINT (start), XINT (end), 1, 1); - -It deletes the region between the beginning position, `start', and -the ending position, `end'. - -From the point of view of the person writing Lisp, Emacs is all very -simple; but hidden underneath is a great deal of complexity to make it -all work. - ----------- Footnotes ---------- - -(1) More precisely, and requiring more expert knowledge to -understand, the two integers are of type `Lisp_Object', which can -also be a C union instead of an integer type. - -Initializing a Variable with `defvar' -===================================== - -Unlike the `delete-and-extract-region' function, the -`copy-region-as-kill' function is written in Emacs Lisp. Two -functions within it, `kill-append' and `kill-new', copy a region in a -buffer and save it in a variable called the `kill-ring'. This -section describes how the `kill-ring' variable is created and -initialized using the `defvar' special form. - -(Again we note that the term `kill-ring' is a misnomer. The text -that is clipped out of the buffer can be brought back; it is not a -ring of corpses, but a ring of resurrectable text.) - -In Emacs Lisp, a variable such as the `kill-ring' is created and -given an initial value by using the `defvar' special form. The name -comes from "define variable". - -The `defvar' special form is similar to `setq' in that it sets the -value of a variable. It is unlike `setq' in two ways: first, it only -sets the value of the variable if the variable does not already have -a value. If the variable already has a value, `defvar' does not -override the existing value. Second, `defvar' has a documentation -string. - -(Another special form, `defcustom', is designed for variables that -people customize. It has more features than `defvar'. (*Note -Setting Variables with `defcustom': defcustom.) - -Seeing the Current Value of a Variable --------------------------------------- - -You can see the current value of a variable, any variable, by using -the `describe-variable' function, which is usually invoked by typing -`C-h v'. If you type `C-h v' and then `kill-ring' (followed by -<RET>) when prompted, you will see what is in your current kill -ring--this may be quite a lot! Conversely, if you have been doing -nothing this Emacs session except read this document, you may have -nothing in it. Also, you will see the documentation for `kill-ring': - - Documentation: - List of killed text sequences. - Since the kill ring is supposed to interact nicely with cut-and-paste - facilities offered by window systems, use of this variable should - interact nicely with `interprogram-cut-function' and - `interprogram-paste-function'. The functions `kill-new', - `kill-append', and `current-kill' are supposed to implement this - interaction; you may want to use them instead of manipulating the kill - ring directly. - -The kill ring is defined by a `defvar' in the following way: - - (defvar kill-ring nil - "List of killed text sequences. - ...") - -In this variable definition, the variable is given an initial value of -`nil', which makes sense, since if you have saved nothing, you want -nothing back if you give a `yank' command. The documentation string -is written just like the documentation string of a `defun'. As with -the documentation string of the `defun', the first line of the -documentation should be a complete sentence, since some commands, -like `apropos', print only the first line of documentation. -Succeeding lines should not be indented; otherwise they look odd when -you use `C-h v' (`describe-variable'). - -`defvar' and an asterisk ------------------------- - -In the past, Emacs used the `defvar' special form both for internal -variables that you would not expect a user to change and for -variables that you do expect a user to change. Although you can still -use `defvar' for user customizable variables, please use `defcustom' -instead, since that special form provides a path into the -Customization commands. (*Note Setting Variables with `defcustom': -defcustom.) - -When you specified a variable using the `defvar' special form, you -could distinguish a readily settable variable from others by typing -an asterisk, `*', in the first column of its documentation string. -For example: - - (defvar shell-command-default-error-buffer nil - "*Buffer name for `shell-command' ... error output. - ... ") - -This means that you could (and still can) use the `edit-options' -command to change the value of `shell-command-default-error-buffer' -temporarily. - -However, options set using `edit-options' are set only for the -duration of your editing session. The new values are not saved -between sessions. Each time Emacs starts, it reads the original -value, unless you change the value within your `.emacs' file, either -by setting it manually or by using `customize'. *Note Your `.emacs' -File: Emacs Initialization. - -For me, the major use of the `edit-options' command is to suggest -variables that I might want to set in my `.emacs' file. I urge you -to look through the list. (*Note Editing Variable Values: -(emacs)Edit Options.) - -`copy-region-as-kill' -===================== - -The `copy-region-as-kill' function copies a region of text from a -buffer and (via either `kill-append' or `kill-new') saves it in the -`kill-ring'. - -If you call `copy-region-as-kill' immediately after a `kill-region' -command, Emacs appends the newly copied text to the previously copied -text. This means that if you yank back the text, you get it all, -from both this and the previous operation. On the other hand, if -some other command precedes the `copy-region-as-kill', the function -copies the text into a separate entry in the kill ring. - -The complete `copy-region-as-kill' function definition ------------------------------------------------------- - -Here is the complete text of the version 21 `copy-region-as-kill' -function: - - (defun copy-region-as-kill (beg end) - "Save the region as if killed, but don't kill it. - In Transient Mark mode, deactivate the mark. - If `interprogram-cut-function' is non-nil, also save - the text for a window system cut and paste." - (interactive "r") - (if (eq last-command 'kill-region) - (kill-append (buffer-substring beg end) (< end beg)) - (kill-new (buffer-substring beg end))) - (if transient-mark-mode - (setq deactivate-mark t)) - nil) - -As usual, this function can be divided into its component parts: - - (defun copy-region-as-kill (ARGUMENT-LIST) - "DOCUMENTATION..." - (interactive "r") - BODY...) - -The arguments are `beg' and `end' and the function is interactive -with `"r"', so the two arguments must refer to the beginning and end -of the region. If you have been reading though this document from -the beginning, understanding these parts of a function is almost -becoming routine. - -The documentation is somewhat confusing unless you remember that the -word `kill' has a meaning different from its usual meaning. The -`Transient Mark' and `interprogram-cut-function' comments explain -certain side-effects. - -After you once set a mark, a buffer always contains a region. If you -wish, you can use Transient Mark mode to highlight the region -temporarily. (No one wants to highlight the region all the time, so -Transient Mark mode highlights it only at appropriate times. Many -people turn off Transient Mark mode, so the region is never -highlighted.) - -Also, a windowing system allows you to copy, cut, and paste among -different programs. In the X windowing system, for example, the -`interprogram-cut-function' function is `x-select-text', which works -with the windowing system's equivalent of the Emacs kill ring. - -The body of the `copy-region-as-kill' function starts with an `if' -clause. What this clause does is distinguish between two different -situations: whether or not this command is executed immediately after -a previous `kill-region' command. In the first case, the new region -is appended to the previously copied text. Otherwise, it is inserted -into the beginning of the kill ring as a separate piece of text from -the previous piece. - -The last two lines of the function prevent the region from lighting up -if Transient Mark mode is turned on. - -The body of `copy-region-as-kill' merits discussion in detail. - -The Body of `copy-region-as-kill' ---------------------------------- - -The `copy-region-as-kill' function works in much the same way as the -`kill-region' function (*note `kill-region': kill-region.). Both are -written so that two or more kills in a row combine their text into a -single entry. If you yank back the text from the kill ring, you get -it all in one piece. Moreover, kills that kill forward from the -current position of the cursor are added to the end of the previously -copied text and commands that copy text backwards add it to the -beginning of the previously copied text. This way, the words in the -text stay in the proper order. - -Like `kill-region', the `copy-region-as-kill' function makes use of -the `last-command' variable that keeps track of the previous Emacs -command. - -`last-command' and `this-command' -................................. - -Normally, whenever a function is executed, Emacs sets the value of -`this-command' to the function being executed (which in this case -would be `copy-region-as-kill'). At the same time, Emacs sets the -value of `last-command' to the previous value of `this-command'. - -In the first part of the body of the `copy-region-as-kill' function, -an `if' expression determines whether the value of `last-command' is -`kill-region'. If so, the then-part of the `if' expression is -evaluated; it uses the `kill-append' function to concatenate the text -copied at this call to the function with the text already in the -first element (the CAR) of the kill ring. On the other hand, if the -value of `last-command' is not `kill-region', then the -`copy-region-as-kill' function attaches a new element to the kill -ring using the `kill-new' function. - -The `if' expression reads as follows; it uses `eq', which is a -function we have not yet seen: - - (if (eq last-command 'kill-region) - ;; then-part - (kill-append (buffer-substring beg end) (< end beg)) - ;; else-part - (kill-new (buffer-substring beg end))) - -The `eq' function tests whether its first argument is the same Lisp -object as its second argument. The `eq' function is similar to the -`equal' function in that it is used to test for equality, but differs -in that it determines whether two representations are actually the -same object inside the computer, but with different names. `equal' -determines whether the structure and contents of two expressions are -the same. - -If the previous command was `kill-region', then the Emacs Lisp -interpreter calls the `kill-append' function - -The `kill-append' function -.......................... - -The `kill-append' function looks like this: - - (defun kill-append (string before-p) - "Append STRING to the end of the latest kill in the kill ring. - If BEFORE-P is non-nil, prepend STRING to the kill. - If `interprogram-cut-function' is set, pass the resulting kill to - it." - (kill-new (if before-p - (concat string (car kill-ring)) - (concat (car kill-ring) string)) - t)) - -The `kill-append' function is fairly straightforward. It uses the -`kill-new' function, which we will discuss in more detail in a moment. - -First, let us look at the conditional that is one of the two arguments -to `kill-new'. It uses `concat' to concatenate the new text to the -CAR of the kill ring. Whether it prepends or appends the text -depends on the results of an `if' expression: - - (if before-p ; if-part - (concat string (car kill-ring)) ; then-part - (concat (car kill-ring) string)) ; else-part - -If the region being killed is before the region that was killed in the -last command, then it should be prepended before the material that was -saved in the previous kill; and conversely, if the killed text follows -what was just killed, it should be appended after the previous text. -The `if' expression depends on the predicate `before-p' to decide -whether the newly saved text should be put before or after the -previously saved text. - -The symbol `before-p' is the name of one of the arguments to -`kill-append'. When the `kill-append' function is evaluated, it is -bound to the value returned by evaluating the actual argument. In -this case, this is the expression `(< end beg)'. This expression -does not directly determine whether the killed text in this command -is located before or after the kill text of the last command; what is -does is determine whether the value of the variable `end' is less -than the value of the variable `beg'. If it is, it means that the -user is most likely heading towards the beginning of the buffer. -Also, the result of evaluating the predicate expression, `(< end -beg)', will be true and the text will be prepended before the -previous text. On the other hand, if the value of the variable `end' -is greater than the value of the variable `beg', the text will be -appended after the previous text. - -When the newly saved text will be prepended, then the string with the -new text will be concatenated before the old text: - - (concat string (car kill-ring)) - -But if the text will be appended, it will be concatenated after the -old text: - - (concat (car kill-ring) string)) - -To understand how this works, we first need to review the `concat' -function. The `concat' function links together or unites two strings -of text. The result is a string. For example: - - (concat "abc" "def") - => "abcdef" - - (concat "new " - (car '("first element" "second element"))) - => "new first element" - - (concat (car - '("first element" "second element")) " modified") - => "first element modified" - -We can now make sense of `kill-append': it modifies the contents of -the kill ring. The kill ring is a list, each element of which is -saved text. The `kill-append' function uses the `kill-new' function -which in turn uses the `setcar' function. - -The `kill-new' function -....................... - -The `kill-new' function looks like this: - - (defun kill-new (string &optional replace) - "Make STRING the latest kill in the kill ring. - Set the kill-ring-yank pointer to point to it. - If `interprogram-cut-function' is non-nil, apply it to STRING. - Optional second argument REPLACE non-nil means that STRING will replace - the front of the kill ring, rather than being added to the list." - (and (fboundp 'menu-bar-update-yank-menu) - (menu-bar-update-yank-menu string (and replace (car kill-ring)))) - (if (and replace kill-ring) - (setcar kill-ring string) - (setq kill-ring (cons string kill-ring)) - (if (> (length kill-ring) kill-ring-max) - (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))) - (setq kill-ring-yank-pointer kill-ring) - (if interprogram-cut-function - (funcall interprogram-cut-function string (not replace)))) - -As usual, we can look at this function in parts. - -The first line of the documentation makes sense: - - Make STRING the latest kill in the kill ring. - -Let's skip over the rest of the documentation for the moment. - -Also, let's skip over the first two lines of code, those involving -`menu-bar-update-yank-menu'. We will explain them below. - -The critical lines are these: - - (if (and replace kill-ring) - ;; then - (setcar kill-ring string) - ;; else - (setq kill-ring (cons string kill-ring)) - (if (> (length kill-ring) kill-ring-max) - ;; avoid overly long kill ring - (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))) - (setq kill-ring-yank-pointer kill-ring) - (if interprogram-cut-function - (funcall interprogram-cut-function string (not replace)))) - -The conditional test is `(and replace kill-ring)'. This will be true -when two conditions are met: the kill ring has something in it, and -the `replace' variable is true. - -The `kill-append' function sets `replace' to be true; then, when the -kill ring has at least one item in it, the `setcar' expression is -executed: - - (setcar kill-ring string) - -The `setcar' function actually changes the first element of the -`kill-ring' list to the value of `string'. It replaces the first -element. - -On the other hand, if the kill ring is empty, or replace is false, the -else-part of the condition is executed: - - (setq kill-ring (cons string kill-ring)) - (if (> (length kill-ring) kill-ring-max) - (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)) - -This expression first constructs a new version of the kill ring by -prepending `string' to the existing kill ring as a new element. Then -it executes a second `if' clause. This second `if' clause keeps the -kill ring from growing too long. - -Let's look at these two expressions in order. - -The `setq' line of the else-part sets the new value of the kill ring -to what results from adding the string being killed to the old kill -ring. - -We can see how this works with an example: - - (setq example-list '("here is a clause" "another clause")) - -After evaluating this expression with `C-x C-e', you can evaluate -`example-list' and see what it returns: - - example-list - => ("here is a clause" "another clause") - -Now, we can add a new element on to this list by evaluating the -following expression: - - (setq example-list (cons "a third clause" example-list)) - -When we evaluate `example-list', we find its value is: - - example-list - => ("a third clause" "here is a clause" "another clause") - -Thus, the third clause was added to the list by `cons'. - -This is exactly similar to what the `setq' and `cons' do in the -function. Here is the line again: - - (setq kill-ring (cons string kill-ring)) - -Now for the second part of the `if' clause. This expression keeps -the kill ring from growing too long. It looks like this: - - (if (> (length kill-ring) kill-ring-max) - (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)) - -The code checks whether the length of the kill ring is greater than -the maximum permitted length. This is the value of `kill-ring-max' -(which is 60, by default). If the length of the kill ring is too -long, then this code sets the last element of the kill ring to `nil'. -It does this by using two functions, `nthcdr' and `setcdr'. - -We looked at `setcdr' earlier (*note `setcdr': setcdr.). It sets the -CDR of a list, just as `setcar' sets the CAR of a list. In this -case, however, `setcdr' will not be setting the CDR of the whole kill -ring; the `nthcdr' function is used to cause it to set the CDR of the -next to last element of the kill ring--this means that since the CDR -of the next to last element is the last element of the kill ring, it -will set the last element of the kill ring. - -The `nthcdr' function works by repeatedly taking the CDR of a -list--it takes the CDR of the CDR of the CDR ... It does this N -times and returns the results. - -Thus, if we had a four element list that was supposed to be three -elements long, we could set the CDR of the next to last element to -`nil', and thereby shorten the list. - -You can see this by evaluating the following three expressions in -turn. First set the value of `trees' to `(maple oak pine birch)', -then set the CDR of its second CDR to `nil' and then find the value -of `trees': - - (setq trees '(maple oak pine birch)) - => (maple oak pine birch) - - (setcdr (nthcdr 2 trees) nil) - => nil - - trees - => (maple oak pine) - -(The value returned by the `setcdr' expression is `nil' since that is -what the CDR is set to.) - -To repeat, in `kill-new', the `nthcdr' function takes the CDR a -number of times that is one less than the maximum permitted size of -the kill ring and sets the CDR of that element (which will be the -rest of the elements in the kill ring) to `nil'. This prevents the -kill ring from growing too long. - -The next to last expression in the `kill-new' function is - - (setq kill-ring-yank-pointer kill-ring) - -The `kill-ring-yank-pointer' is a global variable that is set to be -the `kill-ring'. - -Even though the `kill-ring-yank-pointer' is called a `pointer', it is -a variable just like the kill ring. However, the name has been -chosen to help humans understand how the variable is used. The -variable is used in functions such as `yank' and `yank-pop' (*note -Yanking Text Back: Yanking.). - -Now, to return to the first two lines in the body of the function: - - (and (fboundp 'menu-bar-update-yank-menu) - (menu-bar-update-yank-menu string (and replace (car kill-ring)))) - -This is an expression whose first element is the function `and'. - -The `and' special form evaluates each of its arguments until one of -the arguments returns a value of `nil', in which case the `and' -expression returns `nil'; however, if none of the arguments returns a -value of `nil', the value resulting from evaluating the last argument -is returned. (Since such a value is not `nil', it is considered true -in Emacs Lisp.) In other words, an `and' expression returns a true -value only if all its arguments are true. - -In this case, the expression tests first to see whether -`menu-bar-update-yank-menu' exists as a function, and if so, calls -it. The `fboundp' function returns true if the symbol it is testing -has a function definition that `is not void'. If the symbol's -function definition were void, we would receive an error message, as -we did when we created errors intentionally (*note Generate an Error -Message: Making Errors.). - -Essentially, the `and' is an `if' expression that reads like this: - - if THE-MENU-BAR-FUNCTION-EXISTS - then EXECUTE-IT - -`menu-bar-update-yank-menu' is one of the functions that make it -possible to use the `Select and Paste' menu in the Edit item of a menu -bar; using a mouse, you can look at the various pieces of text you -have saved and select one piece to paste. - -Finally, the last expression in the `kill-new' function adds the -newly copied string to whatever facility exists for copying and -pasting among different programs running in a windowing system. In -the X Windowing system, for example, the `x-select-text' function -takes the string and stores it in memory operated by X. You can paste -the string in another program, such as an Xterm. - -The expression looks like this: - - (if interprogram-cut-function - (funcall interprogram-cut-function string (not replace)))) - -If an `interprogram-cut-function' exists, then Emacs executes -`funcall', which in turn calls its first argument as a function and -passes the remaining arguments to it. (Incidentally, as far as I can -see, this `if' expression could be replaced by an `and' expression -similar to the one in the first part of the function.) - -We are not going to discuss windowing systems and other programs -further, but merely note that this is a mechanism that enables GNU -Emacs to work easily and well with other programs. - -This code for placing text in the kill ring, either concatenated with -an existing element or as a new element, leads us to the code for -bringing back text that has been cut out of the buffer--the yank -commands. However, before discussing the yank commands, it is better -to learn how lists are implemented in a computer. This will make -clear such mysteries as the use of the term `pointer'. - -Review -====== - -Here is a brief summary of some recently introduced functions. - -`car' -`cdr' - `car' returns the first element of a list; `cdr' returns the - second and subsequent elements of a list. - - For example: - - (car '(1 2 3 4 5 6 7)) - => 1 - (cdr '(1 2 3 4 5 6 7)) - => (2 3 4 5 6 7) - -`cons' - `cons' constructs a list by prepending its first argument to its - second argument. - - For example: - - (cons 1 '(2 3 4)) - => (1 2 3 4) - -`nthcdr' - Return the result of taking CDR `n' times on a list. The `rest - of the rest', as it were. - - For example: - - (nthcdr 3 '(1 2 3 4 5 6 7)) - => (4 5 6 7) - -`setcar' -`setcdr' - `setcar' changes the first element of a list; `setcdr' changes - the second and subsequent elements of a list. - - For example: - - (setq triple '(1 2 3)) - - (setcar triple '37) - - triple - => (37 2 3) - - (setcdr triple '("foo" "bar")) - - triple - => (37 "foo" "bar") - -`progn' - Evaluate each argument in sequence and then return the value of - the last. - - For example: - - (progn 1 2 3 4) - => 4 - -`save-restriction' - Record whatever narrowing is in effect in the current buffer, if - any, and restore that narrowing after evaluating the arguments. - -`search-forward' - Search for a string, and if the string is found, move point. - - Takes four arguments: - - 1. The string to search for. - - 2. Optionally, the limit of the search. - - 3. Optionally, what to do if the search fails, return `nil' or - an error message. - - 4. Optionally, how many times to repeat the search; if - negative, the search goes backwards. - -`kill-region' -`delete-region' -`copy-region-as-kill' - `kill-region' cuts the text between point and mark from the - buffer and stores that text in the kill ring, so you can get it - back by yanking. - - `delete-and-extract-region' removes the text between point and - mark from the buffer and throws it away. You cannot get it back. - - `copy-region-as-kill' copies the text between point and mark into - the kill ring, from which you can get it by yanking. The - function does not cut or remove the text from the buffer. - -Searching Exercises -=================== - - * Write an interactive function that searches for a string. If the - search finds the string, leave point after it and display a - message that says "Found!". (Do not use `search-forward' for - the name of this function; if you do, you will overwrite the - existing version of `search-forward' that comes with Emacs. Use - a name such as `test-search' instead.) - - * Write a function that prints the third element of the kill ring - in the echo area, if any; if the kill ring does not contain a - third element, print an appropriate message. - -How Lists are Implemented -************************* - -In Lisp, atoms are recorded in a straightforward fashion; if the -implementation is not straightforward in practice, it is, nonetheless, -straightforward in theory. The atom `rose', for example, is recorded -as the four contiguous letters `r', `o', `s', `e'. A list, on the -other hand, is kept differently. The mechanism is equally simple, -but it takes a moment to get used to the idea. A list is kept using -a series of pairs of pointers. In the series, the first pointer in -each pair points to an atom or to another list, and the second -pointer in each pair points to the next pair, or to the symbol `nil', -which marks the end of the list. - -A pointer itself is quite simply the electronic address of what is -pointed to. Hence, a list is kept as a series of electronic -addresses. - -Lists diagrammed -================ - -For example, the list `(rose violet buttercup)' has three elements, -`rose', `violet', and `buttercup'. In the computer, the electronic -address of `rose' is recorded in a segment of computer memory along -with the address that gives the electronic address of where the atom -`violet' is located; and that address (the one that tells where -`violet' is located) is kept along with an address that tells where -the address for the atom `buttercup' is located. - -This sounds more complicated than it is and is easier seen in a -diagram: - - ___ ___ ___ ___ ___ ___ - |___|___|--> |___|___|--> |___|___|--> nil - | | | - | | | - --> rose --> violet --> buttercup - - - -In the diagram, each box represents a word of computer memory that -holds a Lisp object, usually in the form of a memory address. The -boxes, i.e. the addresses, are in pairs. Each arrow points to what -the address is the address of, either an atom or another pair of -addresses. The first box is the electronic address of `rose' and the -arrow points to `rose'; the second box is the address of the next -pair of boxes, the first part of which is the address of `violet' and -the second part of which is the address of the next pair. The very -last box points to the symbol `nil', which marks the end of the list. - -When a variable is set to a list with a function such as `setq', it -stores the address of the first box in the variable. Thus, -evaluation of the expression - - (setq bouquet '(rose violet buttercup)) - -creates a situation like this: - - bouquet - | - | ___ ___ ___ ___ ___ ___ - --> |___|___|--> |___|___|--> |___|___|--> nil - | | | - | | | - --> rose --> violet --> buttercup - - - -In this example, the symbol `bouquet' holds the address of the first -pair of boxes. - -This same list can be illustrated in a different sort of box notation -like this: - - bouquet - | - | -------------- --------------- ---------------- - | | car | cdr | | car | cdr | | car | cdr | - -->| rose | o------->| violet | o------->| butter- | nil | - | | | | | | | cup | | - -------------- --------------- ---------------- - - - -(Symbols consist of more than pairs of addresses, but the structure of -a symbol is made up of addresses. Indeed, the symbol `bouquet' -consists of a group of address-boxes, one of which is the address of -the printed word `bouquet', a second of which is the address of a -function definition attached to the symbol, if any, a third of which -is the address of the first pair of address-boxes for the list `(rose -violet buttercup)', and so on. Here we are showing that the symbol's -third address-box points to the first pair of address-boxes for the -list.) - -If a symbol is set to the CDR of a list, the list itself is not -changed; the symbol simply has an address further down the list. (In -the jargon, CAR and CDR are `non-destructive'.) Thus, evaluation of -the following expression - - (setq flowers (cdr bouquet)) - -produces this: - - - bouquet flowers - | | - | ___ ___ | ___ ___ ___ ___ - --> | | | --> | | | | | | - |___|___|----> |___|___|--> |___|___|--> nil - | | | - | | | - --> rose --> violet --> buttercup - - - - -The value of `flowers' is `(violet buttercup)', which is to say, the -symbol `flowers' holds the address of the pair of address-boxes, the -first of which holds the address of `violet', and the second of which -holds the address of `buttercup'. - -A pair of address-boxes is called a "cons cell" or "dotted pair". -*Note List Type: (elisp)List Type, and *Note Dotted Pair Notation: -(elisp)Dotted Pair Notation, for more information about cons cells -and dotted pairs. - -The function `cons' adds a new pair of addresses to the front of a -series of addresses like that shown above. For example, evaluating -the expression - - (setq bouquet (cons 'lily bouquet)) - -produces: - - - bouquet flowers - | | - | ___ ___ ___ ___ | ___ ___ ___ ___ - --> | | | | | | --> | | | | | | - |___|___|----> |___|___|----> |___|___|---->|___|___|--> nil - | | | | - | | | | - --> lily --> rose --> violet --> buttercup - - - - -However, this does not change the value of the symbol `flowers', as -you can see by evaluating the following, - - (eq (cdr (cdr bouquet)) flowers) - -which returns `t' for true. - -Until it is reset, `flowers' still has the value `(violet -buttercup)'; that is, it has the address of the cons cell whose first -address is of `violet'. Also, this does not alter any of the -pre-existing cons cells; they are all still there. - -Thus, in Lisp, to get the CDR of a list, you just get the address of -the next cons cell in the series; to get the CAR of a list, you get -the address of the first element of the list; to `cons' a new element -on a list, you add a new cons cell to the front of the list. That is -all there is to it! The underlying structure of Lisp is brilliantly -simple! - -And what does the last address in a series of cons cells refer to? It -is the address of the empty list, of `nil'. - -In summary, when a Lisp variable is set to a value, it is provided -with the address of the list to which the variable refers. - -Symbols as a Chest of Drawers -============================= - -In an earlier section, I suggested that you might imagine a symbol as -being a chest of drawers. The function definition is put in one -drawer, the value in another, and so on. What is put in the drawer -holding the value can be changed without affecting the contents of the -drawer holding the function definition, and vice-versa. - -Actually, what is put in each drawer is the address of the value or -function definition. It is as if you found an old chest in the attic, -and in one of its drawers you found a map giving you directions to -where the buried treasure lies. - -(In addition to its name, symbol definition, and variable value, a -symbol has a `drawer' for a "property list" which can be used to -record other information. Property lists are not discussed here; see -*Note Property Lists: (elisp)Property Lists.) - -Here is a fanciful representation: - - - Chest of Drawers Contents of Drawers - - __ o0O0o __ - / \ - --------------------- - | directions to | [map to] - | symbol name | bouquet - | | - +---------------------+ - | directions to | - | symbol definition | [none] - | | - +---------------------+ - | directions to | [map to] - | variable value | (rose violet buttercup) - | | - +---------------------+ - | directions to | - | property list | [not described here] - | | - +---------------------+ - |/ \| - - - - -Exercise -======== - -Set `flowers' to `violet' and `buttercup'. Cons two more flowers on -to this list and set this new list to `more-flowers'. Set the CAR of -`flowers' to a fish. What does the `more-flowers' list now contain? - -Yanking Text Back -***************** - -Whenever you cut text out of a buffer with a `kill' command in GNU -Emacs, you can bring it back with a `yank' command. The text that is -cut out of the buffer is put in the kill ring and the yank commands -insert the appropriate contents of the kill ring back into a buffer -(not necessarily the original buffer). - -A simple `C-y' (`yank') command inserts the first item from the kill -ring into the current buffer. If the `C-y' command is followed -immediately by `M-y', the first element is replaced by the second -element. Successive `M-y' commands replace the second element with -the third, fourth, or fifth element, and so on. When the last -element in the kill ring is reached, it is replaced by the first -element and the cycle is repeated. (Thus the kill ring is called a -`ring' rather than just a `list'. However, the actual data structure -that holds the text is a list. *Note Handling the Kill Ring: Kill -Ring, for the details of how the list is handled as a ring.) - -Kill Ring Overview -================== - -The kill ring is a list of textual strings. This is what it looks -like: - - ("some text" "a different piece of text" "yet more text") - -If this were the contents of my kill ring and I pressed `C-y', the -string of characters saying `some text' would be inserted in this -buffer where my cursor is located. - -The `yank' command is also used for duplicating text by copying it. -The copied text is not cut from the buffer, but a copy of it is put -on the kill ring and is inserted by yanking it back. - -Three functions are used for bringing text back from the kill ring: -`yank', which is usually bound to `C-y'; `yank-pop', which is usually -bound to `M-y'; and `rotate-yank-pointer', which is used by the two -other functions. - -These functions refer to the kill ring through a variable called the -`kill-ring-yank-pointer'. Indeed, the insertion code for both the -`yank' and `yank-pop' functions is: - - (insert (car kill-ring-yank-pointer)) - -To begin to understand how `yank' and `yank-pop' work, it is first -necessary to look at the `kill-ring-yank-pointer' variable and the -`rotate-yank-pointer' function. - -The `kill-ring-yank-pointer' Variable -===================================== - -`kill-ring-yank-pointer' is a variable, just as `kill-ring' is a -variable. It points to something by being bound to the value of what -it points to, like any other Lisp variable. - -Thus, if the value of the kill ring is: - - ("some text" "a different piece of text" "yet more text") - -and the `kill-ring-yank-pointer' points to the second clause, the -value of `kill-ring-yank-pointer' is: - - ("a different piece of text" "yet more text") - -As explained in the previous chapter (*note List Implementation::), -the computer does not keep two different copies of the text being -pointed to by both the `kill-ring' and the `kill-ring-yank-pointer'. -The words "a different piece of text" and "yet more text" are not -duplicated. Instead, the two Lisp variables point to the same pieces -of text. Here is a diagram: - - kill-ring kill-ring-yank-pointer - | | - | ___ ___ | ___ ___ ___ ___ - ---> | | | --> | | | | | | - |___|___|----> |___|___|--> |___|___|--> nil - | | | - | | | - | | --> "yet more text" - | | - | --> "a different piece of text - | - --> "some text" - - - - -Both the variable `kill-ring' and the variable -`kill-ring-yank-pointer' are pointers. But the kill ring itself is -usually described as if it were actually what it is composed of. The -`kill-ring' is spoken of as if it were the list rather than that it -points to the list. Conversely, the `kill-ring-yank-pointer' is -spoken of as pointing to a list. - -These two ways of talking about the same thing sound confusing at -first but make sense on reflection. The kill ring is generally -thought of as the complete structure of data that holds the -information of what has recently been cut out of the Emacs buffers. -The `kill-ring-yank-pointer' on the other hand, serves to -indicate--that is, to `point to'--that part of the kill ring of which -the first element (the CAR) will be inserted. - -The `rotate-yank-pointer' function changes the element in the kill -ring to which the `kill-ring-yank-pointer' points; when the pointer -is set to point to the next element beyond the end of the kill ring, -it automatically sets it to point to the first element of the kill -ring. This is how the list is transformed into a ring. The -`rotate-yank-pointer' function itself is not difficult, but contains -many details. It and the much simpler `yank' and `yank-pop' -functions are described in an appendix. *Note Handling the Kill -Ring: Kill Ring. - -Exercises with `yank' and `nthcdr' -================================== - - * Using `C-h v' (`describe-variable'), look at the value of your - kill ring. Add several items to your kill ring; look at its - value again. Using `M-y' (`yank-pop)', move all the way around - the kill ring. How many items were in your kill ring? Find the - value of `kill-ring-max'. Was your kill ring full, or could you - have kept more blocks of text within it? - - * Using `nthcdr' and `car', construct a series of expressions to - return the first, second, third, and fourth elements of a list. - -Loops and Recursion -******************* - -Emacs Lisp has two primary ways to cause an expression, or a series of -expressions, to be evaluated repeatedly: one uses a `while' loop, and -the other uses "recursion". - -Repetition can be very valuable. For example, to move forward four -sentences, you need only write a program that will move forward one -sentence and then repeat the process four times. Since a computer -does not get bored or tired, such repetitive action does not have the -deleterious effects that excessive or the wrong kinds of repetition -can have on humans. - -People mostly write Emacs Lisp functions using `while' loops and -their kin; but you can use recursion, which provides a very powerful -way to think about and then to solve problems(1). - ----------- Footnotes ---------- - -(1) You can write recursive functions to be frugal or wasteful of -mental or computer resources; as it happens, methods that people find -easy--that are frugal of `mental resources'--sometimes use -considerable computer resources. Emacs was designed to run on -machines that we now consider limited and its default settings are -conservative. You may want to increase the values of -`max-specpdl-size' and `max-lisp-eval-depth'. In my `.emacs' file, I -set them to 15 and 30 times their default value. - -`while' -======= - -The `while' special form tests whether the value returned by -evaluating its first argument is true or false. This is similar to -what the Lisp interpreter does with an `if'; what the interpreter does -next, however, is different. - -In a `while' expression, if the value returned by evaluating the -first argument is false, the Lisp interpreter skips the rest of the -expression (the "body" of the expression) and does not evaluate it. -However, if the value is true, the Lisp interpreter evaluates the body -of the expression and then again tests whether the first argument to -`while' is true or false. If the value returned by evaluating the -first argument is again true, the Lisp interpreter again evaluates the -body of the expression. - -The template for a `while' expression looks like this: - - (while TRUE-OR-FALSE-TEST - BODY...) - -Looping with `while' --------------------- - -So long as the true-or-false-test of the `while' expression returns a -true value when it is evaluated, the body is repeatedly evaluated. -This process is called a loop since the Lisp interpreter repeats the -same thing again and again, like an airplane doing a loop. When the -result of evaluating the true-or-false-test is false, the Lisp -interpreter does not evaluate the rest of the `while' expression and -`exits the loop'. - -Clearly, if the value returned by evaluating the first argument to -`while' is always true, the body following will be evaluated again -and again ... and again ... forever. Conversely, if the value -returned is never true, the expressions in the body will never be -evaluated. The craft of writing a `while' loop consists of choosing -a mechanism such that the true-or-false-test returns true just the -number of times that you want the subsequent expressions to be -evaluated, and then have the test return false. - -The value returned by evaluating a `while' is the value of the -true-or-false-test. An interesting consequence of this is that a -`while' loop that evaluates without error will return `nil' or false -regardless of whether it has looped 1 or 100 times or none at all. A -`while' expression that evaluates successfully never returns a true -value! What this means is that `while' is always evaluated for its -side effects, which is to say, the consequences of evaluating the -expressions within the body of the `while' loop. This makes sense. -It is not the mere act of looping that is desired, but the -consequences of what happens when the expressions in the loop are -repeatedly evaluated. - -A `while' Loop and a List -------------------------- - -A common way to control a `while' loop is to test whether a list has -any elements. If it does, the loop is repeated; but if it does not, -the repetition is ended. Since this is an important technique, we -will create a short example to illustrate it. - -A simple way to test whether a list has elements is to evaluate the -list: if it has no elements, it is an empty list and will return the -empty list, `()', which is a synonym for `nil' or false. On the -other hand, a list with elements will return those elements when it -is evaluated. Since Emacs Lisp considers as true any value that is -not `nil', a list that returns elements will test true in a `while' -loop. - -For example, you can set the variable `empty-list' to `nil' by -evaluating the following `setq' expression: - - (setq empty-list ()) - -After evaluating the `setq' expression, you can evaluate the variable -`empty-list' in the usual way, by placing the cursor after the symbol -and typing `C-x C-e'; `nil' will appear in your echo area: - - empty-list - -On the other hand, if you set a variable to be a list with elements, -the list will appear when you evaluate the variable, as you can see by -evaluating the following two expressions: - - (setq animals '(gazelle giraffe lion tiger)) - - animals - -Thus, to create a `while' loop that tests whether there are any items -in the list `animals', the first part of the loop will be written -like this: - - (while animals - ... - -When the `while' tests its first argument, the variable `animals' is -evaluated. It returns a list. So long as the list has elements, the -`while' considers the results of the test to be true; but when the -list is empty, it considers the results of the test to be false. - -To prevent the `while' loop from running forever, some mechanism -needs to be provided to empty the list eventually. An oft-used -technique is to have one of the subsequent forms in the `while' -expression set the value of the list to be the CDR of the list. Each -time the `cdr' function is evaluated, the list will be made shorter, -until eventually only the empty list will be left. At this point, -the test of the `while' loop will return false, and the arguments to -the `while' will no longer be evaluated. - -For example, the list of animals bound to the variable `animals' can -be set to be the CDR of the original list with the following -expression: - - (setq animals (cdr animals)) - -If you have evaluated the previous expressions and then evaluate this -expression, you will see `(giraffe lion tiger)' appear in the echo -area. If you evaluate the expression again, `(lion tiger)' will -appear in the echo area. If you evaluate it again and yet again, -`(tiger)' appears and then the empty list, shown by `nil'. - -A template for a `while' loop that uses the `cdr' function repeatedly -to cause the true-or-false-test eventually to test false looks like -this: - - (while TEST-WHETHER-LIST-IS-EMPTY - BODY... - SET-LIST-TO-CDR-OF-LIST) - -This test and use of `cdr' can be put together in a function that -goes through a list and prints each element of the list on a line of -its own. - -An Example: `print-elements-of-list' ------------------------------------- - -The `print-elements-of-list' function illustrates a `while' loop with -a list. - -The function requires several lines for its output. If you are -reading this in Emacs 21 or a later version, you can evaluate the -following expression inside of Info, as usual. - -If you are using an earlier version of Emacs, you need to copy the -necessary expressions to your `*scratch*' buffer and evaluate them -there. This is because the echo area had only one line in the -earlier versions. - -You can copy the expressions by marking the beginning of the region -with `C-<SPC>' (`set-mark-command'), moving the cursor to the end of -the region and then copying the region using `M-w' -(`copy-region-as-kill'). In the `*scratch*' buffer, you can yank the -expressions back by typing `C-y' (`yank'). - -After you have copied the expressions to the `*scratch*' buffer, -evaluate each expression in turn. Be sure to evaluate the last -expression, `(print-elements-of-list animals)', by typing `C-u C-x -C-e', that is, by giving an argument to `eval-last-sexp'. This will -cause the result of the evaluation to be printed in the `*scratch*' -buffer instead of being printed in the echo area. (Otherwise you -will see something like this in your echo area: -`^Jgazelle^J^Jgiraffe^J^Jlion^J^Jtiger^Jnil', in which each `^J' -stands for a `newline'.) - -If you are using Emacs 21 or later, you can evaluate these expressions -directly in the Info buffer, and the echo area will grow to show the -results. - - (setq animals '(gazelle giraffe lion tiger)) - - (defun print-elements-of-list (list) - "Print each element of LIST on a line of its own." - (while list - (print (car list)) - (setq list (cdr list)))) - - (print-elements-of-list animals) - -When you evaluate the three expressions in sequence, you will see -this: - - gazelle - - giraffe - - lion - - tiger - nil - -Each element of the list is printed on a line of its own (that is what -the function `print' does) and then the value returned by the -function is printed. Since the last expression in the function is the -`while' loop, and since `while' loops always return `nil', a `nil' is -printed after the last element of the list. - -A Loop with an Incrementing Counter ------------------------------------ - -A loop is not useful unless it stops when it ought. Besides -controlling a loop with a list, a common way of stopping a loop is to -write the first argument as a test that returns false when the correct -number of repetitions are complete. This means that the loop must -have a counter--an expression that counts how many times the loop -repeats itself. - -The test can be an expression such as `(< count desired-number)' -which returns `t' for true if the value of `count' is less than the -`desired-number' of repetitions and `nil' for false if the value of -`count' is equal to or is greater than the `desired-number'. The -expression that increments the count can be a simple `setq' such as -`(setq count (1+ count))', where `1+' is a built-in function in Emacs -Lisp that adds 1 to its argument. (The expression `(1+ count)' has -the same result as `(+ count 1)', but is easier for a human to read.) - -The template for a `while' loop controlled by an incrementing counter -looks like this: - - SET-COUNT-TO-INITIAL-VALUE - (while (< count desired-number) ; true-or-false-test - BODY... - (setq count (1+ count))) ; incrementer - -Note that you need to set the initial value of `count'; usually it is -set to 1. - -Example with incrementing counter -................................. - -Suppose you are playing on the beach and decide to make a triangle of -pebbles, putting one pebble in the first row, two in the second row, -three in the third row and so on, like this: - - - * - * * - * * * - * * * * - - -(About 2500 years ago, Pythagoras and others developed the beginnings -of number theory by considering questions such as this.) - -Suppose you want to know how many pebbles you will need to make a -triangle with 7 rows? - -Clearly, what you need to do is add up the numbers from 1 to 7. There -are two ways to do this; start with the smallest number, one, and add -up the list in sequence, 1, 2, 3, 4 and so on; or start with the -largest number and add the list going down: 7, 6, 5, 4 and so on. -Because both mechanisms illustrate common ways of writing `while' -loops, we will create two examples, one counting up and the other -counting down. In this first example, we will start with 1 and add -2, 3, 4 and so on. - -If you are just adding up a short list of numbers, the easiest way to -do it is to add up all the numbers at once. However, if you do not -know ahead of time how many numbers your list will have, or if you -want to be prepared for a very long list, then you need to design -your addition so that what you do is repeat a simple process many -times instead of doing a more complex process once. - -For example, instead of adding up all the pebbles all at once, what -you can do is add the number of pebbles in the first row, 1, to the -number in the second row, 2, and then add the total of those two rows -to the third row, 3. Then you can add the number in the fourth row, -4, to the total of the first three rows; and so on. - -The critical characteristic of the process is that each repetitive -action is simple. In this case, at each step we add only two numbers, -the number of pebbles in the row and the total already found. This -process of adding two numbers is repeated again and again until the -last row has been added to the total of all the preceding rows. In a -more complex loop the repetitive action might not be so simple, but -it will be simpler than doing everything all at once. - -The parts of the function definition -.................................... - -The preceding analysis gives us the bones of our function definition: -first, we will need a variable that we can call `total' that will be -the total number of pebbles. This will be the value returned by the -function. - -Second, we know that the function will require an argument: this -argument will be the total number of rows in the triangle. It can be -called `number-of-rows'. - -Finally, we need a variable to use as a counter. We could call this -variable `counter', but a better name is `row-number'. That is -because what the counter does is count rows, and a program should be -written to be as understandable as possible. - -When the Lisp interpreter first starts evaluating the expressions in -the function, the value of `total' should be set to zero, since we -have not added anything to it. Then the function should add the -number of pebbles in the first row to the total, and then add the -number of pebbles in the second to the total, and then add the number -of pebbles in the third row to the total, and so on, until there are -no more rows left to add. - -Both `total' and `row-number' are used only inside the function, so -they can be declared as local variables with `let' and given initial -values. Clearly, the initial value for `total' should be 0. The -initial value of `row-number' should be 1, since we start with the -first row. This means that the `let' statement will look like this: - - (let ((total 0) - (row-number 1)) - BODY...) - -After the internal variables are declared and bound to their initial -values, we can begin the `while' loop. The expression that serves as -the test should return a value of `t' for true so long as the -`row-number' is less than or equal to the `number-of-rows'. (If the -expression tests true only so long as the row number is less than the -number of rows in the triangle, the last row will never be added to -the total; hence the row number has to be either less than or equal -to the number of rows.) - -Lisp provides the `<=' function that returns true if the value of its -first argument is less than or equal to the value of its second -argument and false otherwise. So the expression that the `while' -will evaluate as its test should look like this: - - (<= row-number number-of-rows) - -The total number of pebbles can be found by repeatedly adding the -number of pebbles in a row to the total already found. Since the -number of pebbles in the row is equal to the row number, the total -can be found by adding the row number to the total. (Clearly, in a -more complex situation, the number of pebbles in the row might be -related to the row number in a more complicated way; if this were the -case, the row number would be replaced by the appropriate expression.) - - (setq total (+ total row-number)) - -What this does is set the new value of `total' to be equal to the sum -of adding the number of pebbles in the row to the previous total. - -After setting the value of `total', the conditions need to be -established for the next repetition of the loop, if there is one. -This is done by incrementing the value of the `row-number' variable, -which serves as a counter. After the `row-number' variable has been -incremented, the true-or-false-test at the beginning of the `while' -loop tests whether its value is still less than or equal to the value -of the `number-of-rows' and if it is, adds the new value of the -`row-number' variable to the `total' of the previous repetition of -the loop. - -The built-in Emacs Lisp function `1+' adds 1 to a number, so the -`row-number' variable can be incremented with this expression: - - (setq row-number (1+ row-number)) - -Putting the function definition together -........................................ - -We have created the parts for the function definition; now we need to -put them together. - -First, the contents of the `while' expression: - - (while (<= row-number number-of-rows) ; true-or-false-test - (setq total (+ total row-number)) - (setq row-number (1+ row-number))) ; incrementer - -Along with the `let' expression varlist, this very nearly completes -the body of the function definition. However, it requires one final -element, the need for which is somewhat subtle. - -The final touch is to place the variable `total' on a line by itself -after the `while' expression. Otherwise, the value returned by the -whole function is the value of the last expression that is evaluated -in the body of the `let', and this is the value returned by the -`while', which is always `nil'. - -This may not be evident at first sight. It almost looks as if the -incrementing expression is the last expression of the whole function. -But that expression is part of the body of the `while'; it is the -last element of the list that starts with the symbol `while'. -Moreover, the whole of the `while' loop is a list within the body of -the `let'. - -In outline, the function will look like this: - - (defun NAME-OF-FUNCTION (ARGUMENT-LIST) - "DOCUMENTATION..." - (let (VARLIST) - (while (TRUE-OR-FALSE-TEST) - BODY-OF-WHILE... ) - ... ) ; Need final expression here. - -The result of evaluating the `let' is what is going to be returned by -the `defun' since the `let' is not embedded within any containing -list, except for the `defun' as a whole. However, if the `while' is -the last element of the `let' expression, the function will always -return `nil'. This is not what we want! Instead, what we want is -the value of the variable `total'. This is returned by simply -placing the symbol as the last element of the list starting with -`let'. It gets evaluated after the preceding elements of the list -are evaluated, which means it gets evaluated after it has been -assigned the correct value for the total. - -It may be easier to see this by printing the list starting with `let' -all on one line. This format makes it evident that the VARLIST and -`while' expressions are the second and third elements of the list -starting with `let', and the `total' is the last element: - - (let (VARLIST) (while (TRUE-OR-FALSE-TEST) BODY-OF-WHILE... ) total) - -Putting everything together, the `triangle' function definition looks -like this: - - (defun triangle (number-of-rows) ; Version with - ; incrementing counter. - "Add up the number of pebbles in a triangle. - The first row has one pebble, the second row two pebbles, - the third row three pebbles, and so on. - The argument is NUMBER-OF-ROWS." - (let ((total 0) - (row-number 1)) - (while (<= row-number number-of-rows) - (setq total (+ total row-number)) - (setq row-number (1+ row-number))) - total)) - -After you have installed `triangle' by evaluating the function, you -can try it out. Here are two examples: - - (triangle 4) - - (triangle 7) - -The sum of the first four numbers is 10 and the sum of the first seven -numbers is 28. - -Loop with a Decrementing Counter --------------------------------- - -Another common way to write a `while' loop is to write the test so -that it determines whether a counter is greater than zero. So long -as the counter is greater than zero, the loop is repeated. But when -the counter is equal to or less than zero, the loop is stopped. For -this to work, the counter has to start out greater than zero and then -be made smaller and smaller by a form that is evaluated repeatedly. - -The test will be an expression such as `(> counter 0)' which returns -`t' for true if the value of `counter' is greater than zero, and -`nil' for false if the value of `counter' is equal to or less than -zero. The expression that makes the number smaller and smaller can -be a simple `setq' such as `(setq counter (1- counter))', where `1-' -is a built-in function in Emacs Lisp that subtracts 1 from its -argument. - -The template for a decrementing `while' loop looks like this: - - (while (> counter 0) ; true-or-false-test - BODY... - (setq counter (1- counter))) ; decrementer - -Example with decrementing counter -................................. - -To illustrate a loop with a decrementing counter, we will rewrite the -`triangle' function so the counter decreases to zero. - -This is the reverse of the earlier version of the function. In this -case, to find out how many pebbles are needed to make a triangle with -3 rows, add the number of pebbles in the third row, 3, to the number -in the preceding row, 2, and then add the total of those two rows to -the row that precedes them, which is 1. - -Likewise, to find the number of pebbles in a triangle with 7 rows, add -the number of pebbles in the seventh row, 7, to the number in the -preceding row, which is 6, and then add the total of those two rows to -the row that precedes them, which is 5, and so on. As in the previous -example, each addition only involves adding two numbers, the total of -the rows already added up and the number of pebbles in the row that is -being added to the total. This process of adding two numbers is -repeated again and again until there are no more pebbles to add. - -We know how many pebbles to start with: the number of pebbles in the -last row is equal to the number of rows. If the triangle has seven -rows, the number of pebbles in the last row is 7. Likewise, we know -how many pebbles are in the preceding row: it is one less than the -number in the row. - -The parts of the function definition -.................................... - -We start with three variables: the total number of rows in the -triangle; the number of pebbles in a row; and the total number of -pebbles, which is what we want to calculate. These variables can be -named `number-of-rows', `number-of-pebbles-in-row', and `total', -respectively. - -Both `total' and `number-of-pebbles-in-row' are used only inside the -function and are declared with `let'. The initial value of `total' -should, of course, be zero. However, the initial value of -`number-of-pebbles-in-row' should be equal to the number of rows in -the triangle, since the addition will start with the longest row. - -This means that the beginning of the `let' expression will look like -this: - - (let ((total 0) - (number-of-pebbles-in-row number-of-rows)) - BODY...) - -The total number of pebbles can be found by repeatedly adding the -number of pebbles in a row to the total already found, that is, by -repeatedly evaluating the following expression: - - (setq total (+ total number-of-pebbles-in-row)) - -After the `number-of-pebbles-in-row' is added to the `total', the -`number-of-pebbles-in-row' should be decremented by one, since the -next time the loop repeats, the preceding row will be added to the -total. - -The number of pebbles in a preceding row is one less than the number -of pebbles in a row, so the built-in Emacs Lisp function `1-' can be -used to compute the number of pebbles in the preceding row. This can -be done with the following expression: - - (setq number-of-pebbles-in-row - (1- number-of-pebbles-in-row)) - -Finally, we know that the `while' loop should stop making repeated -additions when there are no pebbles in a row. So the test for the -`while' loop is simply: - - (while (> number-of-pebbles-in-row 0) - -Putting the function definition together -........................................ - -We can put these expressions together to create a function definition -that works. However, on examination, we find that one of the local -variables is unneeded! - -The function definition looks like this: - - ;;; First subtractive version. - (defun triangle (number-of-rows) - "Add up the number of pebbles in a triangle." - (let ((total 0) - (number-of-pebbles-in-row number-of-rows)) - (while (> number-of-pebbles-in-row 0) - (setq total (+ total number-of-pebbles-in-row)) - (setq number-of-pebbles-in-row - (1- number-of-pebbles-in-row))) - total)) - -As written, this function works. - -However, we do not need `number-of-pebbles-in-row'. - -When the `triangle' function is evaluated, the symbol -`number-of-rows' will be bound to a number, giving it an initial -value. That number can be changed in the body of the function as if -it were a local variable, without any fear that such a change will -effect the value of the variable outside of the function. This is a -very useful characteristic of Lisp; it means that the variable -`number-of-rows' can be used anywhere in the function where -`number-of-pebbles-in-row' is used. - -Here is a second version of the function written a bit more cleanly: - - (defun triangle (number) ; Second version. - "Return sum of numbers 1 through NUMBER inclusive." - (let ((total 0)) - (while (> number 0) - (setq total (+ total number)) - (setq number (1- number))) - total)) - -In brief, a properly written `while' loop will consist of three parts: - - 1. A test that will return false after the loop has repeated itself - the correct number of times. - - 2. An expression the evaluation of which will return the value - desired after being repeatedly evaluated. - - 3. An expression to change the value passed to the - true-or-false-test so that the test returns false after the loop - has repeated itself the right number of times. - -Save your time: `dolist' and `dotimes' -====================================== - -In addition to `while', both `dolist' and `dotimes' provide for -looping. Sometimes these are quicker to write than the equivalent -`while' loop. Both are Lisp macros. (*Note Macros: (elisp)Macros. ) - -`dolist' works like a `while' loop that `CDRs down a list': `dolist' -automatically shortens the list each time it loops--takes the CDR of -the list--and binds the CAR of each shorter version of the list to -the first of its arguments. - -`dotimes' loops a specific number of times: you specify the number. - -The `dolist' Macro -.................. - -Suppose, for example, you want to reverse a list, so that "first" -"second" "third" becomes "third" "second" "first". - -In practice, you would use the `reverse' function, like this: - - (setq animals '(gazelle giraffe lion tiger)) - - (reverse animals) - -Here is how you could reverse the list using a `while' loop: - - (setq animals '(gazelle giraffe lion tiger)) - - (defun reverse-list-with-while (list) - "Using while, reverse the order of LIST." - (let (value) ; make sure list starts empty - (while list - (setq value (cons (car list) value)) - (setq list (cdr list))) - value)) - - (reverse-list-with-while animals) - -And here is how you could use the `dolist' macro: - - (setq animals '(gazelle giraffe lion tiger)) - - (defun reverse-list-with-dolist (list) - "Using dolist, reverse the order of LIST." - (let (value) ; make sure list starts empty - (dolist (element list value) - (setq value (cons element value))))) - - (reverse-list-with-dolist animals) - -In Info, you can place your cursor after the closing parenthesis of -each expression and type `C-x C-e'; in each case, you should see - - (tiger lion giraffe gazelle) - -in the echo area. - -For this example, the existing `reverse' function is obviously best. -The `while' loop is just like our first example (*note A `while' Loop -and a List: Loop Example.). The `while' first checks whether the -list has elements; if so, it constructs a new list by adding the -first element of the list to the existing list (which in the first -iteration of the loop is `nil'). Since the second element is -prepended in front of the first element, and the third element is -prepended in front of the second element, the list is reversed. - -In the expression using a `while' loop, the `(setq list (cdr list))' -expression shortens the list, so the `while' loop eventually stops. -In addition, it provides the `cons' expression with a new first -element by creating a new and shorter list at each repetition of the -loop. - -The `dolist' expression does very much the same as the `while' -expression, except that the `dolist' macro does some of the work you -have to do when writing a `while' expression. - -Like a `while' loop, a `dolist' loops. What is different is that it -automatically shortens the list each time it loops -- it `CDRs down -the list' on its own -- and it automatically binds the CAR of each -shorter version of the list to the first of its arguments. - -In the example, the CAR of each shorter version of the list is -referred to using the symbol `element', the list itself is called -`list', and the value returned is called `value'. The remainder of -the `dolist' expression is the body. - -The `dolist' expression binds the CAR of each shorter version of the -list to `element' and then evaluates the body of the expression; and -repeats the loop. The result is returned in `value'. - -The `dotimes' Macro -................... - -The `dotimes' macro is similar to `dolist', except that it loops a -specific number of times. - -The first argument to `dotimes' is assigned the numbers 0, 1, 2 and -so forth each time around the loop, and the value of the third -argument is returned. You need to provide the value of the second -argument, which is how many times the macro loops. - -For example, the following binds the numbers from 0 up to, but not -including, the number 3 to the first argument, NUMBER, and then -constructs a list of the three numbers. (The first number is 0, the -second number is 1, and the third number is 2; this makes a total of -three numbers in all, starting with zero as the first number.) - - (let (value) ; otherwise a value is a void variable - (dotimes (number 3 value) - (setq value (cons number value)))) - - => (2 1 0) - -`dotimes' returns `value', so the way to use `dotimes' is to operate -on some expression NUMBER number of times and then return the result, -either as a list or an atom. - -Here is an example of a `defun' that uses `dotimes' to add up the -number of pebbles in a triangle. - - (defun triangle-using-dotimes (number-of-rows) - "Using dotimes, add up the number of pebbles in a triangle." - (let ((total 0)) ; otherwise a total is a void variable - (dotimes (number number-of-rows total) - (setq total (+ total (1+ number)))))) - - (triangle-using-dotimes 4) - -Recursion -========= - -A recursive function contains code that tells the Lisp interpreter to -call a program that runs exactly like itself, but with slightly -different arguments. The code runs exactly the same because it has -the same name. However, even though the program has the same name, it -is not the same entity. It is different. In the jargon, it is a -different `instance'. - -Eventually, if the program is written correctly, the `slightly -different arguments' will become sufficiently different from the first -arguments that the final instance will stop. - -Building Robots: Extending the Metaphor ---------------------------------------- - -It is sometimes helpful to think of a running program as a robot that -does a job. In doing its job, a recursive function calls on a second -robot to help it. The second robot is identical to the first in every -way, except that the second robot helps the first and has been passed -different arguments than the first. - -In a recursive function, the second robot may call a third; and the -third may call a fourth, and so on. Each of these is a different -entity; but all are clones. - -Since each robot has slightly different instructions--the arguments -will differ from one robot to the next--the last robot should know -when to stop. - -Let's expand on the metaphor in which a computer program is a robot. - -A function definition provides the blueprints for a robot. When you -install a function definition, that is, when you evaluate a `defun' -special form, you install the necessary equipment to build robots. -It is as if you were in a factory, setting up an assembly line. -Robots with the same name are built according to the same blueprints. -So they have, as it were, the same `model number', but a different -`serial number'. - -We often say that a recursive function `calls itself'. What we mean -is that the instructions in a recursive function cause the Lisp -interpreter to run a different function that has the same name and -does the same job as the first, but with different arguments. - -It is important that the arguments differ from one instance to the -next; otherwise, the process will never stop. - -The Parts of a Recursive Definition ------------------------------------ - -A recursive function typically contains a conditional expression which -has three parts: - - 1. A true-or-false-test that determines whether the function is - called again, here called the "do-again-test". - - 2. The name of the function. When this name is called, a new - instance of the function--a new robot, as it were--is created - and told what to do. - - 3. An expression that returns a different value each time the - function is called, here called the "next-step-expression". - Consequently, the argument (or arguments) passed to the new - instance of the function will be different from that passed to - the previous instance. This causes the conditional expression, - the "do-again-test", to test false after the correct number of - repetitions. - -Recursive functions can be much simpler than any other kind of -function. Indeed, when people first start to use them, they often -look so mysteriously simple as to be incomprehensible. Like riding a -bicycle, reading a recursive function definition takes a certain knack -which is hard at first but then seems simple. - -There are several different common recursive patterns. A very simple -pattern looks like this: - - (defun NAME-OF-RECURSIVE-FUNCTION (ARGUMENT-LIST) - "DOCUMENTATION..." - (if DO-AGAIN-TEST - BODY... - (NAME-OF-RECURSIVE-FUNCTION - NEXT-STEP-EXPRESSION))) - -Each time a recursive function is evaluated, a new instance of it is -created and told what to do. The arguments tell the instance what to -do. - -An argument is bound to the value of the next-step-expression. Each -instance runs with a different value of the next-step-expression. - -The value in the next-step-expression is used in the do-again-test. - -The value returned by the next-step-expression is passed to the new -instance of the function, which evaluates it (or some -transmogrification of it) to determine whether to continue or stop. -The next-step-expression is designed so that the do-again-test returns -false when the function should no longer be repeated. - -The do-again-test is sometimes called the "stop condition", since it -stops the repetitions when it tests false. - -Recursion with a List ---------------------- - -The example of a `while' loop that printed the elements of a list of -numbers can be written recursively. Here is the code, including an -expression to set the value of the variable `animals' to a list. - -If you are using Emacs 20 or before, this example must be copied to -the `*scratch*' buffer and each expression must be evaluated there. -Use `C-u C-x C-e' to evaluate the `(print-elements-recursively -animals)' expression so that the results are printed in the buffer; -otherwise the Lisp interpreter will try to squeeze the results into -the one line of the echo area. - -Also, place your cursor immediately after the last closing parenthesis -of the `print-elements-recursively' function, before the comment. -Otherwise, the Lisp interpreter will try to evaluate the comment. - -If you are using Emacs 21 or later, you can evaluate this expression -directly in Info. - - (setq animals '(gazelle giraffe lion tiger)) - - (defun print-elements-recursively (list) - "Print each element of LIST on a line of its own. - Uses recursion." - (if list ; do-again-test - (progn - (print (car list)) ; body - (print-elements-recursively ; recursive call - (cdr list))))) ; next-step-expression - - (print-elements-recursively animals) - -The `print-elements-recursively' function first tests whether there -is any content in the list; if there is, the function prints the -first element of the list, the CAR of the list. Then the function -`invokes itself', but gives itself as its argument, not the whole -list, but the second and subsequent elements of the list, the CDR of -the list. - -Put another way, if the list is not empty, the function invokes -another instance of code that is similar to the initial code, but is a -different thread of execution, with different arguments than the first -instance. - -Put in yet another way, if the list is not empty, the first robot -assemblies a second robot and tells it what to do; the second robot is -a different individual from the first, but is the same model. - -When the second evaluation occurs, the `if' expression is evaluated -and if true, prints the first element of the list it receives as its -argument (which is the second element of the original list). Then -the function `calls itself' with the CDR of the list it is invoked -with, which (the second time around) is the CDR of the CDR of the -original list. - -Note that although we say that the function `calls itself', what we -mean is that the Lisp interpreter assembles and instructs a new -instance of the program. The new instance is a clone of the first, -but is a separate individual. - -Each time the function `invokes itself', it invokes itself on a -shorter version of the original list. It creates a new instance that -works on a shorter list. - -Eventually, the function invokes itself on an empty list. It creates -a new instance whose argument is `nil'. The conditional expression -tests the value of `list'. Since the value of `list' is `nil', the -`if' expression tests false so the then-part is not evaluated. The -function as a whole then returns `nil'. - -When you evaluate `(print-elements-recursively animals)' in the -`*scratch*' buffer, you see this result: - - gazelle - - giraffe - - lion - - tiger - nil - -Recursion in Place of a Counter -------------------------------- - -The `triangle' function described in a previous section can also be -written recursively. It looks like this: - - (defun triangle-recursively (number) - "Return the sum of the numbers 1 through NUMBER inclusive. - Uses recursion." - (if (= number 1) ; do-again-test - 1 ; then-part - (+ number ; else-part - (triangle-recursively ; recursive call - (1- number))))) ; next-step-expression - - (triangle-recursively 7) - -You can install this function by evaluating it and then try it by -evaluating `(triangle-recursively 7)'. (Remember to put your cursor -immediately after the last parenthesis of the function definition, -before the comment.) The function evaluates to 28. - -To understand how this function works, let's consider what happens in -the various cases when the function is passed 1, 2, 3, or 4 as the -value of its argument. - -An argument of 1 or 2 -..................... - -First, what happens if the value of the argument is 1? - -The function has an `if' expression after the documentation string. -It tests whether the value of `number' is equal to 1; if so, Emacs -evaluates the then-part of the `if' expression, which returns the -number 1 as the value of the function. (A triangle with one row has -one pebble in it.) - -Suppose, however, that the value of the argument is 2. In this case, -Emacs evaluates the else-part of the `if' expression. - -The else-part consists of an addition, the recursive call to -`triangle-recursively' and a decrementing action; and it looks like -this: - - (+ number (triangle-recursively (1- number))) - -When Emacs evaluates this expression, the innermost expression is -evaluated first; then the other parts in sequence. Here are the steps -in detail: - -Step 1 Evaluate the innermost expression. - The innermost expression is `(1- number)' so Emacs decrements the - value of `number' from 2 to 1. - -Step 2 Evaluate the `triangle-recursively' function. - The Lisp interpreter creates an individual instance of - `triangle-recursively'. It does not matter that this function is - contained within itself. Emacs passes the result Step 1 as the - argument used by this instance of the `triangle-recursively' - function - - In this case, Emacs evaluates `triangle-recursively' with an - argument of 1. This means that this evaluation of - `triangle-recursively' returns 1. - -Step 3 Evaluate the value of `number'. - The variable `number' is the second element of the list that - starts with `+'; its value is 2. - -Step 4 Evaluate the `+' expression. - The `+' expression receives two arguments, the first from the - evaluation of `number' (Step 3) and the second from the - evaluation of `triangle-recursively' (Step 2). - - The result of the addition is the sum of 2 plus 1, and the - number 3 is returned, which is correct. A triangle with two - rows has three pebbles in it. - -An argument of 3 or 4 -..................... - -Suppose that `triangle-recursively' is called with an argument of 3. - -Step 1 Evaluate the do-again-test. - The `if' expression is evaluated first. This is the do-again - test and returns false, so the else-part of the `if' expression - is evaluated. (Note that in this example, the do-again-test - causes the function to call itself when it tests false, not when - it tests true.) - -Step 2 Evaluate the innermost expression of the else-part. - The innermost expression of the else-part is evaluated, which - decrements 3 to 2. This is the next-step-expression. - -Step 3 Evaluate the `triangle-recursively' function. - The number 2 is passed to the `triangle-recursively' function. - - We know what happens when Emacs evaluates `triangle-recursively' - with an argument of 2. After going through the sequence of - actions described earlier, it returns a value of 3. So that is - what will happen here. - -Step 4 Evaluate the addition. - 3 will be passed as an argument to the addition and will be - added to the number with which the function was called, which is - 3. - -The value returned by the function as a whole will be 6. - -Now that we know what will happen when `triangle-recursively' is -called with an argument of 3, it is evident what will happen if it is -called with an argument of 4: - - In the recursive call, the evaluation of - - (triangle-recursively (1- 4)) - - will return the value of evaluating - - (triangle-recursively 3) - - which is 6 and this value will be added to 4 by the addition in - the third line. - -The value returned by the function as a whole will be 10. - -Each time `triangle-recursively' is evaluated, it evaluates a version -of itself--a different instance of itself--with a smaller argument, -until the argument is small enough so that it does not evaluate -itself. - -Note that this particular design for a recursive function requires -that operations be deferred. - -Before `(triangle-recursively 7)' can calculate its answer, it must -call `(triangle-recursively 6)'; and before `(triangle-recursively -6)' can calculate its answer, it must call `(triangle-recursively -5)'; and so on. That is to say, the calculation that -`(triangle-recursively 7)' makes must be deferred until -`(triangle-recursively 6)' makes its calculation; and -`(triangle-recursively 6)' must defer until `(triangle-recursively -5)' completes; and so on. - -If each of these instances of `triangle-recursively' are thought of -as different robots, the first robot must wait for the second to -complete its job, which must wait until the third completes, and so -on. - -There is a way around this kind of waiting, which we will discuss in -*Note Recursion without Deferments: No Deferment. - -Recursion Example Using `cond' ------------------------------- - -The version of `triangle-recursively' described earlier is written -with the `if' special form. It can also be written using another -special form called `cond'. The name of the special form `cond' is -an abbreviation of the word `conditional'. - -Although the `cond' special form is not used as often in the Emacs -Lisp sources as `if', it is used often enough to justify explaining -it. - -The template for a `cond' expression looks like this: - - (cond - BODY...) - -where the BODY is a series of lists. - -Written out more fully, the template looks like this: - - (cond - (FIRST-TRUE-OR-FALSE-TEST FIRST-CONSEQUENT) - (SECOND-TRUE-OR-FALSE-TEST SECOND-CONSEQUENT) - (THIRD-TRUE-OR-FALSE-TEST THIRD-CONSEQUENT) - ...) - -When the Lisp interpreter evaluates the `cond' expression, it -evaluates the first element (the CAR or true-or-false-test) of the -first expression in a series of expressions within the body of the -`cond'. - -If the true-or-false-test returns `nil' the rest of that expression, -the consequent, is skipped and the true-or-false-test of the next -expression is evaluated. When an expression is found whose -true-or-false-test returns a value that is not `nil', the consequent -of that expression is evaluated. The consequent can be one or more -expressions. If the consequent consists of more than one expression, -the expressions are evaluated in sequence and the value of the last -one is returned. If the expression does not have a consequent, the -value of the true-or-false-test is returned. - -If none of the true-or-false-tests test true, the `cond' expression -returns `nil'. - -Written using `cond', the `triangle' function looks like this: - - (defun triangle-using-cond (number) - (cond ((<= number 0) 0) - ((= number 1) 1) - ((> number 1) - (+ number (triangle-using-cond (1- number)))))) - -In this example, the `cond' returns 0 if the number is less than or -equal to 0, it returns 1 if the number is 1 and it evaluates `(+ -number (triangle-using-cond (1- number)))' if the number is greater -than 1. - -Recursive Patterns ------------------- - -Here are three common recursive patterns. Each involves a list. -Recursion does not need to involve lists, but Lisp is designed for -lists and this provides a sense of its primal capabilities. - -Recursive Pattern: _every_ -.......................... - -In the `every' recursive pattern, an action is performed on every -element of a list. - -The basic pattern is: - - * If a list be empty, return `nil'. - - * Else, act on the beginning of the list (the CAR of the list) - - through a recursive call by the function on the rest - (the CDR) of the list, - - - and, optionally, combine the acted-on element, using - `cons', with the results of acting on the rest. - -Here is example: - - (defun square-each (numbers-list) - "Square each of a NUMBERS LIST, recursively." - (if (not numbers-list) ; do-again-test - nil - (cons - (* (car numbers-list) (car numbers-list)) - (square-each (cdr numbers-list))))) ; next-step-expression - - (square-each '(1 2 3)) - => (1 4 9) - -If `numbers-list' is empty, do nothing. But if it has content, -construct a list combining the square of the first number in the list -with the result of the recursive call. - -(The example follows the pattern exactly: `nil' is returned if the -numbers' list is empty. In practice, you would write the conditional -so it carries out the action when the numbers' list is not empty.) - -The `print-elements-recursively' function (*note Recursion with a -List: Recursion with list.) is another example of an `every' pattern, -except in this case, rather than bring the results together using -`cons', we print each element of output. - -The `print-elements-recursively' function looks like this: - - (setq animals '(gazelle giraffe lion tiger)) - - (defun print-elements-recursively (list) - "Print each element of LIST on a line of its own. - Uses recursion." - (if list ; do-again-test - (progn - (print (car list)) ; body - (print-elements-recursively ; recursive call - (cdr list))))) ; next-step-expression - - (print-elements-recursively animals) - -The pattern for `print-elements-recursively' is: - - * If the list be empty, do nothing. - - * But if the list has at least one element, - - act on the beginning of the list (the CAR of the list), - - - and make a recursive call on the rest (the CDR) of the - list. - -Recursive Pattern: _accumulate_ -............................... - -Another recursive pattern is called the `accumulate' pattern. In the -`accumulate' recursive pattern, an action is performed on every -element of a list and the result of that action is accumulated with -the results of performing the action on the other elements. - -This is very like the `every' pattern using `cons', except that -`cons' is not used, but some other combiner. - -The pattern is: - - * If a list be empty, return zero or some other constant. - - * Else, act on the beginning of the list (the CAR of the list), - - and combine that acted-on element, using `+' or - some other combining function, with - - - a recursive call by the function on the rest (the CDR) - of the list. - -Here is an example: - - (defun add-elements (numbers-list) - "Add the elements of NUMBERS-LIST together." - (if (not numbers-list) - 0 - (+ (car numbers-list) (add-elements (cdr numbers-list))))) - - (add-elements '(1 2 3 4)) - => 10 - -*Note Making a List of Files: Files List, for an example of the -accumulate pattern. - -Recursive Pattern: _keep_ -......................... - -A third recursive pattern is called the `keep' pattern. In the -`keep' recursive pattern, each element of a list is tested; the -element is acted on and the results are kept only if the element -meets a criterion. - -Again, this is very like the `every' pattern, except the element is -skipped unless it meets a criterion. - -The pattern has three parts: - - * If a list be empty, return `nil'. - - * Else, if the beginning of the list (the CAR of the list) passes - a test - - act on that element and combine it, using `cons' with - - - a recursive call by the function on the rest (the CDR) - of the list. - - * Otherwise, if the beginning of the list (the CAR of the list) - fails the test - - skip on that element, - - - and, recursively call the function on the rest (the - CDR) of the list. - -Here is an example that uses `cond': - - (defun keep-three-letter-words (word-list) - "Keep three letter words in WORD-LIST." - (cond - ;; First do-again-test: stop-condition - ((not word-list) nil) - - ;; Second do-again-test: when to act - ((eq 3 (length (symbol-name (car word-list)))) - ;; combine acted-on element with recursive call on shorter list - (cons (car word-list) (keep-three-letter-words (cdr word-list)))) - - ;; Third do-again-test: when to skip element; - ;; recursively call shorter list with next-step expression - (t (keep-three-letter-words (cdr word-list))))) - - (keep-three-letter-words '(one two three four five six)) - => (one two six) - -It goes without saying that you need not use `nil' as the test for -when to stop; and you can, of course, combine these patterns. - -Recursion without Deferments ----------------------------- - -Let's consider again what happens with the `triangle-recursively' -function. We will find that the intermediate calculations are -deferred until all can be done. - -Here is the function definition: - - (defun triangle-recursively (number) - "Return the sum of the numbers 1 through NUMBER inclusive. - Uses recursion." - (if (= number 1) ; do-again-test - 1 ; then-part - (+ number ; else-part - (triangle-recursively ; recursive call - (1- number))))) ; next-step-expression - -What happens when we call this function with a argument of 7? - -The first instance of the `triangle-recursively' function adds the -number 7 to the value returned by a second instance of -`triangle-recursively', an instance that has been passed an argument -of 6. That is to say, the first calculation is: - - (+ 7 (triangle-recursively 6)) - -The first instance of `triangle-recursively'--you may want to think -of it as a little robot--cannot complete its job. It must hand off -the calculation for `(triangle-recursively 6)' to a second instance -of the program, to a second robot. This second individual is -completely different from the first one; it is, in the jargon, a -`different instantiation'. Or, put another way, it is a different -robot. It is the same model as the first; it calculates triangle -numbers recursively; but it has a different serial number. - -And what does `(triangle-recursively 6)' return? It returns the -number 6 added to the value returned by evaluating -`triangle-recursively' with an argument of 5. Using the robot -metaphor, it asks yet another robot to help it. - -Now the total is: - - (+ 7 6 (triangle-recursively 5)) - -And what happens next? - - (+ 7 6 5 (triangle-recursively 4)) - -Each time `triangle-recursively' is called, except for the last time, -it creates another instance of the program--another robot--and asks -it to make a calculation. - -Eventually, the full addition is set up and performed: - - (+ 7 6 5 4 3 2 1) - -This design for the function defers the calculation of the first step -until the second can be done, and defers that until the third can be -done, and so on. Each deferment means the computer must remember what -is being waited on. This is not a problem when there are only a few -steps, as in this example. But it can be a problem when there are -more steps. - -No Deferment Solution ---------------------- - -The solution to the problem of deferred operations is to write in a -manner that does not defer operations(1). This requires writing to a -different pattern, often one that involves writing two function -definitions, an `initialization' function and a `helper' function. - -The `initialization' function sets up the job; the `helper' function -does the work. - -Here are the two function definitions for adding up numbers. They are -so simple, I find them hard to understand. - - (defun triangle-initialization (number) - "Return the sum of the numbers 1 through NUMBER inclusive. - This is the `initialization' component of a two function - duo that uses recursion." - (triangle-recursive-helper 0 0 number)) - - (defun triangle-recursive-helper (sum counter number) - "Return SUM, using COUNTER, through NUMBER inclusive. - This is the `helper' component of a two function duo - that uses recursion." - (if (> counter number) - sum - (triangle-recursive-helper (+ sum counter) ; sum - (1+ counter) ; counter - number))) ; number - -Install both function definitions by evaluating them, then call -`triangle-initialization' with 2 rows: - - (triangle-initialization 2) - => 3 - -The `initialization' function calls the first instance of the `helper' -function with three arguments: zero, zero, and a number which is the -number of rows in the triangle. - -The first two arguments passed to the `helper' function are -initialization values. These values are changed when -`triangle-recursive-helper' invokes new instances.(2) - -Let's see what happens when we have a triangle that has one row. -(This triangle will have one pebble in it!) - -`triangle-initialization' will call its helper with the arguments -`0 0 1'. That function will run the conditional test whether `(> -counter number)': - - (> 0 1) - -and find that the result is false, so it will invoke the then-part of -the `if' clause: - - (triangle-recursive-helper - (+ sum counter) ; sum plus counter => sum - (1+ counter) ; increment counter => counter - number) ; number stays the same - -which will first compute: - - (triangle-recursive-helper (+ 0 0) ; sum - (1+ 0) ; counter - 1) ; number -which is: - - (triangle-recursive-helper 0 1 1) - -Again, `(> counter number)' will be false, so again, the Lisp -interpreter will evaluate `triangle-recursive-helper', creating a new -instance with new arguments. - -This new instance will be; - - (triangle-recursive-helper - (+ sum counter) ; sum plus counter => sum - (1+ counter) ; increment counter => counter - number) ; number stays the same - -which is: - - (triangle-recursive-helper 1 2 1) - -In this case, the `(> counter number)' test will be true! So the -instance will return the value of the sum, which will be 1, as -expected. - -Now, let's pass `triangle-initialization' an argument of 2, to find -out how many pebbles there are in a triangle with two rows. - -That function calls `(triangle-recursive-helper 0 0 2)'. - -In stages, the instances called will be: - - sum counter number - (triangle-recursive-helper 0 1 2) - - (triangle-recursive-helper 1 2 2) - - (triangle-recursive-helper 3 3 2) - -When the last instance is called, the `(> counter number)' test will -be true, so the instance will return the value of `sum', which will -be 3. - -This kind of pattern helps when you are writing functions that can use -many resources in a computer. - ----------- Footnotes ---------- - -(1) The phrase "tail recursive" is used to describe such a process, -one that uses `constant space'. - -(2) The jargon is mildly confusing: `triangle-recursive-helper' uses -a process that is iterative in a procedure that is recursive. The -process is called iterative because the computer need only record the -three values, `sum', `counter', and `number'; the procedure is -recursive because the function `calls itself'. On the other hand, -both the process and the procedure used by `triangle-recursively' are -called recursive. The word `recursive' has different meanings in the -two contexts. - -Looping Exercise -================ - - * Write a function similar to `triangle' in which each row has a - value which is the square of the row number. Use a `while' loop. - - * Write a function similar to `triangle' that multiplies instead of - adds the values. - - * Rewrite these two functions recursively. Rewrite these functions - using `cond'. - - * Write a function for Texinfo mode that creates an index entry at - the beginning of a paragraph for every `@dfn' within the - paragraph. (In a Texinfo file, `@dfn' marks a definition. For - more information, see *Note Indicating Definitions: - (texinfo)Indicating.) - -Regular Expression Searches -*************************** - -Regular expression searches are used extensively in GNU Emacs. The -two functions, `forward-sentence' and `forward-paragraph', illustrate -these searches well. They use regular expressions to find where to -move point. The phrase `regular expression' is often written as -`regexp'. - -Regular expression searches are described in *Note Regular Expression -Search: (emacs)Regexp Search, as well as in *Note Regular -Expressions: (elisp)Regular Expressions. In writing this chapter, I -am presuming that you have at least a mild acquaintance with them. -The major point to remember is that regular expressions permit you to -search for patterns as well as for literal strings of characters. -For example, the code in `forward-sentence' searches for the pattern -of possible characters that could mark the end of a sentence, and -moves point to that spot. - -Before looking at the code for the `forward-sentence' function, it is -worth considering what the pattern that marks the end of a sentence -must be. The pattern is discussed in the next section; following that -is a description of the regular expression search function, -`re-search-forward'. The `forward-sentence' function is described in -the section following. Finally, the `forward-paragraph' function is -described in the last section of this chapter. `forward-paragraph' -is a complex function that introduces several new features. - -The Regular Expression for `sentence-end' -========================================= - -The symbol `sentence-end' is bound to the pattern that marks the end -of a sentence. What should this regular expression be? - -Clearly, a sentence may be ended by a period, a question mark, or an -exclamation mark. Indeed, only clauses that end with one of those -three characters should be considered the end of a sentence. This -means that the pattern should include the character set: - - [.?!] - -However, we do not want `forward-sentence' merely to jump to a -period, a question mark, or an exclamation mark, because such a -character might be used in the middle of a sentence. A period, for -example, is used after abbreviations. So other information is needed. - -According to convention, you type two spaces after every sentence, but -only one space after a period, a question mark, or an exclamation -mark in the body of a sentence. So a period, a question mark, or an -exclamation mark followed by two spaces is a good indicator of an end -of sentence. However, in a file, the two spaces may instead be a tab -or the end of a line. This means that the regular expression should -include these three items as alternatives. - -This group of alternatives will look like this: - - \\($\\| \\| \\) - ^ ^^ - TAB SPC - -Here, `$' indicates the end of the line, and I have pointed out where -the tab and two spaces are inserted in the expression. Both are -inserted by putting the actual characters into the expression. - -Two backslashes, `\\', are required before the parentheses and -vertical bars: the first backslash quotes the following backslash in -Emacs; and the second indicates that the following character, the -parenthesis or the vertical bar, is special. - -Also, a sentence may be followed by one or more carriage returns, like -this: - - [ - ]* - -Like tabs and spaces, a carriage return is inserted into a regular -expression by inserting it literally. The asterisk indicates that the -<RET> is repeated zero or more times. - -But a sentence end does not consist only of a period, a question mark -or an exclamation mark followed by appropriate space: a closing -quotation mark or a closing brace of some kind may precede the space. -Indeed more than one such mark or brace may precede the space. -These require a expression that looks like this: - - []\"')}]* - -In this expression, the first `]' is the first character in the -expression; the second character is `"', which is preceded by a `\' -to tell Emacs the `"' is _not_ special. The last three characters -are `'', `)', and `}'. - -All this suggests what the regular expression pattern for matching the -end of a sentence should be; and, indeed, if we evaluate -`sentence-end' we find that it returns the following value: - - sentence-end - => "[.?!][]\"')}]*\\($\\| \\| \\)[ - ]*" - -The `re-search-forward' Function -================================ - -The `re-search-forward' function is very like the `search-forward' -function. (*Note The `search-forward' Function: search-forward.) - -`re-search-forward' searches for a regular expression. If the search -is successful, it leaves point immediately after the last character -in the target. If the search is backwards, it leaves point just -before the first character in the target. You may tell -`re-search-forward' to return `t' for true. (Moving point is -therefore a `side effect'.) - -Like `search-forward', the `re-search-forward' function takes four -arguments: - - 1. The first argument is the regular expression that the function - searches for. The regular expression will be a string between - quotations marks. - - 2. The optional second argument limits how far the function will - search; it is a bound, which is specified as a position in the - buffer. - - 3. The optional third argument specifies how the function responds - to failure: `nil' as the third argument causes the function to - signal an error (and print a message) when the search fails; any - other value causes it to return `nil' if the search fails and `t' - if the search succeeds. - - 4. The optional fourth argument is the repeat count. A negative - repeat count causes `re-search-forward' to search backwards. - -The template for `re-search-forward' looks like this: - - (re-search-forward "REGULAR-EXPRESSION" - LIMIT-OF-SEARCH - WHAT-TO-DO-IF-SEARCH-FAILS - REPEAT-COUNT) - -The second, third, and fourth arguments are optional. However, if you -want to pass a value to either or both of the last two arguments, you -must also pass a value to all the preceding arguments. Otherwise, the -Lisp interpreter will mistake which argument you are passing the value -to. - -In the `forward-sentence' function, the regular expression will be -the value of the variable `sentence-end', namely: - - "[.?!][]\"')}]*\\($\\| \\| \\)[ - ]*" - -The limit of the search will be the end of the paragraph (since a -sentence cannot go beyond a paragraph). If the search fails, the -function will return `nil'; and the repeat count will be provided by -the argument to the `forward-sentence' function. - -`forward-sentence' -================== - -The command to move the cursor forward a sentence is a straightforward -illustration of how to use regular expression searches in Emacs Lisp. -Indeed, the function looks longer and more complicated than it is; -this is because the function is designed to go backwards as well as -forwards; and, optionally, over more than one sentence. The function -is usually bound to the key command `M-e'. - -Complete `forward-sentence' function definition ------------------------------------------------ - -Here is the code for `forward-sentence': - - (defun forward-sentence (&optional arg) - "Move forward to next sentence-end. With argument, repeat. - With negative argument, move backward repeatedly to sentence-beginning. - Sentence ends are identified by the value of sentence-end - treated as a regular expression. Also, every paragraph boundary - terminates sentences as well." - (interactive "p") - (or arg (setq arg 1)) - (while (< arg 0) - (let ((par-beg - (save-excursion (start-of-paragraph-text) (point)))) - (if (re-search-backward - (concat sentence-end "[^ \t\n]") par-beg t) - (goto-char (1- (match-end 0))) - (goto-char par-beg))) - (setq arg (1+ arg))) - (while (> arg 0) - (let ((par-end - (save-excursion (end-of-paragraph-text) (point)))) - (if (re-search-forward sentence-end par-end t) - (skip-chars-backward " \t\n") - (goto-char par-end))) - (setq arg (1- arg)))) - -The function looks long at first sight and it is best to look at its -skeleton first, and then its muscle. The way to see the skeleton is -to look at the expressions that start in the left-most columns: - - (defun forward-sentence (&optional arg) - "DOCUMENTATION..." - (interactive "p") - (or arg (setq arg 1)) - (while (< arg 0) - BODY-OF-WHILE-LOOP - (while (> arg 0) - BODY-OF-WHILE-LOOP - -This looks much simpler! The function definition consists of -documentation, an `interactive' expression, an `or' expression, and -`while' loops. - -Let's look at each of these parts in turn. - -We note that the documentation is thorough and understandable. - -The function has an `interactive "p"' declaration. This means that -the processed prefix argument, if any, is passed to the function as -its argument. (This will be a number.) If the function is not -passed an argument (it is optional) then the argument `arg' will be -bound to 1. When `forward-sentence' is called non-interactively -without an argument, `arg' is bound to `nil'. - -The `or' expression handles the prefix argument. What it does is -either leave the value of `arg' as it is, but only if `arg' is bound -to a value; or it sets the value of `arg' to 1, in the case when -`arg' is bound to `nil'. - -The `while' loops ------------------ - -Two `while' loops follow the `or' expression. The first `while' has -a true-or-false-test that tests true if the prefix argument for -`forward-sentence' is a negative number. This is for going -backwards. The body of this loop is similar to the body of the -second `while' clause, but it is not exactly the same. We will skip -this `while' loop and concentrate on the second `while' loop. - -The second `while' loop is for moving point forward. Its skeleton -looks like this: - - (while (> arg 0) ; true-or-false-test - (let VARLIST - (if (TRUE-OR-FALSE-TEST) - THEN-PART - ELSE-PART - (setq arg (1- arg)))) ; `while' loop decrementer - -The `while' loop is of the decrementing kind. (*Note A Loop with a -Decrementing Counter: Decrementing Loop.) It has a -true-or-false-test that tests true so long as the counter (in this -case, the variable `arg') is greater than zero; and it has a -decrementer that subtracts 1 from the value of the counter every time -the loop repeats. - -If no prefix argument is given to `forward-sentence', which is the -most common way the command is used, this `while' loop will run once, -since the value of `arg' will be 1. - -The body of the `while' loop consists of a `let' expression, which -creates and binds a local variable, and has, as its body, an `if' -expression. - -The body of the `while' loop looks like this: - - (let ((par-end - (save-excursion (end-of-paragraph-text) (point)))) - (if (re-search-forward sentence-end par-end t) - (skip-chars-backward " \t\n") - (goto-char par-end))) - -The `let' expression creates and binds the local variable `par-end'. -As we shall see, this local variable is designed to provide a bound -or limit to the regular expression search. If the search fails to -find a proper sentence ending in the paragraph, it will stop on -reaching the end of the paragraph. - -But first, let us examine how `par-end' is bound to the value of the -end of the paragraph. What happens is that the `let' sets the value -of `par-end' to the value returned when the Lisp interpreter -evaluates the expression - - (save-excursion (end-of-paragraph-text) (point)) - -In this expression, `(end-of-paragraph-text)' moves point to the end -of the paragraph, `(point)' returns the value of point, and then -`save-excursion' restores point to its original position. Thus, the -`let' binds `par-end' to the value returned by the `save-excursion' -expression, which is the position of the end of the paragraph. (The -`(end-of-paragraph-text)' function uses `forward-paragraph', which we -will discuss shortly.) - -Emacs next evaluates the body of the `let', which is an `if' -expression that looks like this: - - (if (re-search-forward sentence-end par-end t) ; if-part - (skip-chars-backward " \t\n") ; then-part - (goto-char par-end))) ; else-part - -The `if' tests whether its first argument is true and if so, -evaluates its then-part; otherwise, the Emacs Lisp interpreter -evaluates the else-part. The true-or-false-test of the `if' -expression is the regular expression search. - -It may seem odd to have what looks like the `real work' of the -`forward-sentence' function buried here, but this is a common way -this kind of operation is carried out in Lisp. - -The regular expression search ------------------------------ - -The `re-search-forward' function searches for the end of the -sentence, that is, for the pattern defined by the `sentence-end' -regular expression. If the pattern is found--if the end of the -sentence is found--then the `re-search-forward' function does two -things: - - 1. The `re-search-forward' function carries out a side effect, which - is to move point to the end of the occurrence found. - - 2. The `re-search-forward' function returns a value of true. This - is the value received by the `if', and means that the search was - successful. - -The side effect, the movement of point, is completed before the `if' -function is handed the value returned by the successful conclusion of -the search. - -When the `if' function receives the value of true from a successful -call to `re-search-forward', the `if' evaluates the then-part, which -is the expression `(skip-chars-backward " \t\n")'. This expression -moves backwards over any blank spaces, tabs or carriage returns until -a printed character is found and then leaves point after the -character. Since point has already been moved to the end of the -pattern that marks the end of the sentence, this action leaves point -right after the closing printed character of the sentence, which is -usually a period. - -On the other hand, if the `re-search-forward' function fails to find -a pattern marking the end of the sentence, the function returns -false. The false then causes the `if' to evaluate its third -argument, which is `(goto-char par-end)': it moves point to the end -of the paragraph. - -Regular expression searches are exceptionally useful and the pattern -illustrated by `re-search-forward', in which the search is the test -of an `if' expression, is handy. You will see or write code -incorporating this pattern often. - -`forward-paragraph': a Goldmine of Functions -============================================ - -The `forward-paragraph' function moves point forward to the end of -the paragraph. It is usually bound to `M-}' and makes use of a -number of functions that are important in themselves, including -`let*', `match-beginning', and `looking-at'. - -The function definition for `forward-paragraph' is considerably -longer than the function definition for `forward-sentence' because it -works with a paragraph, each line of which may begin with a fill -prefix. - -A fill prefix consists of a string of characters that are repeated at -the beginning of each line. For example, in Lisp code, it is a -convention to start each line of a paragraph-long comment with `;;; -'. In Text mode, four blank spaces make up another common fill -prefix, creating an indented paragraph. (*Note Fill Prefix: -(emacs)Fill Prefix, for more information about fill prefixes.) - -The existence of a fill prefix means that in addition to being able to -find the end of a paragraph whose lines begin on the left-most -column, the `forward-paragraph' function must be able to find the end -of a paragraph when all or many of the lines in the buffer begin with -the fill prefix. - -Moreover, it is sometimes practical to ignore a fill prefix that -exists, especially when blank lines separate paragraphs. This is an -added complication. - -Shortened `forward-paragraph' function definition -------------------------------------------------- - -Rather than print all of the `forward-paragraph' function, we will -only print parts of it. Read without preparation, the function can -be daunting! - -In outline, the function looks like this: - - (defun forward-paragraph (&optional arg) - "DOCUMENTATION..." - (interactive "p") - (or arg (setq arg 1)) - (let* - VARLIST - (while (< arg 0) ; backward-moving-code - ... - (setq arg (1+ arg))) - (while (> arg 0) ; forward-moving-code - ... - (setq arg (1- arg))))) - -The first parts of the function are routine: the function's argument -list consists of one optional argument. Documentation follows. - -The lower case `p' in the `interactive' declaration means that the -processed prefix argument, if any, is passed to the function. This -will be a number, and is the repeat count of how many paragraphs -point will move. The `or' expression in the next line handles the -common case when no argument is passed to the function, which occurs -if the function is called from other code rather than interactively. -This case was described earlier. (*Note The `forward-sentence' -function: forward-sentence.) Now we reach the end of the familiar -part of this function. - -The `let*' expression ---------------------- - -The next line of the `forward-paragraph' function begins a `let*' -expression. This is a different kind of expression than we have seen -so far. The symbol is `let*' not `let'. - -The `let*' special form is like `let' except that Emacs sets each -variable in sequence, one after another, and variables in the latter -part of the varlist can make use of the values to which Emacs set -variables in the earlier part of the varlist. - -In the `let*' expression in this function, Emacs binds two variables: -`fill-prefix-regexp' and `paragraph-separate'. The value to which -`paragraph-separate' is bound depends on the value of -`fill-prefix-regexp'. - -Let's look at each in turn. The symbol `fill-prefix-regexp' is set -to the value returned by evaluating the following list: - - (and fill-prefix - (not (equal fill-prefix "")) - (not paragraph-ignore-fill-prefix) - (regexp-quote fill-prefix)) - -This is an expression whose first element is the `and' special form. - -As we learned earlier (*note The `kill-new' function: kill-new -function.), the `and' special form evaluates each of its arguments -until one of the arguments returns a value of `nil', in which case -the `and' expression returns `nil'; however, if none of the arguments -returns a value of `nil', the value resulting from evaluating the -last argument is returned. (Since such a value is not `nil', it is -considered true in Lisp.) In other words, an `and' expression -returns a true value only if all its arguments are true. - -In this case, the variable `fill-prefix-regexp' is bound to a -non-`nil' value only if the following four expressions produce a true -(i.e., a non-`nil') value when they are evaluated; otherwise, -`fill-prefix-regexp' is bound to `nil'. - -`fill-prefix' - When this variable is evaluated, the value of the fill prefix, - if any, is returned. If there is no fill prefix, this variable - returns `nil'. - -`(not (equal fill-prefix "")' - This expression checks whether an existing fill prefix is an - empty string, that is, a string with no characters in it. An - empty string is not a useful fill prefix. - -`(not paragraph-ignore-fill-prefix)' - This expression returns `nil' if the variable - `paragraph-ignore-fill-prefix' has been turned on by being set - to a true value such as `t'. - -`(regexp-quote fill-prefix)' - This is the last argument to the `and' special form. If all the - arguments to the `and' are true, the value resulting from - evaluating this expression will be returned by the `and' - expression and bound to the variable `fill-prefix-regexp', - -The result of evaluating this `and' expression successfully is that -`fill-prefix-regexp' will be bound to the value of `fill-prefix' as -modified by the `regexp-quote' function. What `regexp-quote' does is -read a string and return a regular expression that will exactly match -the string and match nothing else. This means that -`fill-prefix-regexp' will be set to a value that will exactly match -the fill prefix if the fill prefix exists. Otherwise, the variable -will be set to `nil'. - -The second local variable in the `let*' expression is -`paragraph-separate'. It is bound to the value returned by -evaluating the expression: - - (if fill-prefix-regexp - (concat paragraph-separate - "\\|^" fill-prefix-regexp "[ \t]*$") - paragraph-separate))) - -This expression shows why `let*' rather than `let' was used. The -true-or-false-test for the `if' depends on whether the variable -`fill-prefix-regexp' evaluates to `nil' or some other value. - -If `fill-prefix-regexp' does not have a value, Emacs evaluates the -else-part of the `if' expression and binds `paragraph-separate' to -its local value. (`paragraph-separate' is a regular expression that -matches what separates paragraphs.) - -But if `fill-prefix-regexp' does have a value, Emacs evaluates the -then-part of the `if' expression and binds `paragraph-separate' to a -regular expression that includes the `fill-prefix-regexp' as part of -the pattern. - -Specifically, `paragraph-separate' is set to the original value of -the paragraph separate regular expression concatenated with an -alternative expression that consists of the `fill-prefix-regexp' -followed by a blank line. The `^' indicates that the -`fill-prefix-regexp' must begin a line, and the optional whitespace -to the end of the line is defined by `"[ \t]*$"'.) The `\\|' defines -this portion of the regexp as an alternative to `paragraph-separate'. - -Now we get into the body of the `let*'. The first part of the body -of the `let*' deals with the case when the function is given a -negative argument and is therefore moving backwards. We will skip -this section. - -The forward motion `while' loop -------------------------------- - -The second part of the body of the `let*' deals with forward motion. -It is a `while' loop that repeats itself so long as the value of -`arg' is greater than zero. In the most common use of the function, -the value of the argument is 1, so the body of the `while' loop is -evaluated exactly once, and the cursor moves forward one paragraph. - -This part handles three situations: when point is between paragraphs, -when point is within a paragraph and there is a fill prefix, and when -point is within a paragraph and there is no fill prefix. - -The `while' loop looks like this: - - (while (> arg 0) - (beginning-of-line) - - ;; between paragraphs - (while (prog1 (and (not (eobp)) - (looking-at paragraph-separate)) - (forward-line 1))) - - ;; within paragraphs, with a fill prefix - (if fill-prefix-regexp - ;; There is a fill prefix; it overrides paragraph-start. - (while (and (not (eobp)) - (not (looking-at paragraph-separate)) - (looking-at fill-prefix-regexp)) - (forward-line 1)) - - ;; within paragraphs, no fill prefix - (if (re-search-forward paragraph-start nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max)))) - - (setq arg (1- arg))) - -We can see immediately that this is a decrementing counter `while' -loop, using the expression `(setq arg (1- arg))' as the decrementer. - -The body of the loop consists of three expressions: - - ;; between paragraphs - (beginning-of-line) - (while - BODY-OF-WHILE) - - ;; within paragraphs, with fill prefix - (if TRUE-OR-FALSE-TEST - THEN-PART - - ;; within paragraphs, no fill prefix - ELSE-PART - -When the Emacs Lisp interpreter evaluates the body of the `while' -loop, the first thing it does is evaluate the `(beginning-of-line)' -expression and move point to the beginning of the line. Then there -is an inner `while' loop. This `while' loop is designed to move the -cursor out of the blank space between paragraphs, if it should happen -to be there. Finally, there is an `if' expression that actually -moves point to the end of the paragraph. - -Between paragraphs ------------------- - -First, let us look at the inner `while' loop. This loop handles the -case when point is between paragraphs; it uses three functions that -are new to us: `prog1', `eobp' and `looking-at'. - - * `prog1' is similar to the `progn' special form, except that - `prog1' evaluates its arguments in sequence and then returns the - value of its first argument as the value of the whole - expression. (`progn' returns the value of its last argument as - the value of the expression.) The second and subsequent - arguments to `prog1' are evaluated only for their side effects. - - * `eobp' is an abbreviation of `End Of Buffer P' and is a function - that returns true if point is at the end of the buffer. - - * `looking-at' is a function that returns true if the text - following point matches the regular expression passed - `looking-at' as its argument. - -The `while' loop we are studying looks like this: - - (while (prog1 (and (not (eobp)) - (looking-at paragraph-separate)) - (forward-line 1))) - -This is a `while' loop with no body! The true-or-false-test of the -loop is the expression: - - (prog1 (and (not (eobp)) - (looking-at paragraph-separate)) - (forward-line 1)) - -The first argument to the `prog1' is the `and' expression. It has -within in it a test of whether point is at the end of the buffer and -also a test of whether the pattern following point matches the regular -expression for separating paragraphs. - -If the cursor is not at the end of the buffer and if the characters -following the cursor mark the separation between two paragraphs, then -the `and' expression is true. After evaluating the `and' expression, -the Lisp interpreter evaluates the second argument to `prog1', which -is `forward-line'. This moves point forward one line. The value -returned by the `prog1' however, is the value of its first argument, -so the `while' loop continues so long as point is not at the end of -the buffer and is between paragraphs. When, finally, point is moved -to a paragraph, the `and' expression tests false. Note however, that -the `forward-line' command is carried out anyhow. This means that -when point is moved from between paragraphs to a paragraph, it is left -at the beginning of the second line of the paragraph. - -Within paragraphs ------------------ - -The next expression in the outer `while' loop is an `if' expression. -The Lisp interpreter evaluates the then-part of the `if' when the -`fill-prefix-regexp' variable has a value other than `nil', and it -evaluates the else-part when the value of `if fill-prefix-regexp' is -`nil', that is, when there is no fill prefix. - -No fill prefix --------------- - -It is simplest to look at the code for the case when there is no fill -prefix first. This code consists of yet another inner `if' -expression, and reads as follows: - - (if (re-search-forward paragraph-start nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max))) - -This expression actually does the work that most people think of as -the primary purpose of the `forward-paragraph' command: it causes a -regular expression search to occur that searches forward to the start -of the next paragraph and if it is found, moves point there; but if -the start of another paragraph if not found, it moves point to the -end of the accessible region of the buffer. - -The only unfamiliar part of this is the use of `match-beginning'. -This is another function that is new to us. The `match-beginning' -function returns a number specifying the location of the start of the -text that was matched by the last regular expression search. - -The `match-beginning' function is used here because of a -characteristic of a forward search: a successful forward search, -regardless of whether it is a plain search or a regular expression -search, will move point to the end of the text that is found. In this -case, a successful search will move point to the end of the pattern -for `paragraph-start', which will be the beginning of the next -paragraph rather than the end of the current one. - -However, we want to put point at the end of the current paragraph, -not at the beginning of the next one. The two positions may be -different, because there may be several blank lines between -paragraphs. - -When given an argument of 0, `match-beginning' returns the position -that is the start of the text that the most recent regular expression -search matched. In this case, the most recent regular expression -search is the one looking for `paragraph-start', so `match-beginning' -returns the beginning position of the pattern, rather than the end of -the pattern. The beginning position is the end of the paragraph. - -(Incidentally, when passed a positive number as an argument, the -`match-beginning' function will place point at that parenthesized -expression in the last regular expression. It is a useful function.) - -With a fill prefix ------------------- - -The inner `if' expression just discussed is the else-part of an -enclosing `if' expression which tests whether there is a fill prefix. -If there is a fill prefix, the then-part of this `if' is evaluated. -It looks like this: - - (while (and (not (eobp)) - (not (looking-at paragraph-separate)) - (looking-at fill-prefix-regexp)) - (forward-line 1)) - -What this expression does is move point forward line by line so long -as three conditions are true: - - 1. Point is not at the end of the buffer. - - 2. The text following point does not separate paragraphs. - - 3. The pattern following point is the fill prefix regular - expression. - -The last condition may be puzzling, until you remember that point was -moved to the beginning of the line early in the `forward-paragraph' -function. This means that if the text has a fill prefix, the -`looking-at' function will see it. - -Summary -------- - -In summary, when moving forward, the `forward-paragraph' function -does the following: - - * Move point to the beginning of the line. - - * Skip over lines between paragraphs. - - * Check whether there is a fill prefix, and if there is: - - -- Go forward line by line so long as the line is not a - paragraph separating line. - - * But if there is no fill prefix, - - -- Search for the next paragraph start pattern. - - -- Go to the beginning of the paragraph start pattern, which - will be the end of the previous paragraph. - - -- Or else go to the end of the accessible portion of the - buffer. - -For review, here is the code we have just been discussing, formatted -for clarity: - - (interactive "p") - (or arg (setq arg 1)) - (let* ( - (fill-prefix-regexp - (and fill-prefix (not (equal fill-prefix "")) - (not paragraph-ignore-fill-prefix) - (regexp-quote fill-prefix))) - - (paragraph-separate - (if fill-prefix-regexp - (concat paragraph-separate - "\\|^" - fill-prefix-regexp - "[ \t]*$") - paragraph-separate))) - - OMITTED-BACKWARD-MOVING-CODE ... - - (while (> arg 0) ; forward-moving-code - (beginning-of-line) - - (while (prog1 (and (not (eobp)) - (looking-at paragraph-separate)) - (forward-line 1))) - - (if fill-prefix-regexp - (while (and (not (eobp)) ; then-part - (not (looking-at paragraph-separate)) - (looking-at fill-prefix-regexp)) - (forward-line 1)) - ; else-part: the inner-if - (if (re-search-forward paragraph-start nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max)))) - - (setq arg (1- arg))))) ; decrementer - -The full definition for the `forward-paragraph' function not only -includes this code for going forwards, but also code for going -backwards. - -If you are reading this inside of GNU Emacs and you want to see the -whole function, you can type `C-h f' (`describe-function') and the -name of the function. This gives you the function documentation and -the name of the library containing the function's source. Place -point over the name of the library and press the RET key; you will be -taken directly to the source. (Be sure to install your sources! -Without them, you are like a person who tries to drive a car with his -eyes shut!) - -Or - a good habit to get into - you can type `M-.' (`find-tag') and -the name of the function when prompted for it. This will take you -directly to the source. If the `find-tag' function first asks you -for the name of a `TAGS' table, give it the name of the `TAGS' file -such as `/usr/local/share/emacs/21.0.100/lisp/TAGS'. (The exact path -to your `TAGS' file depends on how your copy of Emacs was installed.) - -You can also create your own `TAGS' file for directories that lack -one. *Note Create Your Own `TAGS' File: etags. - -Create Your Own `TAGS' File -=========================== - -The `M-.' (`find-tag') command takes you directly to the source for a -function, variable, node, or other source. The function depends on -tags tables to tell it where to go. - -You often need to build and install tags tables yourself. They are -not built automatically. A tags table is called a `TAGS' file; the -name is in upper case letters. - -You can create a `TAGS' file by calling the `etags' program that -comes as a part of the Emacs distribution. Usually, `etags' is -compiled and installed when Emacs is built. (`etags' is not an Emacs -Lisp function or a part of Emacs; it is a C program.) - -To create a `TAGS' file, first switch to the directory in which you -want to create the file. In Emacs you can do this with the `M-x cd' -command, or by visiting a file in the directory, or by listing the -directory with `C-x d' (`dired'). Then run the compile command, with -`etags *.el' as the command to execute - - M-x compile RET etags *.el RET - -to create a `TAGS' file. - -For example, if you have a large number of files in your `~/emacs' -directory, as I do--I have 137 `.el' files in it, of which I load -12--you can create a `TAGS' file for the Emacs Lisp files in that -directory. - -The `etags' program takes all the usual shell `wildcards'. For -example, if you have two directories for which you want a single -`TAGS file', type `etags *.el ../elisp/*.el', where `../elisp/' is -the second directory: - - M-x compile RET etags *.el ../elisp/*.el RET - -Type - - M-x compile RET etags --help RET - -to see a list of the options accepted by `etags' as well as a list of -supported languages. - -The `etags' program handles more than 20 languages, including Emacs -Lisp, Common Lisp, Scheme, C, C++, Ada, Fortran, Java, LaTeX, Pascal, -Perl, Python, Texinfo, makefiles, and most assemblers. The program -has no switches for specifying the language; it recognizes the -language in an input file according to its file name and contents. - -`etags' is very helpful when you are writing code yourself and want -to refer back to functions you have already written. Just run -`etags' again at intervals as you write new functions, so they become -part of the `TAGS' file. - -If you think an appropriate `TAGS' file already exists for what you -want, but do not know where it is, you can use the `locate' program -to attempt to find it. - -Type `M-x locate RET TAGS RET' and Emacs will list for you the full -path names of all your `TAGS' files. On my system, this command -lists 34 `TAGS' files. On the other hand, a `plain vanilla' system I -recently installed did not contain any `TAGS' files. - -If the tags table you want has been created, you can use the `M-x -visit-tags-table' command to specify it. Otherwise, you will need to -create the tag table yourself and then use `M-x visit-tags-table'. - -Building Tags in the Emacs sources -.................................. - -The GNU Emacs sources come with a `Makefile' that contains a -sophisticated `etags' command that creates, collects, and merges tags -tables from all over the Emacs sources and puts the information into -one `TAGS' file in the `src/' directory below the top level of your -Emacs source directory. - -To build this `TAGS' file, go to the top level of your Emacs source -directory and run the compile command `make tags': - - M-x compile RET make tags RET - -(The `make tags' command works well with the GNU Emacs sources, as -well as with some other source packages.) - -For more information, see *Note Tag Tables: (emacs)Tags. - -Review -====== - -Here is a brief summary of some recently introduced functions. - -`while' - Repeatedly evaluate the body of the expression so long as the - first element of the body tests true. Then return `nil'. (The - expression is evaluated only for its side effects.) - - For example: - - (let ((foo 2)) - (while (> foo 0) - (insert (format "foo is %d.\n" foo)) - (setq foo (1- foo)))) - - => foo is 2. - foo is 1. - nil - - (The `insert' function inserts its arguments at point; the - `format' function returns a string formatted from its arguments - the way `message' formats its arguments; `\n' produces a new - line.) - -`re-search-forward' - Search for a pattern, and if the pattern is found, move point to - rest just after it. - - Takes four arguments, like `search-forward': - - 1. A regular expression that specifies the pattern to search - for. - - 2. Optionally, the limit of the search. - - 3. Optionally, what to do if the search fails, return `nil' or - an error message. - - 4. Optionally, how many times to repeat the search; if - negative, the search goes backwards. - -`let*' - Bind some variables locally to particular values, and then - evaluate the remaining arguments, returning the value of the - last one. While binding the local variables, use the local - values of variables bound earlier, if any. - - For example: - - (let* ((foo 7) - (bar (* 3 foo))) - (message "`bar' is %d." bar)) - => `bar' is 21. - -`match-beginning' - Return the position of the start of the text found by the last - regular expression search. - -`looking-at' - Return `t' for true if the text after point matches the argument, - which should be a regular expression. - -`eobp' - Return `t' for true if point is at the end of the accessible part - of a buffer. The end of the accessible part is the end of the - buffer if the buffer is not narrowed; it is the end of the - narrowed part if the buffer is narrowed. - -`prog1' - Evaluate each argument in sequence and then return the value of - the _first_. - - For example: - - (prog1 1 2 3 4) - => 1 - -Exercises with `re-search-forward' -================================== - - * Write a function to search for a regular expression that matches - two or more blank lines in sequence. - - * Write a function to search for duplicated words, such as `the - the'. *Note Syntax of Regular Expressions: (emacs)Regexps, for - information on how to write a regexp (a regular expression) to - match a string that is composed of two identical halves. You - can devise several regexps; some are better than others. The - function I use is described in an appendix, along with several - regexps. *Note `the-the' Duplicated Words Function: the-the. - -Counting: Repetition and Regexps -******************************** - -Repetition and regular expression searches are powerful tools that you -often use when you write code in Emacs Lisp. This chapter illustrates -the use of regular expression searches through the construction of -word count commands using `while' loops and recursion. - -Counting words -============== - -The standard Emacs distribution contains a function for counting the -number of lines within a region. However, there is no corresponding -function for counting words. - -Certain types of writing ask you to count words. Thus, if you write -an essay, you may be limited to 800 words; if you write a novel, you -may discipline yourself to write 1000 words a day. It seems odd to me -that Emacs lacks a word count command. Perhaps people use Emacs -mostly for code or types of documentation that do not require word -counts; or perhaps they restrict themselves to the operating system -word count command, `wc'. Alternatively, people may follow the -publishers' convention and compute a word count by dividing the -number of characters in a document by five. In any event, here are -commands to count words. - -The `count-words-region' Function -================================= - -A word count command could count words in a line, paragraph, region, -or buffer. What should the command cover? You could design the -command to count the number of words in a complete buffer. However, -the Emacs tradition encourages flexibility--you may want to count -words in just a section, rather than all of a buffer. So it makes -more sense to design the command to count the number of words in a -region. Once you have a `count-words-region' command, you can, if -you wish, count words in a whole buffer by marking it with `C-x h' -(`mark-whole-buffer'). - -Clearly, counting words is a repetitive act: starting from the -beginning of the region, you count the first word, then the second -word, then the third word, and so on, until you reach the end of the -region. This means that word counting is ideally suited to recursion -or to a `while' loop. - -Designing `count-words-region' ------------------------------- - -First, we will implement the word count command with a `while' loop, -then with recursion. The command will, of course, be interactive. - -The template for an interactive function definition is, as always: - - (defun NAME-OF-FUNCTION (ARGUMENT-LIST) - "DOCUMENTATION..." - (INTERACTIVE-EXPRESSION...) - BODY...) - -What we need to do is fill in the slots. - -The name of the function should be self-explanatory and similar to the -existing `count-lines-region' name. This makes the name easier to -remember. `count-words-region' is a good choice. - -The function counts words within a region. This means that the -argument list must contain symbols that are bound to the two -positions, the beginning and end of the region. These two positions -can be called `beginning' and `end' respectively. The first line of -the documentation should be a single sentence, since that is all that -is printed as documentation by a command such as `apropos'. The -interactive expression will be of the form `(interactive "r")', since -that will cause Emacs to pass the beginning and end of the region to -the function's argument list. All this is routine. - -The body of the function needs to be written to do three tasks: -first, to set up conditions under which the `while' loop can count -words, second, to run the `while' loop, and third, to send a message -to the user. - -When a user calls `count-words-region', point may be at the beginning -or the end of the region. However, the counting process must start -at the beginning of the region. This means we will want to put point -there if it is not already there. Executing `(goto-char beginning)' -ensures this. Of course, we will want to return point to its -expected position when the function finishes its work. For this -reason, the body must be enclosed in a `save-excursion' expression. - -The central part of the body of the function consists of a `while' -loop in which one expression jumps point forward word by word, and -another expression counts those jumps. The true-or-false-test of the -`while' loop should test true so long as point should jump forward, -and false when point is at the end of the region. - -We could use `(forward-word 1)' as the expression for moving point -forward word by word, but it is easier to see what Emacs identifies -as a `word' if we use a regular expression search. - -A regular expression search that finds the pattern for which it is -searching leaves point after the last character matched. This means -that a succession of successful word searches will move point forward -word by word. - -As a practical matter, we want the regular expression search to jump -over whitespace and punctuation between words as well as over the -words themselves. A regexp that refuses to jump over interword -whitespace would never jump more than one word! This means that the -regexp should include the whitespace and punctuation that follows a -word, if any, as well as the word itself. (A word may end a buffer -and not have any following whitespace or punctuation, so that part of -the regexp must be optional.) - -Thus, what we want for the regexp is a pattern defining one or more -word constituent characters followed, optionally, by one or more -characters that are not word constituents. The regular expression for -this is: - - \w+\W* - -The buffer's syntax table determines which characters are and are not -word constituents. (*Note What Constitutes a Word or Symbol?: -Syntax, for more about syntax. Also, see *Note Syntax: -(emacs)Syntax, and *Note Syntax Tables: (elisp)Syntax Tables.) - -The search expression looks like this: - - (re-search-forward "\\w+\\W*") - -(Note that paired backslashes precede the `w' and `W'. A single -backslash has special meaning to the Emacs Lisp interpreter. It -indicates that the following character is interpreted differently than -usual. For example, the two characters, `\n', stand for `newline', -rather than for a backslash followed by `n'. Two backslashes in a -row stand for an ordinary, `unspecial' backslash.) - -We need a counter to count how many words there are; this variable -must first be set to 0 and then incremented each time Emacs goes -around the `while' loop. The incrementing expression is simply: - - (setq count (1+ count)) - -Finally, we want to tell the user how many words there are in the -region. The `message' function is intended for presenting this kind -of information to the user. The message has to be phrased so that it -reads properly regardless of how many words there are in the region: -we don't want to say that "there are 1 words in the region". The -conflict between singular and plural is ungrammatical. We can solve -this problem by using a conditional expression that evaluates -different messages depending on the number of words in the region. -There are three possibilities: no words in the region, one word in the -region, and more than one word. This means that the `cond' special -form is appropriate. - -All this leads to the following function definition: - - ;;; First version; has bugs! - (defun count-words-region (beginning end) - "Print number of words in the region. - Words are defined as at least one word-constituent - character followed by at least one character that - is not a word-constituent. The buffer's syntax - table determines which characters these are." - (interactive "r") - (message "Counting words in region ... ") - - ;;; 1. Set up appropriate conditions. - (save-excursion - (goto-char beginning) - (let ((count 0)) - - ;;; 2. Run the while loop. - (while (< (point) end) - (re-search-forward "\\w+\\W*") - (setq count (1+ count))) - - ;;; 3. Send a message to the user. - (cond ((zerop count) - (message - "The region does NOT have any words.")) - ((= 1 count) - (message - "The region has 1 word.")) - (t - (message - "The region has %d words." count)))))) - -As written, the function works, but not in all circumstances. - -The Whitespace Bug in `count-words-region' ------------------------------------------- - -The `count-words-region' command described in the preceding section -has two bugs, or rather, one bug with two manifestations. First, if -you mark a region containing only whitespace in the middle of some -text, the `count-words-region' command tells you that the region -contains one word! Second, if you mark a region containing only -whitespace at the end of the buffer or the accessible portion of a -narrowed buffer, the command displays an error message that looks -like this: - - Search failed: "\\w+\\W*" - -If you are reading this in Info in GNU Emacs, you can test for these -bugs yourself. - -First, evaluate the function in the usual manner to install it. Here -is a copy of the definition. Place your cursor after the closing -parenthesis and type `C-x C-e' to install it. - - ;; First version; has bugs! - (defun count-words-region (beginning end) - "Print number of words in the region. - Words are defined as at least one word-constituent character followed - by at least one character that is not a word-constituent. The buffer's - syntax table determines which characters these are." - (interactive "r") - (message "Counting words in region ... ") - - ;;; 1. Set up appropriate conditions. - (save-excursion - (goto-char beginning) - (let ((count 0)) - - ;;; 2. Run the while loop. - (while (< (point) end) - (re-search-forward "\\w+\\W*") - (setq count (1+ count))) - - ;;; 3. Send a message to the user. - (cond ((zerop count) - (message "The region does NOT have any words.")) - ((= 1 count) (message "The region has 1 word.")) - (t (message "The region has %d words." count)))))) - -If you wish, you can also install this keybinding by evaluating it: - - (global-set-key "\C-c=" 'count-words-region) - -To conduct the first test, set mark and point to the beginning and end -of the following line and then type `C-c =' (or `M-x -count-words-region' if you have not bound `C-c ='): - - one two three - -Emacs will tell you, correctly, that the region has three words. - -Repeat the test, but place mark at the beginning of the line and place -point just _before_ the word `one'. Again type the command `C-c =' -(or `M-x count-words-region'). Emacs should tell you that the region -has no words, since it is composed only of the whitespace at the -beginning of the line. But instead Emacs tells you that the region -has one word! - -For the third test, copy the sample line to the end of the -`*scratch*' buffer and then type several spaces at the end of the -line. Place mark right after the word `three' and point at the end -of line. (The end of the line will be the end of the buffer.) Type -`C-c =' (or `M-x count-words-region') as you did before. Again, -Emacs should tell you that the region has no words, since it is -composed only of the whitespace at the end of the line. Instead, -Emacs displays an error message saying `Search failed'. - -The two bugs stem from the same problem. - -Consider the first manifestation of the bug, in which the command -tells you that the whitespace at the beginning of the line contains -one word. What happens is this: The `M-x count-words-region' command -moves point to the beginning of the region. The `while' tests -whether the value of point is smaller than the value of `end', which -it is. Consequently, the regular expression search looks for and -finds the first word. It leaves point after the word. `count' is -set to one. The `while' loop repeats; but this time the value of -point is larger than the value of `end', the loop is exited; and the -function displays a message saying the number of words in the region -is one. In brief, the regular expression search looks for and finds -the word even though it is outside the marked region. - -In the second manifestation of the bug, the region is whitespace at -the end of the buffer. Emacs says `Search failed'. What happens is -that the true-or-false-test in the `while' loop tests true, so the -search expression is executed. But since there are no more words in -the buffer, the search fails. - -In both manifestations of the bug, the search extends or attempts to -extend outside of the region. - -The solution is to limit the search to the region--this is a fairly -simple action, but as you may have come to expect, it is not quite as -simple as you might think. - -As we have seen, the `re-search-forward' function takes a search -pattern as its first argument. But in addition to this first, -mandatory argument, it accepts three optional arguments. The optional -second argument bounds the search. The optional third argument, if -`t', causes the function to return `nil' rather than signal an error -if the search fails. The optional fourth argument is a repeat count. -(In Emacs, you can see a function's documentation by typing `C-h f', -the name of the function, and then <RET>.) - -In the `count-words-region' definition, the value of the end of the -region is held by the variable `end' which is passed as an argument -to the function. Thus, we can add `end' as an argument to the -regular expression search expression: - - (re-search-forward "\\w+\\W*" end) - -However, if you make only this change to the `count-words-region' -definition and then test the new version of the definition on a -stretch of whitespace, you will receive an error message saying -`Search failed'. - -What happens is this: the search is limited to the region, and fails -as you expect because there are no word-constituent characters in the -region. Since it fails, we receive an error message. But we do not -want to receive an error message in this case; we want to receive the -message that "The region does NOT have any words." - -The solution to this problem is to provide `re-search-forward' with a -third argument of `t', which causes the function to return `nil' -rather than signal an error if the search fails. - -However, if you make this change and try it, you will see the message -"Counting words in region ... " and ... you will keep on seeing that -message ..., until you type `C-g' (`keyboard-quit'). - -Here is what happens: the search is limited to the region, as before, -and it fails because there are no word-constituent characters in the -region, as expected. Consequently, the `re-search-forward' -expression returns `nil'. It does nothing else. In particular, it -does not move point, which it does as a side effect if it finds the -search target. After the `re-search-forward' expression returns -`nil', the next expression in the `while' loop is evaluated. This -expression increments the count. Then the loop repeats. The -true-or-false-test tests true because the value of point is still less -than the value of end, since the `re-search-forward' expression did -not move point. ... and the cycle repeats ... - -The `count-words-region' definition requires yet another -modification, to cause the true-or-false-test of the `while' loop to -test false if the search fails. Put another way, there are two -conditions that must be satisfied in the true-or-false-test before the -word count variable is incremented: point must still be within the -region and the search expression must have found a word to count. - -Since both the first condition and the second condition must be true -together, the two expressions, the region test and the search -expression, can be joined with an `and' special form and embedded in -the `while' loop as the true-or-false-test, like this: - - (and (< (point) end) (re-search-forward "\\w+\\W*" end t)) - -(*Note forward-paragraph::, for information about `and'.) - -The `re-search-forward' expression returns `t' if the search succeeds -and as a side effect moves point. Consequently, as words are found, -point is moved through the region. When the search expression fails -to find another word, or when point reaches the end of the region, -the true-or-false-test tests false, the `while' loop exists, and the -`count-words-region' function displays one or other of its messages. - -After incorporating these final changes, the `count-words-region' -works without bugs (or at least, without bugs that I have found!). -Here is what it looks like: - - ;;; Final version: `while' - (defun count-words-region (beginning end) - "Print number of words in the region." - (interactive "r") - (message "Counting words in region ... ") - - ;;; 1. Set up appropriate conditions. - (save-excursion - (let ((count 0)) - (goto-char beginning) - - ;;; 2. Run the while loop. - (while (and (< (point) end) - (re-search-forward "\\w+\\W*" end t)) - (setq count (1+ count))) - - ;;; 3. Send a message to the user. - (cond ((zerop count) - (message - "The region does NOT have any words.")) - ((= 1 count) - (message - "The region has 1 word.")) - (t - (message - "The region has %d words." count)))))) - -Count Words Recursively -======================= - -You can write the function for counting words recursively as well as -with a `while' loop. Let's see how this is done. - -First, we need to recognize that the `count-words-region' function -has three jobs: it sets up the appropriate conditions for counting to -occur; it counts the words in the region; and it sends a message to -the user telling how many words there are. - -If we write a single recursive function to do everything, we will -receive a message for every recursive call. If the region contains 13 -words, we will receive thirteen messages, one right after the other. -We don't want this! Instead, we must write two functions to do the -job, one of which (the recursive function) will be used inside of the -other. One function will set up the conditions and display the -message; the other will return the word count. - -Let us start with the function that causes the message to be -displayed. We can continue to call this `count-words-region'. - -This is the function that the user will call. It will be interactive. -Indeed, it will be similar to our previous versions of this function, -except that it will call `recursive-count-words' to determine how -many words are in the region. - -We can readily construct a template for this function, based on our -previous versions: - - ;; Recursive version; uses regular expression search - (defun count-words-region (beginning end) - "DOCUMENTATION..." - (INTERACTIVE-EXPRESSION...) - - ;;; 1. Set up appropriate conditions. - (EXPLANATORY MESSAGE) - (SET-UP FUNCTIONS... - - ;;; 2. Count the words. - RECURSIVE CALL - - ;;; 3. Send a message to the user. - MESSAGE PROVIDING WORD COUNT)) - -The definition looks straightforward, except that somehow the count -returned by the recursive call must be passed to the message -displaying the word count. A little thought suggests that this can be -done by making use of a `let' expression: we can bind a variable in -the varlist of a `let' expression to the number of words in the -region, as returned by the recursive call; and then the `cond' -expression, using binding, can display the value to the user. - -Often, one thinks of the binding within a `let' expression as somehow -secondary to the `primary' work of a function. But in this case, -what you might consider the `primary' job of the function, counting -words, is done within the `let' expression. - -Using `let', the function definition looks like this: - - (defun count-words-region (beginning end) - "Print number of words in the region." - (interactive "r") - - ;;; 1. Set up appropriate conditions. - (message "Counting words in region ... ") - (save-excursion - (goto-char beginning) - - ;;; 2. Count the words. - (let ((count (recursive-count-words end))) - - ;;; 3. Send a message to the user. - (cond ((zerop count) - (message - "The region does NOT have any words.")) - ((= 1 count) - (message - "The region has 1 word.")) - (t - (message - "The region has %d words." count)))))) - -Next, we need to write the recursive counting function. - -A recursive function has at least three parts: the `do-again-test', -the `next-step-expression', and the recursive call. - -The do-again-test determines whether the function will or will not be -called again. Since we are counting words in a region and can use a -function that moves point forward for every word, the do-again-test -can check whether point is still within the region. The do-again-test -should find the value of point and determine whether point is before, -at, or after the value of the end of the region. We can use the -`point' function to locate point. Clearly, we must pass the value of -the end of the region to the recursive counting function as an -argument. - -In addition, the do-again-test should also test whether the search -finds a word. If it does not, the function should not call itself -again. - -The next-step-expression changes a value so that when the recursive -function is supposed to stop calling itself, it stops. More -precisely, the next-step-expression changes a value so that at the -right time, the do-again-test stops the recursive function from -calling itself again. In this case, the next-step-expression can be -the expression that moves point forward, word by word. - -The third part of a recursive function is the recursive call. - -Somewhere, also, we also need a part that does the `work' of the -function, a part that does the counting. A vital part! - -But already, we have an outline of the recursive counting function: - - (defun recursive-count-words (region-end) - "DOCUMENTATION..." - DO-AGAIN-TEST - NEXT-STEP-EXPRESSION - RECURSIVE CALL) - -Now we need to fill in the slots. Let's start with the simplest cases -first: if point is at or beyond the end of the region, there cannot -be any words in the region, so the function should return zero. -Likewise, if the search fails, there are no words to count, so the -function should return zero. - -On the other hand, if point is within the region and the search -succeeds, the function should call itself again. - -Thus, the do-again-test should look like this: - - (and (< (point) region-end) - (re-search-forward "\\w+\\W*" region-end t)) - -Note that the search expression is part of the do-again-test--the -function returns `t' if its search succeeds and `nil' if it fails. -(*Note The Whitespace Bug in `count-words-region': Whitespace Bug, -for an explanation of how `re-search-forward' works.) - -The do-again-test is the true-or-false test of an `if' clause. -Clearly, if the do-again-test succeeds, the then-part of the `if' -clause should call the function again; but if it fails, the else-part -should return zero since either point is outside the region or the -search failed because there were no words to find. - -But before considering the recursive call, we need to consider the -next-step-expression. What is it? Interestingly, it is the search -part of the do-again-test. - -In addition to returning `t' or `nil' for the do-again-test, -`re-search-forward' moves point forward as a side effect of a -successful search. This is the action that changes the value of -point so that the recursive function stops calling itself when point -completes its movement through the region. Consequently, the -`re-search-forward' expression is the next-step-expression. - -In outline, then, the body of the `recursive-count-words' function -looks like this: - - (if DO-AGAIN-TEST-AND-NEXT-STEP-COMBINED - ;; then - RECURSIVE-CALL-RETURNING-COUNT - ;; else - RETURN-ZERO) - -How to incorporate the mechanism that counts? - -If you are not used to writing recursive functions, a question like -this can be troublesome. But it can and should be approached -systematically. - -We know that the counting mechanism should be associated in some way -with the recursive call. Indeed, since the next-step-expression moves -point forward by one word, and since a recursive call is made for -each word, the counting mechanism must be an expression that adds one -to the value returned by a call to `recursive-count-words'. - -Consider several cases: - - * If there are two words in the region, the function should return - a value resulting from adding one to the value returned when it - counts the first word, plus the number returned when it counts - the remaining words in the region, which in this case is one. - - * If there is one word in the region, the function should return a - value resulting from adding one to the value returned when it - counts that word, plus the number returned when it counts the - remaining words in the region, which in this case is zero. - - * If there are no words in the region, the function should return - zero. - -From the sketch we can see that the else-part of the `if' returns -zero for the case of no words. This means that the then-part of the -`if' must return a value resulting from adding one to the value -returned from a count of the remaining words. - -The expression will look like this, where `1+' is a function that -adds one to its argument. - - (1+ (recursive-count-words region-end)) - -The whole `recursive-count-words' function will then look like this: - - (defun recursive-count-words (region-end) - "DOCUMENTATION..." - - ;;; 1. do-again-test - (if (and (< (point) region-end) - (re-search-forward "\\w+\\W*" region-end t)) - - ;;; 2. then-part: the recursive call - (1+ (recursive-count-words region-end)) - - ;;; 3. else-part - 0)) - -Let's examine how this works: - -If there are no words in the region, the else part of the `if' -expression is evaluated and consequently the function returns zero. - -If there is one word in the region, the value of point is less than -the value of `region-end' and the search succeeds. In this case, the -true-or-false-test of the `if' expression tests true, and the -then-part of the `if' expression is evaluated. The counting -expression is evaluated. This expression returns a value (which will -be the value returned by the whole function) that is the sum of one -added to the value returned by a recursive call. - -Meanwhile, the next-step-expression has caused point to jump over the -first (and in this case only) word in the region. This means that -when `(recursive-count-words region-end)' is evaluated a second time, -as a result of the recursive call, the value of point will be equal -to or greater than the value of region end. So this time, -`recursive-count-words' will return zero. The zero will be added to -one, and the original evaluation of `recursive-count-words' will -return one plus zero, which is one, which is the correct amount. - -Clearly, if there are two words in the region, the first call to -`recursive-count-words' returns one added to the value returned by -calling `recursive-count-words' on a region containing the remaining -word--that is, it adds one to one, producing two, which is the -correct amount. - -Similarly, if there are three words in the region, the first call to -`recursive-count-words' returns one added to the value returned by -calling `recursive-count-words' on a region containing the remaining -two words--and so on and so on. - -With full documentation the two functions look like this: - -The recursive function: - - (defun recursive-count-words (region-end) - "Number of words between point and REGION-END." - - ;;; 1. do-again-test - (if (and (< (point) region-end) - (re-search-forward "\\w+\\W*" region-end t)) - - ;;; 2. then-part: the recursive call - (1+ (recursive-count-words region-end)) - - ;;; 3. else-part - 0)) - -The wrapper: - - ;;; Recursive version - (defun count-words-region (beginning end) - "Print number of words in the region. - - Words are defined as at least one word-constituent - character followed by at least one character that is - not a word-constituent. The buffer's syntax table - determines which characters these are." - (interactive "r") - (message "Counting words in region ... ") - (save-excursion - (goto-char beginning) - (let ((count (recursive-count-words end))) - (cond ((zerop count) - (message - "The region does NOT have any words.")) - ((= 1 count) - (message "The region has 1 word.")) - (t - (message - "The region has %d words." count)))))) - -Exercise: Counting Punctuation -============================== - -Using a `while' loop, write a function to count the number of -punctuation marks in a region--period, comma, semicolon, colon, -exclamation mark, and question mark. Do the same using recursion. - -Counting Words in a `defun' -*************************** - -Our next project is to count the number of words in a function -definition. Clearly, this can be done using some variant of -`count-word-region'. *Note Counting Words: Repetition and Regexps: -Counting Words. If we are just going to count the words in one -definition, it is easy enough to mark the definition with the `C-M-h' -(`mark-defun') command, and then call `count-word-region'. - -However, I am more ambitious: I want to count the words and symbols in -every definition in the Emacs sources and then print a graph that -shows how many functions there are of each length: how many contain 40 -to 49 words or symbols, how many contain 50 to 59 words or symbols, -and so on. I have often been curious how long a typical function is, -and this will tell. - -Divide and Conquer -================== - -Described in one phrase, the histogram project is daunting; but -divided into numerous small steps, each of which we can take one at a -time, the project becomes less fearsome. Let us consider what the -steps must be: - - * First, write a function to count the words in one definition. - This includes the problem of handling symbols as well as words. - - * Second, write a function to list the numbers of words in each - function in a file. This function can use the - `count-words-in-defun' function. - - * Third, write a function to list the numbers of words in each - function in each of several files. This entails automatically - finding the various files, switching to them, and counting the - words in the definitions within them. - - * Fourth, write a function to convert the list of numbers that we - created in step three to a form that will be suitable for - printing as a graph. - - * Fifth, write a function to print the results as a graph. - -This is quite a project! But if we take each step slowly, it will not -be difficult. - -What to Count? -============== - -When we first start thinking about how to count the words in a -function definition, the first question is (or ought to be) what are -we going to count? When we speak of `words' with respect to a Lisp -function definition, we are actually speaking, in large part, of -`symbols'. For example, the following `multiply-by-seven' function -contains the five symbols `defun', `multiply-by-seven', `number', -`*', and `7'. In addition, in the documentation string, it contains -the four words `Multiply', `NUMBER', `by', and `seven'. The symbol -`number' is repeated, so the definition contains a total of ten words -and symbols. - - (defun multiply-by-seven (number) - "Multiply NUMBER by seven." - (* 7 number)) - -However, if we mark the `multiply-by-seven' definition with `C-M-h' -(`mark-defun'), and then call `count-words-region' on it, we will -find that `count-words-region' claims the definition has eleven -words, not ten! Something is wrong! - -The problem is twofold: `count-words-region' does not count the `*' -as a word, and it counts the single symbol, `multiply-by-seven', as -containing three words. The hyphens are treated as if they were -interword spaces rather than intraword connectors: -`multiply-by-seven' is counted as if it were written `multiply by -seven'. - -The cause of this confusion is the regular expression search within -the `count-words-region' definition that moves point forward word by -word. In the canonical version of `count-words-region', the regexp -is: - - "\\w+\\W*" - -This regular expression is a pattern defining one or more word -constituent characters possibly followed by one or more characters -that are not word constituents. What is meant by `word constituent -characters' brings us to the issue of syntax, which is worth a section -of its own. - -What Constitutes a Word or Symbol? -================================== - -Emacs treats different characters as belonging to different "syntax -categories". For example, the regular expression, `\\w+', is a -pattern specifying one or more _word constituent_ characters. Word -constituent characters are members of one syntax category. Other -syntax categories include the class of punctuation characters, such -as the period and the comma, and the class of whitespace characters, -such as the blank space and the tab character. (For more -information, see *Note Syntax: (emacs)Syntax, and *Note Syntax -Tables: (elisp)Syntax Tables.) - -Syntax tables specify which characters belong to which categories. -Usually, a hyphen is not specified as a `word constituent character'. -Instead, it is specified as being in the `class of characters that are -part of symbol names but not words.' This means that the -`count-words-region' function treats it in the same way it treats an -interword white space, which is why `count-words-region' counts -`multiply-by-seven' as three words. - -There are two ways to cause Emacs to count `multiply-by-seven' as one -symbol: modify the syntax table or modify the regular expression. - -We could redefine a hyphen as a word constituent character by -modifying the syntax table that Emacs keeps for each mode. This -action would serve our purpose, except that a hyphen is merely the -most common character within symbols that is not typically a word -constituent character; there are others, too. - -Alternatively, we can redefine the regular expression used in the -`count-words' definition so as to include symbols. This procedure -has the merit of clarity, but the task is a little tricky. - -The first part is simple enough: the pattern must match "at least one -character that is a word or symbol constituent". Thus: - - "\\(\\w\\|\\s_\\)+" - -The `\\(' is the first part of the grouping construct that includes -the `\\w' and the `\\s_' as alternatives, separated by the `\\|'. -The `\\w' matches any word-constituent character and the `\\s_' -matches any character that is part of a symbol name but not a -word-constituent character. The `+' following the group indicates -that the word or symbol constituent characters must be matched at -least once. - -However, the second part of the regexp is more difficult to design. -What we want is to follow the first part with "optionally one or more -characters that are not constituents of a word or symbol". At first, -I thought I could define this with the following: - - "\\(\\W\\|\\S_\\)*" - -The upper case `W' and `S' match characters that are _not_ word or -symbol constituents. Unfortunately, this expression matches any -character that is either not a word constituent or not a symbol -constituent. This matches any character! - -I then noticed that every word or symbol in my test region was -followed by white space (blank space, tab, or newline). So I tried -placing a pattern to match one or more blank spaces after the pattern -for one or more word or symbol constituents. This failed, too. Words -and symbols are often separated by whitespace, but in actual code -parentheses may follow symbols and punctuation may follow words. So -finally, I designed a pattern in which the word or symbol constituents -are followed optionally by characters that are not white space and -then followed optionally by white space. - -Here is the full regular expression: - - "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*" - -The `count-words-in-defun' Function -=================================== - -We have seen that there are several ways to write a -`count-word-region' function. To write a `count-words-in-defun', we -need merely adapt one of these versions. - -The version that uses a `while' loop is easy to understand, so I am -going to adapt that. Because `count-words-in-defun' will be part of -a more complex program, it need not be interactive and it need not -display a message but just return the count. These considerations -simplify the definition a little. - -On the other hand, `count-words-in-defun' will be used within a -buffer that contains function definitions. Consequently, it is -reasonable to ask that the function determine whether it is called -when point is within a function definition, and if it is, to return -the count for that definition. This adds complexity to the -definition, but saves us from needing to pass arguments to the -function. - -These considerations lead us to prepare the following template: - - (defun count-words-in-defun () - "DOCUMENTATION..." - (SET UP... - (WHILE LOOP...) - RETURN COUNT) - -As usual, our job is to fill in the slots. - -First, the set up. - -We are presuming that this function will be called within a buffer -containing function definitions. Point will either be within a -function definition or not. For `count-words-in-defun' to work, -point must move to the beginning of the definition, a counter must -start at zero, and the counting loop must stop when point reaches the -end of the definition. - -The `beginning-of-defun' function searches backwards for an opening -delimiter such as a `(' at the beginning of a line, and moves point -to that position, or else to the limit of the search. In practice, -this means that `beginning-of-defun' moves point to the beginning of -an enclosing or preceding function definition, or else to the -beginning of the buffer. We can use `beginning-of-defun' to place -point where we wish to start. - -The `while' loop requires a counter to keep track of the words or -symbols being counted. A `let' expression can be used to create a -local variable for this purpose, and bind it to an initial value of -zero. - -The `end-of-defun' function works like `beginning-of-defun' except -that it moves point to the end of the definition. `end-of-defun' can -be used as part of an expression that determines the position of the -end of the definition. - -The set up for `count-words-in-defun' takes shape rapidly: first we -move point to the beginning of the definition, then we create a local -variable to hold the count, and finally, we record the position of -the end of the definition so the `while' loop will know when to stop -looping. - -The code looks like this: - - (beginning-of-defun) - (let ((count 0) - (end (save-excursion (end-of-defun) (point)))) - -The code is simple. The only slight complication is likely to concern -`end': it is bound to the position of the end of the definition by a -`save-excursion' expression that returns the value of point after -`end-of-defun' temporarily moves it to the end of the definition. - -The second part of the `count-words-in-defun', after the set up, is -the `while' loop. - -The loop must contain an expression that jumps point forward word by -word and symbol by symbol, and another expression that counts the -jumps. The true-or-false-test for the `while' loop should test true -so long as point should jump forward, and false when point is at the -end of the definition. We have already redefined the regular -expression for this (*note Syntax::), so the loop is straightforward: - - (while (and (< (point) end) - (re-search-forward - "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*" end t) - (setq count (1+ count))) - -The third part of the function definition returns the count of words -and symbols. This part is the last expression within the body of the -`let' expression, and can be, very simply, the local variable -`count', which when evaluated returns the count. - -Put together, the `count-words-in-defun' definition looks like this: - - (defun count-words-in-defun () - "Return the number of words and symbols in a defun." - (beginning-of-defun) - (let ((count 0) - (end (save-excursion (end-of-defun) (point)))) - (while - (and (< (point) end) - (re-search-forward - "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*" - end t)) - (setq count (1+ count))) - count)) - -How to test this? The function is not interactive, but it is easy to -put a wrapper around the function to make it interactive; we can use -almost the same code as for the recursive version of -`count-words-region': - - ;;; Interactive version. - (defun count-words-defun () - "Number of words and symbols in a function definition." - (interactive) - (message - "Counting words and symbols in function definition ... ") - (let ((count (count-words-in-defun))) - (cond - ((zerop count) - (message - "The definition does NOT have any words or symbols.")) - ((= 1 count) - (message - "The definition has 1 word or symbol.")) - (t - (message - "The definition has %d words or symbols." count))))) - -Let's re-use `C-c =' as a convenient keybinding: - - (global-set-key "\C-c=" 'count-words-defun) - -Now we can try out `count-words-defun': install both -`count-words-in-defun' and `count-words-defun', and set the -keybinding, and then place the cursor within the following definition: - - (defun multiply-by-seven (number) - "Multiply NUMBER by seven." - (* 7 number)) - => 10 - -Success! The definition has 10 words and symbols. - -The next problem is to count the numbers of words and symbols in -several definitions within a single file. - -Count Several `defuns' Within a File -==================================== - -A file such as `simple.el' may have 80 or more function definitions -within it. Our long term goal is to collect statistics on many -files, but as a first step, our immediate goal is to collect -statistics on one file. - -The information will be a series of numbers, each number being the -length of a function definition. We can store the numbers in a list. - -We know that we will want to incorporate the information regarding one -file with information about many other files; this means that the -function for counting definition lengths within one file need only -return the list of lengths. It need not and should not display any -messages. - -The word count commands contain one expression to jump point forward -word by word and another expression to count the jumps. The function -to return the lengths of definitions can be designed to work the same -way, with one expression to jump point forward definition by -definition and another expression to construct the lengths' list. - -This statement of the problem makes it elementary to write the -function definition. Clearly, we will start the count at the -beginning of the file, so the first command will be `(goto-char -(point-min))'. Next, we start the `while' loop; and the -true-or-false test of the loop can be a regular expression search for -the next function definition--so long as the search succeeds, point -is moved forward and then the body of the loop is evaluated. The body -needs an expression that constructs the lengths' list. `cons', the -list construction command, can be used to create the list. That is -almost all there is to it. - -Here is what this fragment of code looks like: - - (goto-char (point-min)) - (while (re-search-forward "^(defun" nil t) - (setq lengths-list - (cons (count-words-in-defun) lengths-list))) - -What we have left out is the mechanism for finding the file that -contains the function definitions. - -In previous examples, we either used this, the Info file, or we -switched back and forth to some other buffer, such as the `*scratch*' -buffer. - -Finding a file is a new process that we have not yet discussed. - -Find a File -=========== - -To find a file in Emacs, you use the `C-x C-f' (`find-file') command. -This command is almost, but not quite right for the lengths problem. - -Let's look at the source for `find-file' (you can use the `find-tag' -command or `C-h f' (`describe-function') to find the source of a -function): - - (defun find-file (filename) - "Edit file FILENAME. - Switch to a buffer visiting file FILENAME, - creating one if none already exists." - (interactive "FFind file: ") - (switch-to-buffer (find-file-noselect filename))) - -The definition possesses short but complete documentation and an -interactive specification that prompts you for a file name when you -use the command interactively. The body of the definition contains -two functions, `find-file-noselect' and `switch-to-buffer'. - -According to its documentation as shown by `C-h f' (the -`describe-function' command), the `find-file-noselect' function reads -the named file into a buffer and returns the buffer. However, the -buffer is not selected. Emacs does not switch its attention (or -yours if you are using `find-file-noselect') to the named buffer. -That is what `switch-to-buffer' does: it switches the buffer to which -Emacs attention is directed; and it switches the buffer displayed in -the window to the new buffer. We have discussed buffer switching -elsewhere. (*Note Switching Buffers::.) - -In this histogram project, we do not need to display each file on the -screen as the program determines the length of each definition within -it. Instead of employing `switch-to-buffer', we can work with -`set-buffer', which redirects the attention of the computer program -to a different buffer but does not redisplay it on the screen. So -instead of calling on `find-file' to do the job, we must write our -own expression. - -The task is easy: use `find-file-noselect' and `set-buffer'. - -`lengths-list-file' in Detail -============================= - -The core of the `lengths-list-file' function is a `while' loop -containing a function to move point forward `defun by defun' and a -function to count the number of words and symbols in each defun. -This core must be surrounded by functions that do various other tasks, -including finding the file, and ensuring that point starts out at the -beginning of the file. The function definition looks like this: - - (defun lengths-list-file (filename) - "Return list of definitions' lengths within FILE. - The returned list is a list of numbers. - Each number is the number of words or - symbols in one function definition." - (message "Working on `%s' ... " filename) - (save-excursion - (let ((buffer (find-file-noselect filename)) - (lengths-list)) - (set-buffer buffer) - (setq buffer-read-only t) - (widen) - (goto-char (point-min)) - (while (re-search-forward "^(defun" nil t) - (setq lengths-list - (cons (count-words-in-defun) lengths-list))) - (kill-buffer buffer) - lengths-list))) - -The function is passed one argument, the name of the file on which it -will work. It has four lines of documentation, but no interactive -specification. Since people worry that a computer is broken if they -don't see anything going on, the first line of the body is a message. - -The next line contains a `save-excursion' that returns Emacs' -attention to the current buffer when the function completes. This is -useful in case you embed this function in another function that -presumes point is restored to the original buffer. - -In the varlist of the `let' expression, Emacs finds the file and -binds the local variable `buffer' to the buffer containing the file. -At the same time, Emacs creates `lengths-list' as a local variable. - -Next, Emacs switches its attention to the buffer. - -In the following line, Emacs makes the buffer read-only. Ideally, -this line is not necessary. None of the functions for counting words -and symbols in a function definition should change the buffer. -Besides, the buffer is not going to be saved, even if it were changed. -This line is entirely the consequence of great, perhaps excessive, -caution. The reason for the caution is that this function and those -it calls work on the sources for Emacs and it is very inconvenient if -they are inadvertently modified. It goes without saying that I did -not realize a need for this line until an experiment went awry and -started to modify my Emacs source files ... - -Next comes a call to widen the buffer if it is narrowed. This -function is usually not needed--Emacs creates a fresh buffer if none -already exists; but if a buffer visiting the file already exists Emacs -returns that one. In this case, the buffer may be narrowed and must -be widened. If we wanted to be fully `user-friendly', we would -arrange to save the restriction and the location of point, but we -won't. - -The `(goto-char (point-min))' expression moves point to the beginning -of the buffer. - -Then comes a `while' loop in which the `work' of the function is -carried out. In the loop, Emacs determines the length of each -definition and constructs a lengths' list containing the information. - -Emacs kills the buffer after working through it. This is to save -space inside of Emacs. My version of Emacs 19 contained over 300 -source files of interest; Emacs 21 contains over 800 source files. -Another function will apply `lengths-list-file' to each of the files. - -Finally, the last expression within the `let' expression is the -`lengths-list' variable; its value is returned as the value of the -whole function. - -You can try this function by installing it in the usual fashion. Then -place your cursor after the following expression and type `C-x C-e' -(`eval-last-sexp'). - - (lengths-list-file - "/usr/local/share/emacs/21.0.100/lisp/emacs-lisp/debug.el") - -(You may need to change the pathname of the file; the one here worked -with GNU Emacs version 21.0.100. To change the expression, copy it to -the `*scratch*' buffer and edit it. - -(Also, to see the full length of the list, rather than a truncated -version, you may have to evaluate the following: - - (custom-set-variables '(eval-expression-print-length nil)) - -(*Note Setting Variables with `defcustom': defcustom. Then evaluate -the `lengths-list-file' expression.) - -The lengths' list for `debug.el' takes less than a second to produce -and looks like this: - - (77 95 85 87 131 89 50 25 44 44 68 35 64 45 17 34 167 457) - -(Using my old machine, the version 19 lengths' list for `debug.el' -took seven seconds to produce and looked like this: - - (75 41 80 62 20 45 44 68 45 12 34 235) - -(The newer version of `debug.el' contains more defuns than the -earlier one; and my new machine is much faster than the old one.) - -Note that the length of the last definition in the file is first in -the list. - -Count Words in `defuns' in Different Files -========================================== - -In the previous section, we created a function that returns a list of -the lengths of each definition in a file. Now, we want to define a -function to return a master list of the lengths of the definitions in -a list of files. - -Working on each of a list of files is a repetitious act, so we can use -either a `while' loop or recursion. - -Determine the lengths of `defuns' ---------------------------------- - -The design using a `while' loop is routine. The argument passed the -function is a list of files. As we saw earlier (*note Loop -Example::), you can write a `while' loop so that the body of the loop -is evaluated if such a list contains elements, but to exit the loop -if the list is empty. For this design to work, the body of the loop -must contain an expression that shortens the list each time the body -is evaluated, so that eventually the list is empty. The usual -technique is to set the value of the list to the value of the CDR of -the list each time the body is evaluated. - -The template looks like this: - - (while TEST-WHETHER-LIST-IS-EMPTY - BODY... - SET-LIST-TO-CDR-OF-LIST) - -Also, we remember that a `while' loop returns `nil' (the result of -evaluating the true-or-false-test), not the result of any evaluation -within its body. (The evaluations within the body of the loop are -done for their side effects.) However, the expression that sets the -lengths' list is part of the body--and that is the value that we want -returned by the function as a whole. To do this, we enclose the -`while' loop within a `let' expression, and arrange that the last -element of the `let' expression contains the value of the lengths' -list. (*Note Loop Example with an Incrementing Counter: Incrementing -Example.) - -These considerations lead us directly to the function itself: - - ;;; Use `while' loop. - (defun lengths-list-many-files (list-of-files) - "Return list of lengths of defuns in LIST-OF-FILES." - (let (lengths-list) - - ;;; true-or-false-test - (while list-of-files - (setq lengths-list - (append - lengths-list - - ;;; Generate a lengths' list. - (lengths-list-file - (expand-file-name (car list-of-files))))) - - ;;; Make files' list shorter. - (setq list-of-files (cdr list-of-files))) - - ;;; Return final value of lengths' list. - lengths-list)) - -`expand-file-name' is a built-in function that converts a file name -to the absolute, long, path name form of the directory in which the -function is called. - -Thus, if `expand-file-name' is called on `debug.el' when Emacs is -visiting the `/usr/local/share/emacs/21.0.100/lisp/emacs-lisp/' -directory, - - debug.el - -becomes - - /usr/local/share/emacs/21.0.100/lisp/emacs-lisp/debug.el - -The only other new element of this function definition is the as yet -unstudied function `append', which merits a short section for itself. - -The `append' Function ---------------------- - -The `append' function attaches one list to another. Thus, - - (append '(1 2 3 4) '(5 6 7 8)) - -produces the list - - (1 2 3 4 5 6 7 8) - -This is exactly how we want to attach two lengths' lists produced by -`lengths-list-file' to each other. The results contrast with `cons', - - (cons '(1 2 3 4) '(5 6 7 8)) - -which constructs a new list in which the first argument to `cons' -becomes the first element of the new list: - - ((1 2 3 4) 5 6 7 8) - -Recursively Count Words in Different Files -========================================== - -Besides a `while' loop, you can work on each of a list of files with -recursion. A recursive version of `lengths-list-many-files' is short -and simple. - -The recursive function has the usual parts: the `do-again-test', the -`next-step-expression', and the recursive call. The `do-again-test' -determines whether the function should call itself again, which it -will do if the `list-of-files' contains any remaining elements; the -`next-step-expression' resets the `list-of-files' to the CDR of -itself, so eventually the list will be empty; and the recursive call -calls itself on the shorter list. The complete function is shorter -than this description! - - (defun recursive-lengths-list-many-files (list-of-files) - "Return list of lengths of each defun in LIST-OF-FILES." - (if list-of-files ; do-again-test - (append - (lengths-list-file - (expand-file-name (car list-of-files))) - (recursive-lengths-list-many-files - (cdr list-of-files))))) - -In a sentence, the function returns the lengths' list for the first of -the `list-of-files' appended to the result of calling itself on the -rest of the `list-of-files'. - -Here is a test of `recursive-lengths-list-many-files', along with the -results of running `lengths-list-file' on each of the files -individually. - -Install `recursive-lengths-list-many-files' and `lengths-list-file', -if necessary, and then evaluate the following expressions. You may -need to change the files' pathnames; those here work when this Info -file and the Emacs sources are located in their customary places. To -change the expressions, copy them to the `*scratch*' buffer, edit -them, and then evaluate them. - -The results are shown after the `=>'. (These results are for files -from Emacs Version 21.0.100; files from other versions of Emacs may -produce different results.) - - (cd "/usr/local/share/emacs/21.0.100/") - - (lengths-list-file "./lisp/macros.el") - => (273 263 456 90) - - (lengths-list-file "./lisp/mail/mailalias.el") - => (38 32 26 77 174 180 321 198 324) - - (lengths-list-file "./lisp/makesum.el") - => (85 181) - - (recursive-lengths-list-many-files - '("./lisp/macros.el" - "./lisp/mail/mailalias.el" - "./lisp/makesum.el")) - => (273 263 456 90 38 32 26 77 174 180 321 198 324 85 181) - -The `recursive-lengths-list-many-files' function produces the output -we want. - -The next step is to prepare the data in the list for display in a -graph. - -Prepare the Data for Display in a Graph -======================================= - -The `recursive-lengths-list-many-files' function returns a list of -numbers. Each number records the length of a function definition. -What we need to do now is transform this data into a list of numbers -suitable for generating a graph. The new list will tell how many -functions definitions contain less than 10 words and symbols, how -many contain between 10 and 19 words and symbols, how many contain -between 20 and 29 words and symbols, and so on. - -In brief, we need to go through the lengths' list produced by the -`recursive-lengths-list-many-files' function and count the number of -defuns within each range of lengths, and produce a list of those -numbers. - -Based on what we have done before, we can readily foresee that it -should not be too hard to write a function that `CDRs' down the -lengths' list, looks at each element, determines which length range it -is in, and increments a counter for that range. - -However, before beginning to write such a function, we should consider -the advantages of sorting the lengths' list first, so the numbers are -ordered from smallest to largest. First, sorting will make it easier -to count the numbers in each range, since two adjacent numbers will -either be in the same length range or in adjacent ranges. Second, by -inspecting a sorted list, we can discover the highest and lowest -number, and thereby determine the largest and smallest length range -that we will need. - -Sorting Lists -------------- - -Emacs contains a function to sort lists, called (as you might guess) -`sort'. The `sort' function takes two arguments, the list to be -sorted, and a predicate that determines whether the first of two list -elements is "less" than the second. - -As we saw earlier (*note Using the Wrong Type Object as an Argument: -Wrong Type of Argument.), a predicate is a function that determines -whether some property is true or false. The `sort' function will -reorder a list according to whatever property the predicate uses; -this means that `sort' can be used to sort non-numeric lists by -non-numeric criteria--it can, for example, alphabetize a list. - -The `<' function is used when sorting a numeric list. For example, - - (sort '(4 8 21 17 33 7 21 7) '<) - -produces this: - - (4 7 7 8 17 21 21 33) - -(Note that in this example, both the arguments are quoted so that the -symbols are not evaluated before being passed to `sort' as arguments.) - -Sorting the list returned by the `recursive-lengths-list-many-files' -function is straightforward; it uses the `<' function: - - (sort - (recursive-lengths-list-many-files - '("../lisp/macros.el" - "../lisp/mailalias.el" - "../lisp/makesum.el")) - '< - -which produces: - - (85 86 116 122 154 176 179 265) - -(Note that in this example, the first argument to `sort' is not -quoted, since the expression must be evaluated so as to produce the -list that is passed to `sort'.) - -Making a List of Files ----------------------- - -The `recursive-lengths-list-many-files' function requires a list of -files as its argument. For our test examples, we constructed such a -list by hand; but the Emacs Lisp source directory is too large for us -to do for that. Instead, we will write a function to do the job for -us. In this function, we will use both a `while' loop and a -recursive call. - -We did not have to write a function like this for older versions of -GNU Emacs, since they placed all the `.el' files in one directory. -Instead, we were able to use the `directory-files' function, which -lists the names of files that match a specified pattern within a -single directory. - -However, recent versions of Emacs place Emacs Lisp files in -sub-directories of the top level `lisp' directory. This -re-arrangement eases navigation. For example, all the mail related -files are in a `lisp' sub-directory called `mail'. But at the same -time, this arrangement forces us to create a file listing function -that descends into the sub-directories. - -We can create this function, called `files-in-below-directory', using -familiar functions such as `car', `nthcdr', and `substring' in -conjunction with an existing function called -`directory-files-and-attributes'. This latter function not only -lists all the filenames in a directory, including the names of -sub-directories, but also their attributes. - -To restate our goal: to create a function that will enable us to feed -filenames to `recursive-lengths-list-many-files' as a list that looks -like this (but with more elements): - - ("../lisp/macros.el" - "../lisp/mail/rmail.el" - "../lisp/makesum.el") - -The `directory-files-and-attributes' function returns a list of -lists. Each of the lists within the main list consists of 13 -elements. The first element is a string that contains the name of the -file - which, in GNU/Linux, may be a `directory file', that is to -say, a file with the special attributes of a directory. The second -element of the list is `t' for a directory, a string for symbolic -link (the string is the name linked to), or `nil'. - -For example, the first `.el' file in the `lisp/' directory is -`abbrev.el'. Its name is -`/usr/local/share/emacs/21.0.100/lisp/abbrev.el' and it is not a -directory or a symbolic link. - -This is how `directory-files-and-attributes' lists that file and its -attributes: - - ("/usr/local/share/emacs/21.0.100/lisp/abbrev.el" - nil - 1 - 1000 - 100 - (15019 32380) - (14883 48041) - (15214 49336) - 11583 - "-rw-rw-r--" - t - 341385 - 776) - -On the other hand, `mail/' is a directory within the `lisp/' -directory. The beginning of its listing looks like this: - - ("/usr/local/share/emacs/21.0.100/lisp/mail" - t - ... - ) - -(Look at the documentation of `file-attributes' to learn about the -different attributes. Bear in mind that the `file-attributes' -function does not list the filename, so its first element is -`directory-files-and-attributes''s second element.) - -We will want our new function, `files-in-below-directory', to list -the `.el' files in the directory it is told to check, and in any -directories below that directory. - -This gives us a hint on how to construct `files-in-below-directory': -within a directory, the function should add `.el' filenames to a -list; and if, within a directory, the function comes upon a -sub-directory, it should go into that sub-directory and repeat its -actions. - -However, we should note that every directory contains a name that -refers to itself, called `.', ("dot") and a name that refers to its -parent directory, called `..' ("double dot"). (In `/', the root -directory, `..' refers to itself, since `/' has no parent.) Clearly, -we do not want our `files-in-below-directory' function to enter those -directories, since they always lead us, directly or indirectly, to -the current directory. - -Consequently, our `files-in-below-directory' function must do several -tasks: - - * Check to see whether it is looking at a filename that ends in - `.el'; and if so, add its name to a list. - - * Check to see whether it is looking at a filename that is the - name of a directory; and if so, - - - Check to see whether it is looking at `.' or `..'; and if - so skip it. - - - Or else, go into that directory and repeat the process. - -Let's write a function definition to do these tasks. We will use a -`while' loop to move from one filename to another within a directory, -checking what needs to be done; and we will use a recursive call to -repeat the actions on each sub-directory. The recursive pattern is -`accumulate' (*note Recursive Pattern: _accumulate_: Accumulate.), -using `append' as the combiner. - -Here is the function: - - (defun files-in-below-directory (directory) - "List the .el files in DIRECTORY and in its sub-directories." - ;; Although the function will be used non-interactively, - ;; it will be easier to test if we make it interactive. - ;; The directory will have a name such as - ;; "/usr/local/share/emacs/21.0.100/lisp/" - (interactive "DDirectory name: ") - (let (el-files-list - (current-directory-list - (directory-files-and-attributes directory t))) - ;; while we are in the current directory - (while current-directory-list - (cond - ;; check to see whether filename ends in `.el' - ;; and if so, append its name to a list. - ((equal ".el" (substring (car (car current-directory-list)) -3)) - (setq el-files-list - (cons (car (car current-directory-list)) el-files-list))) - ;; check whether filename is that of a directory - ((eq t (car (cdr (car current-directory-list)))) - ;; decide whether to skip or recurse - (if - (equal (or "." "..") - (substring (car (car current-directory-list)) -1)) - ;; then do nothing if filename is that of - ;; current directory or parent - () - ;; else descend into the directory and repeat the process - (setq el-files-list - (append - (files-in-below-directory - (car (car current-directory-list))) - el-files-list))))) - ;; move to the next filename in the list; this also - ;; shortens the list so the while loop eventually comes to an end - (setq current-directory-list (cdr current-directory-list))) - ;; return the filenames - el-files-list)) - -The `files-in-below-directory' `directory-files' function takes one -argument, the name of a directory. - -Thus, on my system, - - (length - (files-in-below-directory "/usr/local/share/emacs/21.0.100/lisp/")) - -tells me that my version 21.0.100 Lisp sources directory contains 754 -`.el' files. - -`files-in-below-directory' returns a list in reverse alphabetical -order. An expression to sort the list in alphabetical order looks -like this: - - (sort - (files-in-below-directory "/usr/local/share/emacs/21.0.100/lisp/") - 'string-lessp) - -Counting function definitions ------------------------------ - -Our immediate goal is to generate a list that tells us how many -function definitions contain fewer than 10 words and symbols, how many -contain between 10 and 19 words and symbols, how many contain between -20 and 29 words and symbols, and so on. - -With a sorted list of numbers, this is easy: count how many elements -of the list are smaller than 10, then, after moving past the numbers -just counted, count how many are smaller than 20, then, after moving -past the numbers just counted, count how many are smaller than 30, and -so on. Each of the numbers, 10, 20, 30, 40, and the like, is one -larger than the top of that range. We can call the list of such -numbers the `top-of-ranges' list. - -If we wished, we could generate this list automatically, but it is -simpler to write a list manually. Here it is: - - (defvar top-of-ranges - '(10 20 30 40 50 - 60 70 80 90 100 - 110 120 130 140 150 - 160 170 180 190 200 - 210 220 230 240 250 - 260 270 280 290 300) - "List specifying ranges for `defuns-per-range'.") - -To change the ranges, we edit this list. - -Next, we need to write the function that creates the list of the -number of definitions within each range. Clearly, this function must -take the `sorted-lengths' and the `top-of-ranges' lists as arguments. - -The `defuns-per-range' function must do two things again and again: -it must count the number of definitions within a range specified by -the current top-of-range value; and it must shift to the next higher -value in the `top-of-ranges' list after counting the number of -definitions in the current range. Since each of these actions is -repetitive, we can use `while' loops for the job. One loop counts -the number of definitions in the range defined by the current -top-of-range value, and the other loop selects each of the -top-of-range values in turn. - -Several entries of the `sorted-lengths' list are counted for each -range; this means that the loop for the `sorted-lengths' list will be -inside the loop for the `top-of-ranges' list, like a small gear -inside a big gear. - -The inner loop counts the number of definitions within the range. It -is a simple counting loop of the type we have seen before. (*Note A -loop with an incrementing counter: Incrementing Loop.) The -true-or-false test of the loop tests whether the value from the -`sorted-lengths' list is smaller than the current value of the top of -the range. If it is, the function increments the counter and tests -the next value from the `sorted-lengths' list. - -The inner loop looks like this: - - (while LENGTH-ELEMENT-SMALLER-THAN-TOP-OF-RANGE - (setq number-within-range (1+ number-within-range)) - (setq sorted-lengths (cdr sorted-lengths))) - -The outer loop must start with the lowest value of the -`top-of-ranges' list, and then be set to each of the succeeding -higher values in turn. This can be done with a loop like this: - - (while top-of-ranges - BODY-OF-LOOP... - (setq top-of-ranges (cdr top-of-ranges))) - -Put together, the two loops look like this: - - (while top-of-ranges - - ;; Count the number of elements within the current range. - (while LENGTH-ELEMENT-SMALLER-THAN-TOP-OF-RANGE - (setq number-within-range (1+ number-within-range)) - (setq sorted-lengths (cdr sorted-lengths))) - - ;; Move to next range. - (setq top-of-ranges (cdr top-of-ranges))) - -In addition, in each circuit of the outer loop, Emacs should record -the number of definitions within that range (the value of -`number-within-range') in a list. We can use `cons' for this -purpose. (*Note `cons': cons.) - -The `cons' function works fine, except that the list it constructs -will contain the number of definitions for the highest range at its -beginning and the number of definitions for the lowest range at its -end. This is because `cons' attaches new elements of the list to the -beginning of the list, and since the two loops are working their way -through the lengths' list from the lower end first, the -`defuns-per-range-list' will end up largest number first. But we -will want to print our graph with smallest values first and the -larger later. The solution is to reverse the order of the -`defuns-per-range-list'. We can do this using the `nreverse' -function, which reverses the order of a list. - -For example, - - (nreverse '(1 2 3 4)) - -produces: - - (4 3 2 1) - -Note that the `nreverse' function is "destructive"--that is, it -changes the list to which it is applied; this contrasts with the -`car' and `cdr' functions, which are non-destructive. In this case, -we do not want the original `defuns-per-range-list', so it does not -matter that it is destroyed. (The `reverse' function provides a -reversed copy of a list, leaving the original list as is.) - -Put all together, the `defuns-per-range' looks like this: - - (defun defuns-per-range (sorted-lengths top-of-ranges) - "SORTED-LENGTHS defuns in each TOP-OF-RANGES range." - (let ((top-of-range (car top-of-ranges)) - (number-within-range 0) - defuns-per-range-list) - - ;; Outer loop. - (while top-of-ranges - - ;; Inner loop. - (while (and - ;; Need number for numeric test. - (car sorted-lengths) - (< (car sorted-lengths) top-of-range)) - - ;; Count number of definitions within current range. - (setq number-within-range (1+ number-within-range)) - (setq sorted-lengths (cdr sorted-lengths))) - - ;; Exit inner loop but remain within outer loop. - - (setq defuns-per-range-list - (cons number-within-range defuns-per-range-list)) - (setq number-within-range 0) ; Reset count to zero. - - ;; Move to next range. - (setq top-of-ranges (cdr top-of-ranges)) - ;; Specify next top of range value. - (setq top-of-range (car top-of-ranges))) - - ;; Exit outer loop and count the number of defuns larger than - ;; the largest top-of-range value. - (setq defuns-per-range-list - (cons - (length sorted-lengths) - defuns-per-range-list)) - - ;; Return a list of the number of definitions within each range, - ;; smallest to largest. - (nreverse defuns-per-range-list))) - -The function is straightforward except for one subtle feature. The -true-or-false test of the inner loop looks like this: - - (and (car sorted-lengths) - (< (car sorted-lengths) top-of-range)) - -instead of like this: - - (< (car sorted-lengths) top-of-range) - -The purpose of the test is to determine whether the first item in the -`sorted-lengths' list is less than the value of the top of the range. - -The simple version of the test works fine unless the `sorted-lengths' -list has a `nil' value. In that case, the `(car sorted-lengths)' -expression function returns `nil'. The `<' function cannot compare a -number to `nil', which is an empty list, so Emacs signals an error and -stops the function from attempting to continue to execute. - -The `sorted-lengths' list always becomes `nil' when the counter -reaches the end of the list. This means that any attempt to use the -`defuns-per-range' function with the simple version of the test will -fail. - -We solve the problem by using the `(car sorted-lengths)' expression -in conjunction with the `and' expression. The `(car sorted-lengths)' -expression returns a non-`nil' value so long as the list has at least -one number within it, but returns `nil' if the list is empty. The -`and' expression first evaluates the `(car sorted-lengths)' -expression, and if it is `nil', returns false _without_ evaluating the -`<' expression. But if the `(car sorted-lengths)' expression returns -a non-`nil' value, the `and' expression evaluates the `<' expression, -and returns that value as the value of the `and' expression. - -This way, we avoid an error. *Note forward-paragraph::, for more -information about `and'. - -Here is a short test of the `defuns-per-range' function. First, -evaluate the expression that binds (a shortened) `top-of-ranges' list -to the list of values, then evaluate the expression for binding the -`sorted-lengths' list, and then evaluate the `defuns-per-range' -function. - - ;; (Shorter list than we will use later.) - (setq top-of-ranges - '(110 120 130 140 150 - 160 170 180 190 200)) - - (setq sorted-lengths - '(85 86 110 116 122 129 154 176 179 200 265 300 300)) - - (defuns-per-range sorted-lengths top-of-ranges) - -The list returned looks like this: - - (2 2 2 0 0 1 0 2 0 0 4) - -Indeed, there are two elements of the `sorted-lengths' list smaller -than 110, two elements between 110 and 119, two elements between 120 -and 129, and so on. There are four elements with a value of 200 or -larger. - -Readying a Graph -**************** - -Our goal is to construct a graph showing the numbers of function -definitions of various lengths in the Emacs lisp sources. - -As a practical matter, if you were creating a graph, you would -probably use a program such as `gnuplot' to do the job. (`gnuplot' -is nicely integrated into GNU Emacs.) In this case, however, we -create one from scratch, and in the process we will re-acquaint -ourselves with some of what we learned before and learn more. - -In this chapter, we will first write a simple graph printing function. -This first definition will be a "prototype", a rapidly written -function that enables us to reconnoiter this unknown graph-making -territory. We will discover dragons, or find that they are myth. -After scouting the terrain, we will feel more confident and enhance -the function to label the axes automatically. - -Printing the Columns of a Graph -=============================== - -Since Emacs is designed to be flexible and work with all kinds of -terminals, including character-only terminals, the graph will need to -be made from one of the `typewriter' symbols. An asterisk will do; as -we enhance the graph-printing function, we can make the choice of -symbol a user option. - -We can call this function `graph-body-print'; it will take a -`numbers-list' as its only argument. At this stage, we will not -label the graph, but only print its body. - -The `graph-body-print' function inserts a vertical column of -asterisks for each element in the `numbers-list'. The height of each -line is determined by the value of that element of the `numbers-list'. - -Inserting columns is a repetitive act; that means that this function -can be written either with a `while' loop or recursively. - -Our first challenge is to discover how to print a column of asterisks. -Usually, in Emacs, we print characters onto a screen horizontally, -line by line, by typing. We have two routes we can follow: write our -own column-insertion function or discover whether one exists in Emacs. - -To see whether there is one in Emacs, we can use the `M-x apropos' -command. This command is like the `C-h a' (command-apropos) command, -except that the latter finds only those functions that are commands. -The `M-x apropos' command lists all symbols that match a regular -expression, including functions that are not interactive. - -What we want to look for is some command that prints or inserts -columns. Very likely, the name of the function will contain either -the word `print' or the word `insert' or the word `column'. -Therefore, we can simply type `M-x apropos RET print\|insert\|column -RET' and look at the result. On my system, this command takes quite -some time, and then produces a list of 79 functions and variables. -Scanning down the list, the only function that looks as if it might -do the job is `insert-rectangle'. - -Indeed, this is the function we want; its documentation says: - - insert-rectangle: - Insert text of RECTANGLE with upper left corner at point. - RECTANGLE's first line is inserted at point, - its second line is inserted at a point vertically under point, etc. - RECTANGLE should be a list of strings. - -We can run a quick test, to make sure it does what we expect of it. - -Here is the result of placing the cursor after the `insert-rectangle' -expression and typing `C-u C-x C-e' (`eval-last-sexp'). The function -inserts the strings `"first"', `"second"', and `"third"' at and below -point. Also the function returns `nil'. - - (insert-rectangle '("first" "second" "third"))first - second - third - nil - -Of course, we won't be inserting the text of the `insert-rectangle' -expression itself into the buffer in which we are making the graph, -but will call the function from our program. We shall, however, have -to make sure that point is in the buffer at the place where the -`insert-rectangle' function will insert its column of strings. - -If you are reading this in Info, you can see how this works by -switching to another buffer, such as the `*scratch*' buffer, placing -point somewhere in the buffer, typing `M-:', typing the -`insert-rectangle' expression into the minibuffer at the prompt, and -then typing <RET>. This causes Emacs to evaluate the expression in -the minibuffer, but to use as the value of point the position of -point in the `*scratch*' buffer. (`M-:' is the keybinding for -`eval-expression'.) - -We find when we do this that point ends up at the end of the last -inserted line--that is to say, this function moves point as a -side-effect. If we were to repeat the command, with point at this -position, the next insertion would be below and to the right of the -previous insertion. We don't want this! If we are going to make a -bar graph, the columns need to be beside each other. - -So we discover that each cycle of the column-inserting `while' loop -must reposition point to the place we want it, and that place will be -at the top, not the bottom, of the column. Moreover, we remember -that when we print a graph, we do not expect all the columns to be -the same height. This means that the top of each column may be at a -different height from the previous one. We cannot simply reposition -point to the same line each time, but moved over to the right--or -perhaps we can... - -We are planning to make the columns of the bar graph out of asterisks. -The number of asterisks in the column is the number specified by the -current element of the `numbers-list'. We need to construct a list -of asterisks of the right length for each call to `insert-rectangle'. -If this list consists solely of the requisite number of asterisks, -then we will have position point the right number of lines above the -base for the graph to print correctly. This could be difficult. - -Alternatively, if we can figure out some way to pass -`insert-rectangle' a list of the same length each time, then we can -place point on the same line each time, but move it over one column -to the right for each new column. If we do this, however, some of -the entries in the list passed to `insert-rectangle' must be blanks -rather than asterisks. For example, if the maximum height of the -graph is 5, but the height of the column is 3, then -`insert-rectangle' requires an argument that looks like this: - - (" " " " "*" "*" "*") - -This last proposal is not so difficult, so long as we can determine -the column height. There are two ways for us to specify the column -height: we can arbitrarily state what it will be, which would work -fine for graphs of that height; or we can search through the list of -numbers and use the maximum height of the list as the maximum height -of the graph. If the latter operation were difficult, then the former -procedure would be easiest, but there is a function built into Emacs -that determines the maximum of its arguments. We can use that -function. The function is called `max' and it returns the largest of -all its arguments, which must be numbers. Thus, for example, - - (max 3 4 6 5 7 3) - -returns 7. (A corresponding function called `min' returns the -smallest of all its arguments.) - -However, we cannot simply call `max' on the `numbers-list'; the `max' -function expects numbers as its argument, not a list of numbers. -Thus, the following expression, - - (max '(3 4 6 5 7 3)) - -produces the following error message; - - Wrong type of argument: number-or-marker-p, (3 4 6 5 7 3) - -We need a function that passes a list of arguments to a function. -This function is `apply'. This function `applies' its first argument -(a function) to its remaining arguments, the last of which may be a -list. - -For example, - - (apply 'max 3 4 7 3 '(4 8 5)) - -returns 8. - -(Incidentally, I don't know how you would learn of this function -without a book such as this. It is possible to discover other -functions, like `search-forward' or `insert-rectangle', by guessing -at a part of their names and then using `apropos'. Even though its -base in metaphor is clear--`apply' its first argument to the rest--I -doubt a novice would come up with that particular word when using -`apropos' or other aid. Of course, I could be wrong; after all, the -function was first named by someone who had to invent it.) - -The second and subsequent arguments to `apply' are optional, so we -can use `apply' to call a function and pass the elements of a list to -it, like this, which also returns 8: - - (apply 'max '(4 8 5)) - -This latter way is how we will use `apply'. The -`recursive-lengths-list-many-files' function returns a numbers' list -to which we can apply `max' (we could also apply `max' to the sorted -numbers' list; it does not matter whether the list is sorted or not.) - -Hence, the operation for finding the maximum height of the graph is -this: - - (setq max-graph-height (apply 'max numbers-list)) - -Now we can return to the question of how to create a list of strings -for a column of the graph. Told the maximum height of the graph and -the number of asterisks that should appear in the column, the -function should return a list of strings for the `insert-rectangle' -command to insert. - -Each column is made up of asterisks or blanks. Since the function is -passed the value of the height of the column and the number of -asterisks in the column, the number of blanks can be found by -subtracting the number of asterisks from the height of the column. -Given the number of blanks and the number of asterisks, two `while' -loops can be used to construct the list: - - ;;; First version. - (defun column-of-graph (max-graph-height actual-height) - "Return list of strings that is one column of a graph." - (let ((insert-list nil) - (number-of-top-blanks - (- max-graph-height actual-height))) - - ;; Fill in asterisks. - (while (> actual-height 0) - (setq insert-list (cons "*" insert-list)) - (setq actual-height (1- actual-height))) - - ;; Fill in blanks. - (while (> number-of-top-blanks 0) - (setq insert-list (cons " " insert-list)) - (setq number-of-top-blanks - (1- number-of-top-blanks))) - - ;; Return whole list. - insert-list)) - -If you install this function and then evaluate the following -expression you will see that it returns the list as desired: - - (column-of-graph 5 3) - -returns - - (" " " " "*" "*" "*") - -As written, `column-of-graph' contains a major flaw: the symbols used -for the blank and for the marked entries in the column are -`hard-coded' as a space and asterisk. This is fine for a prototype, -but you, or another user, may wish to use other symbols. For example, -in testing the graph function, you many want to use a period in place -of the space, to make sure the point is being repositioned properly -each time the `insert-rectangle' function is called; or you might -want to substitute a `+' sign or other symbol for the asterisk. You -might even want to make a graph-column that is more than one display -column wide. The program should be more flexible. The way to do -that is to replace the blank and the asterisk with two variables that -we can call `graph-blank' and `graph-symbol' and define those -variables separately. - -Also, the documentation is not well written. These considerations -lead us to the second version of the function: - - (defvar graph-symbol "*" - "String used as symbol in graph, usually an asterisk.") - - (defvar graph-blank " " - "String used as blank in graph, usually a blank space. - graph-blank must be the same number of columns wide - as graph-symbol.") - -(For an explanation of `defvar', see *Note Initializing a Variable -with `defvar': defvar.) - - ;;; Second version. - (defun column-of-graph (max-graph-height actual-height) - "Return MAX-GRAPH-HEIGHT strings; ACTUAL-HEIGHT are graph-symbols. - The graph-symbols are contiguous entries at the end - of the list. - The list will be inserted as one column of a graph. - The strings are either graph-blank or graph-symbol." - - (let ((insert-list nil) - (number-of-top-blanks - (- max-graph-height actual-height))) - - ;; Fill in `graph-symbols'. - (while (> actual-height 0) - (setq insert-list (cons graph-symbol insert-list)) - (setq actual-height (1- actual-height))) - - ;; Fill in `graph-blanks'. - (while (> number-of-top-blanks 0) - (setq insert-list (cons graph-blank insert-list)) - (setq number-of-top-blanks - (1- number-of-top-blanks))) - - ;; Return whole list. - insert-list)) - -If we wished, we could rewrite `column-of-graph' a third time to -provide optionally for a line graph as well as for a bar graph. This -would not be hard to do. One way to think of a line graph is that it -is no more than a bar graph in which the part of each bar that is -below the top is blank. To construct a column for a line graph, the -function first constructs a list of blanks that is one shorter than -the value, then it uses `cons' to attach a graph symbol to the list; -then it uses `cons' again to attach the `top blanks' to the list. - -It is easy to see how to write such a function, but since we don't -need it, we will not do it. But the job could be done, and if it were -done, it would be done with `column-of-graph'. Even more important, -it is worth noting that few changes would have to be made anywhere -else. The enhancement, if we ever wish to make it, is simple. - -Now, finally, we come to our first actual graph printing function. -This prints the body of a graph, not the labels for the vertical and -horizontal axes, so we can call this `graph-body-print'. - -The `graph-body-print' Function -=============================== - -After our preparation in the preceding section, the -`graph-body-print' function is straightforward. The function will -print column after column of asterisks and blanks, using the elements -of a numbers' list to specify the number of asterisks in each column. -This is a repetitive act, which means we can use a decrementing -`while' loop or recursive function for the job. In this section, we -will write the definition using a `while' loop. - -The `column-of-graph' function requires the height of the graph as an -argument, so we should determine and record that as a local variable. - -This leads us to the following template for the `while' loop version -of this function: - - (defun graph-body-print (numbers-list) - "DOCUMENTATION..." - (let ((height ... - ...)) - - (while numbers-list - INSERT-COLUMNS-AND-REPOSITION-POINT - (setq numbers-list (cdr numbers-list))))) - -We need to fill in the slots of the template. - -Clearly, we can use the `(apply 'max numbers-list)' expression to -determine the height of the graph. - -The `while' loop will cycle through the `numbers-list' one element at -a time. As it is shortened by the `(setq numbers-list (cdr -numbers-list))' expression, the CAR of each instance of the list is -the value of the argument for `column-of-graph'. - -At each cycle of the `while' loop, the `insert-rectangle' function -inserts the list returned by `column-of-graph'. Since the -`insert-rectangle' function moves point to the lower right of the -inserted rectangle, we need to save the location of point at the time -the rectangle is inserted, move back to that position after the -rectangle is inserted, and then move horizontally to the next place -from which `insert-rectangle' is called. - -If the inserted columns are one character wide, as they will be if -single blanks and asterisks are used, the repositioning command is -simply `(forward-char 1)'; however, the width of a column may be -greater than one. This means that the repositioning command should be -written `(forward-char symbol-width)'. The `symbol-width' itself is -the length of a `graph-blank' and can be found using the expression -`(length graph-blank)'. The best place to bind the `symbol-width' -variable to the value of the width of graph column is in the varlist -of the `let' expression. - -These considerations lead to the following function definition: - - (defun graph-body-print (numbers-list) - "Print a bar graph of the NUMBERS-LIST. - The numbers-list consists of the Y-axis values." - - (let ((height (apply 'max numbers-list)) - (symbol-width (length graph-blank)) - from-position) - - (while numbers-list - (setq from-position (point)) - (insert-rectangle - (column-of-graph height (car numbers-list))) - (goto-char from-position) - (forward-char symbol-width) - ;; Draw graph column by column. - (sit-for 0) - (setq numbers-list (cdr numbers-list))) - ;; Place point for X axis labels. - (forward-line height) - (insert "\n") - )) - -The one unexpected expression in this function is the `(sit-for 0)' -expression in the `while' loop. This expression makes the graph -printing operation more interesting to watch than it would be -otherwise. The expression causes Emacs to `sit' or do nothing for a -zero length of time and then redraw the screen. Placed here, it -causes Emacs to redraw the screen column by column. Without it, -Emacs would not redraw the screen until the function exits. - -We can test `graph-body-print' with a short list of numbers. - - 1. Install `graph-symbol', `graph-blank', `column-of-graph', which - are in *Note Columns of a graph::, and `graph-body-print'. - - 2. Copy the following expression: - - (graph-body-print '(1 2 3 4 6 4 3 5 7 6 5 2 3)) - - 3. Switch to the `*scratch*' buffer and place the cursor where you - want the graph to start. - - 4. Type `M-:' (`eval-expression'). - - 5. Yank the `graph-body-print' expression into the minibuffer with - `C-y' (`yank)'. - - 6. Press <RET> to evaluate the `graph-body-print' expression. - -Emacs will print a graph like this: - - * - * ** - * **** - *** **** - ********* * - ************ - ************* - -The `recursive-graph-body-print' Function -========================================= - -The `graph-body-print' function may also be written recursively. The -recursive solution is divided into two parts: an outside `wrapper' -that uses a `let' expression to determine the values of several -variables that need only be found once, such as the maximum height of -the graph, and an inside function that is called recursively to print -the graph. - -The `wrapper' is uncomplicated: - - (defun recursive-graph-body-print (numbers-list) - "Print a bar graph of the NUMBERS-LIST. - The numbers-list consists of the Y-axis values." - (let ((height (apply 'max numbers-list)) - (symbol-width (length graph-blank)) - from-position) - (recursive-graph-body-print-internal - numbers-list - height - symbol-width))) - -The recursive function is a little more difficult. It has four parts: -the `do-again-test', the printing code, the recursive call, and the -`next-step-expression'. The `do-again-test' is an `if' expression -that determines whether the `numbers-list' contains any remaining -elements; if it does, the function prints one column of the graph -using the printing code and calls itself again. The function calls -itself again according to the value produced by the -`next-step-expression' which causes the call to act on a shorter -version of the `numbers-list'. - - (defun recursive-graph-body-print-internal - (numbers-list height symbol-width) - "Print a bar graph. - Used within recursive-graph-body-print function." - - (if numbers-list - (progn - (setq from-position (point)) - (insert-rectangle - (column-of-graph height (car numbers-list))) - (goto-char from-position) - (forward-char symbol-width) - (sit-for 0) ; Draw graph column by column. - (recursive-graph-body-print-internal - (cdr numbers-list) height symbol-width)))) - -After installation, this expression can be tested; here is a sample: - - (recursive-graph-body-print '(3 2 5 6 7 5 3 4 6 4 3 2 1)) - -Here is what `recursive-graph-body-print' produces: - - * - ** * - **** * - **** *** - * ********* - ************ - ************* - -Either of these two functions, `graph-body-print' or -`recursive-graph-body-print', create the body of a graph. - -Need for Printed Axes -===================== - -A graph needs printed axes, so you can orient yourself. For a do-once -project, it may be reasonable to draw the axes by hand using Emacs' -Picture mode; but a graph drawing function may be used more than once. - -For this reason, I have written enhancements to the basic -`print-graph-body' function that automatically print labels for the -horizontal and vertical axes. Since the label printing functions do -not contain much new material, I have placed their description in an -appendix. *Note A Graph with Labelled Axes: Full Graph. - -Exercise -======== - -Write a line graph version of the graph printing functions. - -Your `.emacs' File -****************** - -"You don't have to like Emacs to like it" - this seemingly -paradoxical statement is the secret of GNU Emacs. The plain, `out of -the box' Emacs is a generic tool. Most people who use it, customize -it to suit themselves. - -GNU Emacs is mostly written in Emacs Lisp; this means that by writing -expressions in Emacs Lisp you can change or extend Emacs. - -Emacs' Default Configuration -============================ - -There are those who appreciate Emacs' default configuration. After -all, Emacs starts you in C mode when you edit a C file, starts you in -Fortran mode when you edit a Fortran file, and starts you in -Fundamental mode when you edit an unadorned file. This all makes -sense, if you do not know who is going to use Emacs. Who knows what a -person hopes to do with an unadorned file? Fundamental mode is the -right default for such a file, just as C mode is the right default for -editing C code. But when you do know who is going to use Emacs--you, -yourself--then it makes sense to customize Emacs. - -For example, I seldom want Fundamental mode when I edit an otherwise -undistinguished file; I want Text mode. This is why I customize -Emacs: so it suits me. - -You can customize and extend Emacs by writing or adapting a -`~/.emacs' file. This is your personal initialization file; its -contents, written in Emacs Lisp, tell Emacs what to do.(1) - -A `~/.emacs' file contains Emacs Lisp code. You can write this code -yourself; or you can use Emacs' `customize' feature to write the code -for you. You can combine your own expressions and auto-written -Customize expressions in your `.emacs' file. - -(I myself prefer to write my own expressions, except for those, -particularly fonts, that I find easier to manipulate using the -`customize' command. I combine the two methods.) - -Most of this chapter is about writing expressions yourself. It -describes a simple `.emacs' file; for more information, see *Note The -Init File: (emacs)Init File, and *Note The Init File: (elisp)Init -File. - ----------- Footnotes ---------- - -(1) You may also add `.el' to `~/.emacs' and call it a `~/.emacs.el' -file. In the past, you were forbidden to type the extra keystrokes -that the name `~/.emacs.el' requires, but now you may. The new -format is consistent with the Emacs Lisp file naming conventions; the -old format saves typing. - -Site-wide Initialization Files -============================== - -In addition to your personal initialization file, Emacs automatically -loads various site-wide initialization files, if they exist. These -have the same form as your `.emacs' file, but are loaded by everyone. - -Two site-wide initialization files, `site-load.el' and -`site-init.el', are loaded into Emacs and then `dumped' if a `dumped' -version of Emacs is created, as is most common. (Dumped copies of -Emacs load more quickly. However, once a file is loaded and dumped, -a change to it does not lead to a change in Emacs unless you load it -yourself or re-dump Emacs. *Note Building Emacs: (elisp)Building -Emacs, and the `INSTALL' file.) - -Three other site-wide initialization files are loaded automatically -each time you start Emacs, if they exist. These are `site-start.el', -which is loaded _before_ your `.emacs' file, and `default.el', and -the terminal type file, which are both loaded _after_ your `.emacs' -file. - -Settings and definitions in your `.emacs' file will overwrite -conflicting settings and definitions in a `site-start.el' file, if it -exists; but the settings and definitions in a `default.el' or -terminal type file will overwrite those in your `.emacs' file. (You -can prevent interference from a terminal type file by setting -`term-file-prefix' to `nil'. *Note A Simple Extension: Simple -Extension.) - -The `INSTALL' file that comes in the distribution contains -descriptions of the `site-init.el' and `site-load.el' files. - -The `loadup.el', `startup.el', and `loaddefs.el' files control -loading. These files are in the `lisp' directory of the Emacs -distribution and are worth perusing. - -The `loaddefs.el' file contains a good many suggestions as to what to -put into your own `.emacs' file, or into a site-wide initialization -file. - -Specifying Variables using `defcustom' -====================================== - -You can specify variables using `defcustom' so that you and others -can then use Emacs' `customize' feature to set their values. (You -cannot use `customize' to write function definitions; but you can -write `defuns' in your `.emacs' file. Indeed, you can write any Lisp -expression in your `.emacs' file.) - -The `customize' feature depends on the `defcustom' special form. -Although you can use `defvar' or `setq' for variables that users set, -the `defcustom' special form is designed for the job. - -You can use your knowledge of `defvar' for writing the first three -arguments for `defcustom'. The first argument to `defcustom' is the -name of the variable. The second argument is the variable's initial -value, if any; and this value is set only if the value has not -already been set. The third argument is the documentation. - -The fourth and subsequent arguments to `defcustom' specify types and -options; these are not featured in `defvar'. (These arguments are -optional.) - -Each of these arguments consists of a keyword followed by a value. -Each keyword starts with the character `:'. - -For example, the customizable user option variable `text-mode-hook' -looks like this: - - (defcustom text-mode-hook nil - "Normal hook run when entering Text mode and many related modes." - :type 'hook - :options '(turn-on-auto-fill flyspell-mode) - :group 'data) - -The name of the variable is `text-mode-hook'; it has no default -value; and its documentation string tells you what it does. - -The `:type' keyword tells Emacs what kind of data `text-mode-hook' -should be set to and how to display the value in a Customization -buffer. - -The `:options' keyword specifies a suggested list of values for the -variable. Currently, you can use `:options' only for a hook. The -list is only a suggestion; it is not exclusive; a person who sets the -variable may set it to other values; the list shown following the -`:options' keyword is intended to offer convenient choices to a user. - -Finally, the `:group' keyword tells the Emacs Customization command -in which group the variable is located. This tells where to find it. - -For more information, see *Note Writing Customization Definitions: -(elisp)Customization. - -Consider `text-mode-hook' as an example. - -There are two ways to customize this variable. You can use the -customization command or write the appropriate expressions yourself. - -Using the customization command, you can type: - - M-x customize - -and find that the group for editing files of data is called `data'. -Enter that group. Text Mode Hook is the first member. You can click -on its various options to set the values. After you click on the -button to - - Save for Future Sessions - -Emacs will write an expression into your `.emacs' file. It will look -like this: - - (custom-set-variables - ;; custom-set-variables was added by Custom -- - ;; don't edit or cut/paste it! - ;; Your init file should contain only one such instance. - '(text-mode-hook (quote (turn-on-auto-fill text-mode-hook-identify)))) - -(The `text-mode-hook-identify' function tells -`toggle-text-mode-auto-fill' which buffers are in Text mode.) - -In spite of the warning, you certainly may edit, cut, and paste the -expression! I do all time. The purpose of the warning is to scare -those who do not know what they are doing, so they do not -inadvertently generate an error. - -The `custom-set-variables' works somewhat differently than a `setq'. -While I have never learned the differences, I do modify the -`custom-set-variables' expressions in my `.emacs' file by hand: I -make the changes in what appears to me to be a reasonable manner and -have not had any problems. Others prefer to use the Customization -command and let Emacs do the work for them. - -Another `custom-set-...' function is `custom-set-faces'. This -function sets the various font faces. Over time, I have set a -considerable number of faces. Some of the time, I re-set them using -`customize'; other times, I simply edit the `custom-set-faces' -expression in my `.emacs' file itself. - -The second way to customize your `text-mode-hook' is to set it -yourself in your `.emacs' file using code that has nothing to do with -the `custom-set-...' functions. - -When you do this, and later use `customize', you will see a message -that says - - this option has been changed outside the customize buffer. - -This message is only a warning. If you click on the button to - - Save for Future Sessions - -Emacs will write a `custom-set-...' expression near the end of your -`.emacs' file that will be evaluated after your hand-written -expression. It will, therefore, overrule your hand-written -expression. No harm will be done. When you do this, however, be -careful to remember which expression is active; if you forget, you -may confuse yourself. - -So long as you remember where the values are set, you will have no -trouble. In any event, the values are always set in your -initialization file, which is usually called `.emacs'. - -I myself use `customize' for hardly anything. Mostly, I write -expressions myself. - -Beginning a `.emacs' File -========================= - -When you start Emacs, it loads your `.emacs' file unless you tell it -not to by specifying `-q' on the command line. (The `emacs -q' -command gives you a plain, out-of-the-box Emacs.) - -A `.emacs' file contains Lisp expressions. Often, these are no more -than expressions to set values; sometimes they are function -definitions. - -*Note The Init File `~/.emacs': (emacs)Init File, for a short -description of initialization files. - -This chapter goes over some of the same ground, but is a walk among -extracts from a complete, long-used `.emacs' file--my own. - -The first part of the file consists of comments: reminders to myself. -By now, of course, I remember these things, but when I started, I did -not. - - ;;;; Bob's .emacs file - ; Robert J. Chassell - ; 26 September 1985 - -Look at that date! I started this file a long time ago. I have been -adding to it ever since. - - ; Each section in this file is introduced by a - ; line beginning with four semicolons; and each - ; entry is introduced by a line beginning with - ; three semicolons. - -This describes the usual conventions for comments in Emacs Lisp. -Everything on a line that follows a semicolon is a comment. Two, -three, and four semicolons are used as section and subsection -markers. (*Note Comments: (elisp)Comments, for more about comments.) - - ;;;; The Help Key - ; Control-h is the help key; - ; after typing control-h, type a letter to - ; indicate the subject about which you want help. - ; For an explanation of the help facility, - ; type control-h two times in a row. - -Just remember: type `C-h' two times for help. - - ; To find out about any mode, type control-h m - ; while in that mode. For example, to find out - ; about mail mode, enter mail mode and then type - ; control-h m. - -`Mode help', as I call this, is very helpful. Usually, it tells you -all you need to know. - -Of course, you don't need to include comments like these in your -`.emacs' file. I included them in mine because I kept forgetting -about Mode help or the conventions for comments--but I was able to -remember to look here to remind myself. - -Text and Auto Fill Mode -======================= - -Now we come to the part that `turns on' Text mode and Auto Fill mode. - - ;;; Text mode and Auto Fill mode - ; The next three lines put Emacs into Text mode - ; and Auto Fill mode, and are for writers who - ; want to start writing prose rather than code. - - (setq default-major-mode 'text-mode) - (add-hook 'text-mode-hook 'text-mode-hook-identify) - (add-hook 'text-mode-hook 'turn-on-auto-fill) - -Here is the first part of this `.emacs' file that does something -besides remind a forgetful human! - -The first of the two lines in parentheses tells Emacs to turn on Text -mode when you find a file, _unless_ that file should go into some -other mode, such as C mode. - -When Emacs reads a file, it looks at the extension to the file name, -if any. (The extension is the part that comes after a `.'.) If the -file ends with a `.c' or `.h' extension then Emacs turns on C mode. -Also, Emacs looks at first nonblank line of the file; if the line -says `-*- C -*-', Emacs turns on C mode. Emacs possesses a list of -extensions and specifications that it uses automatically. In -addition, Emacs looks near the last page for a per-buffer, "local -variables list", if any. - -*Note How Major Modes are Chosen: (emacs)Choosing Modes. - -*Note Local Variables in Files: (emacs)File Variables. - -Now, back to the `.emacs' file. - -Here is the line again; how does it work? - - (setq default-major-mode 'text-mode) - -This line is a short, but complete Emacs Lisp expression. - -We are already familiar with `setq'. It sets the following variable, -`default-major-mode', to the subsequent value, which is `text-mode'. -The single quote mark before `text-mode' tells Emacs to deal directly -with the `text-mode' variable, not with whatever it might stand for. -*Note Setting the Value of a Variable: set & setq, for a reminder of -how `setq' works. The main point is that there is no difference -between the procedure you use to set a value in your `.emacs' file -and the procedure you use anywhere else in Emacs. - -Here are the next two lines: - - (add-hook 'text-mode-hook 'text-mode-hook-identify) - (add-hook 'text-mode-hook 'turn-on-auto-fill) - -In these two lines, the `add-hook' command first adds -`text-mode-hook-identify' to the variable called `text-mode-hook' and -then adds `turn-on-auto-fill' to the variable. - -`turn-on-auto-fill' is the name of a program, that, you guessed it!, -turns on Auto Fill mode. `text-mode-hook-identify' is a function -that tells `toggle-text-mode-auto-fill' which buffers are in Text -mode. - -Every time Emacs turns on Text mode, Emacs runs the commands `hooked' -onto Text mode. So every time Emacs turns on Text mode, Emacs also -turns on Auto Fill mode. - -In brief, the first line causes Emacs to enter Text mode when you edit -a file, unless the file name extension, first non-blank line, or local -variables tell Emacs otherwise. - -Text mode among other actions, sets the syntax table to work -conveniently for writers. In Text mode, Emacs considers an apostrophe -as part of a word like a letter; but Emacs does not consider a period -or a space as part of a word. Thus, `M-f' moves you over `it's'. On -the other hand, in C mode, `M-f' stops just after the `t' of `it's'. - -The second and third lines causes Emacs to turn on Auto Fill mode when -it turns on Text mode. In Auto Fill mode, Emacs automatically breaks -a line that is too wide and brings the excessively wide part of the -line down to the next line. Emacs breaks lines between words, not -within them. - -When Auto Fill mode is turned off, lines continue to the right as you -type them. Depending on how you set the value of `truncate-lines', -the words you type either disappear off the right side of the screen, -or else are shown, in a rather ugly and unreadable manner, as a -continuation line on the screen. - -In addition, in this part of my `.emacs' file, I tell the Emacs fill -commands to insert two spaces after a colon: - - (setq colon-double-space t) - -Mail Aliases -============ - -Here is a `setq' that `turns on' mail aliases, along with more -reminders. - - ;;; Mail mode - ; To enter mail mode, type `C-x m' - ; To enter RMAIL (for reading mail), - ; type `M-x rmail' - - (setq mail-aliases t) - -This `setq' command sets the value of the variable `mail-aliases' to -`t'. Since `t' means true, the line says, in effect, "Yes, use mail -aliases." - -Mail aliases are convenient short names for long email addresses or -for lists of email addresses. The file where you keep your `aliases' -is `~/.mailrc'. You write an alias like this: - - alias geo george@foobar.wiz.edu - -When you write a message to George, address it to `geo'; the mailer -will automatically expand `geo' to the full address. - -Indent Tabs Mode -================ - -By default, Emacs inserts tabs in place of multiple spaces when it -formats a region. (For example, you might indent many lines of text -all at once with the `indent-region' command.) Tabs look fine on a -terminal or with ordinary printing, but they produce badly indented -output when you use TeX or Texinfo since TeX ignores tabs. - -The following turns off Indent Tabs mode: - - ;;; Prevent Extraneous Tabs - (setq-default indent-tabs-mode nil) - -Note that this line uses `setq-default' rather than the `setq' -command that we have seen before. The `setq-default' command sets -values only in buffers that do not have their own local values for -the variable. - -*Note Tabs vs. Spaces: (emacs)Just Spaces. - -*Note Local Variables in Files: (emacs)File Variables. - -Some Keybindings -================ - -Now for some personal keybindings: - - ;;; Compare windows - (global-set-key "\C-cw" 'compare-windows) - -`compare-windows' is a nifty command that compares the text in your -current window with text in the next window. It makes the comparison -by starting at point in each window, moving over text in each window -as far as they match. I use this command all the time. - -This also shows how to set a key globally, for all modes. - -The command is `global-set-key'. It is followed by the keybinding. -In a `.emacs' file, the keybinding is written as shown: `\C-c' stands -for `control-c', which means `press the control key and the `c' key -at the same time'. The `w' means `press the `w' key'. The -keybinding is surrounded by double quotation marks. In -documentation, you would write this as `C-c w'. (If you were binding -a <META> key, such as `M-c', rather than a <CTL> key, you would write -`\M-c'. *Note Rebinding Keys in Your Init File: (emacs)Init -Rebinding, for details.) - -The command invoked by the keys is `compare-windows'. Note that -`compare-windows' is preceded by a single quote; otherwise, Emacs -would first try to evaluate the symbol to determine its value. - -These three things, the double quotation marks, the backslash before -the `C', and the single quote mark are necessary parts of keybinding -that I tend to forget. Fortunately, I have come to remember that I -should look at my existing `.emacs' file, and adapt what is there. - -As for the keybinding itself: `C-c w'. This combines the prefix key, -`C-c', with a single character, in this case, `w'. This set of keys, -`C-c' followed by a single character, is strictly reserved for -individuals' own use. (I call these `own' keys, since these are for -my own use.) You should always be able to create such a keybinding -for your own use without stomping on someone else's keybinding. If -you ever write an extension to Emacs, please avoid taking any of -these keys for public use. Create a key like `C-c C-w' instead. -Otherwise, we will run out of `own' keys. - -Here is another keybinding, with a comment: - - ;;; Keybinding for `occur' - ; I use occur a lot, so let's bind it to a key: - (global-set-key "\C-co" 'occur) - -The `occur' command shows all the lines in the current buffer that -contain a match for a regular expression. Matching lines are shown -in a buffer called `*Occur*'. That buffer serves as a menu to jump -to occurrences. - -Here is how to unbind a key, so it does not work: - - ;;; Unbind `C-x f' - (global-unset-key "\C-xf") - -There is a reason for this unbinding: I found I inadvertently typed -`C-x f' when I meant to type `C-x C-f'. Rather than find a file, as -I intended, I accidentally set the width for filled text, almost -always to a width I did not want. Since I hardly ever reset my -default width, I simply unbound the key. - -The following rebinds an existing key: - - ;;; Rebind `C-x C-b' for `buffer-menu' - (global-set-key "\C-x\C-b" 'buffer-menu) - -By default, `C-x C-b' runs the `list-buffers' command. This command -lists your buffers in _another_ window. Since I almost always want -to do something in that window, I prefer the `buffer-menu' command, -which not only lists the buffers, but moves point into that window. - -Keymaps -======= - -Emacs uses "keymaps" to record which keys call which commands. When -you use `global-set-key' to set the keybinding for a single command -in all parts of Emacs, you are specifying the keybinding in -`current-global-map'. - -Specific modes, such as C mode or Text mode, have their own keymaps; -the mode-specific keymaps override the global map that is shared by -all buffers. - -The `global-set-key' function binds, or rebinds, the global keymap. -For example, the following binds the key `C-x C-b' to the function -`buffer-menu': - - (global-set-key "\C-x\C-b" 'buffer-menu) - -Mode-specific keymaps are bound using the `define-key' function, -which takes a specific keymap as an argument, as well as the key and -the command. For example, my `.emacs' file contains the following -expression to bind the `texinfo-insert-@group' command to `C-c C-c g': - - (define-key texinfo-mode-map "\C-c\C-cg" 'texinfo-insert-@group) - -The `texinfo-insert-@group' function itself is a little extension to -Texinfo mode that inserts `@group' into a Texinfo file. I use this -command all the time and prefer to type the three strokes `C-c C-c g' -rather than the six strokes `@ g r o u p'. (`@group' and its -matching `@end group' are commands that keep all enclosed text -together on one page; many multi-line examples in this book are -surrounded by `@group ... @end group'.) - -Here is the `texinfo-insert-@group' function definition: - - (defun texinfo-insert-@group () - "Insert the string @group in a Texinfo buffer." - (interactive) - (beginning-of-line) - (insert "@group\n")) - -(Of course, I could have used Abbrev mode to save typing, rather than -write a function to insert a word; but I prefer key strokes consistent -with other Texinfo mode key bindings.) - -You will see numerous `define-key' expressions in `loaddefs.el' as -well as in the various mode libraries, such as `cc-mode.el' and -`lisp-mode.el'. - -*Note Customizing Key Bindings: (emacs)Key Bindings, and *Note -Keymaps: (elisp)Keymaps, for more information about keymaps. - -Loading Files -============= - -Many people in the GNU Emacs community have written extensions to -Emacs. As time goes by, these extensions are often included in new -releases. For example, the Calendar and Diary packages are now part -of the standard GNU Emacs. - -(Calc, which I consider a vital part of Emacs, would be part of the -standard distribution except that it was so large it was packaged -separately and no one has changed that.) - -You can use a `load' command to evaluate a complete file and thereby -install all the functions and variables in the file into Emacs. For -example: - - (load "~/emacs/slowsplit") - -This evaluates, i.e. loads, the `slowsplit.el' file or if it exists, -the faster, byte compiled `slowsplit.elc' file from the `emacs' -sub-directory of your home directory. The file contains the function -`split-window-quietly', which John Robinson wrote in 1989. - -The `split-window-quietly' function splits a window with the minimum -of redisplay. I installed it in 1989 because it worked well with the -slow 1200 baud terminals I was then using. Nowadays, I only -occasionally come across such a slow connection, but I continue to use -the function because I like the way it leaves the bottom half of a -buffer in the lower of the new windows and the top half in the upper -window. - -To replace the key binding for the default `split-window-vertically', -you must also unset that key and bind the keys to -`split-window-quietly', like this: - - (global-unset-key "\C-x2") - (global-set-key "\C-x2" 'split-window-quietly) - -If you load many extensions, as I do, then instead of specifying the -exact location of the extension file, as shown above, you can specify -that directory as part of Emacs' `load-path'. Then, when Emacs loads -a file, it will search that directory as well as its default list of -directories. (The default list is specified in `paths.h' when Emacs -is built.) - -The following command adds your `~/emacs' directory to the existing -load path: - - ;;; Emacs Load Path - (setq load-path (cons "~/emacs" load-path)) - -Incidentally, `load-library' is an interactive interface to the -`load' function. The complete function looks like this: - - (defun load-library (library) - "Load the library named LIBRARY. - This is an interface to the function `load'." - (interactive "sLoad library: ") - (load library)) - -The name of the function, `load-library', comes from the use of -`library' as a conventional synonym for `file'. The source for the -`load-library' command is in the `files.el' library. - -Another interactive command that does a slightly different job is -`load-file'. *Note Libraries of Lisp Code for Emacs: (emacs)Lisp -Libraries, for information on the distinction between `load-library' -and this command. - -Autoloading -=========== - -Instead of installing a function by loading the file that contains it, -or by evaluating the function definition, you can make the function -available but not actually install it until it is first called. This -is called "autoloading". - -When you execute an autoloaded function, Emacs automatically evaluates -the file that contains the definition, and then calls the function. - -Emacs starts quicker with autoloaded functions, since their libraries -are not loaded right away; but you need to wait a moment when you -first use such a function, while its containing file is evaluated. - -Rarely used functions are frequently autoloaded. The `loaddefs.el' -library contains hundreds of autoloaded functions, from -`bookmark-set' to `wordstar-mode'. Of course, you may come to use a -`rare' function frequently. When you do, you should load that -function's file with a `load' expression in your `.emacs' file. - -In my `.emacs' file for Emacs version 21, I load 12 libraries that -contain functions that would otherwise be autoloaded. (Actually, it -would have been better to include these files in my `dumped' Emacs -when I built it, but I forgot. *Note Building Emacs: (elisp)Building -Emacs, and the `INSTALL' file for more about dumping.) - -You may also want to include autoloaded expressions in your `.emacs' -file. `autoload' is a built-in function that takes up to five -arguments, the final three of which are optional. The first argument -is the name of the function to be autoloaded; the second is the name -of the file to be loaded. The third argument is documentation for the -function, and the fourth tells whether the function can be called -interactively. The fifth argument tells what type of -object--`autoload' can handle a keymap or macro as well as a function -(the default is a function). - -Here is a typical example: - - (autoload 'html-helper-mode - "html-helper-mode" "Edit HTML documents" t) - -(`html-helper-mode' is an alternative to `html-mode', which is a -standard part of the distribution). - -This expression autoloads the `html-helper-mode' function. It takes -it from the `html-helper-mode.el' file (or from the byte compiled -file `html-helper-mode.elc', if it exists.) The file must be located -in a directory specified by `load-path'. The documentation says that -this is a mode to help you edit documents written in the HyperText -Markup Language. You can call this mode interactively by typing `M-x -html-helper-mode'. (You need to duplicate the function's regular -documentation in the autoload expression because the regular function -is not yet loaded, so its documentation is not available.) - -*Note Autoload: (elisp)Autoload, for more information. - -A Simple Extension: `line-to-top-of-window' -=========================================== - -Here is a simple extension to Emacs that moves the line point is on to -the top of the window. I use this all the time, to make text easier -to read. - -You can put the following code into a separate file and then load it -from your `.emacs' file, or you can include it within your `.emacs' -file. - -Here is the definition: - - ;;; Line to top of window; - ;;; replace three keystroke sequence C-u 0 C-l - (defun line-to-top-of-window () - "Move the line point is on to top of window." - (interactive) - (recenter 0)) - -Now for the keybinding. - -Nowadays, function keys as well as mouse button events and non-ASCII -characters are written within square brackets, without quotation -marks. (In Emacs version 18 and before, you had to write different -function key bindings for each different make of terminal.) - -I bind `line-to-top-of-window' to my <F6> function key like this: - - (global-set-key [f6] 'line-to-top-of-window) - -For more information, see *Note Rebinding Keys in Your Init File: -(emacs)Init Rebinding. - -If you run two versions of GNU Emacs, such as versions 20 and 21, and -use one `.emacs' file, you can select which code to evaluate with the -following conditional: - - (cond - ((string-equal (number-to-string 20) (substring (emacs-version) 10 12)) - ;; evaluate version 20 code - ( ... )) - ((string-equal (number-to-string 21) (substring (emacs-version) 10 12)) - ;; evaluate version 21 code - ( ... ))) - -For example, in contrast to version 20, version 21 blinks its cursor -by default. I hate such blinking, as well as some other features in -version 21, so I placed the following in my `.emacs' file(1): - - (if (string-equal "21" (substring (emacs-version) 10 12)) - (progn - (blink-cursor-mode 0) - ;; Insert newline when you press `C-n' (next-line) - ;; at the end of the buffer - (setq next-line-add-newlines t) - ;; Turn on image viewing - (auto-image-file-mode t) - ;; Turn on menu bar (this bar has text) - ;; (Use numeric argument to turn on) - (menu-bar-mode 1) - ;; Turn off tool bar (this bar has icons) - ;; (Use numeric argument to turn on) - (tool-bar-mode nil) - ;; Turn off tooltip mode for tool bar - ;; (This mode causes icon explanations to pop up) - ;; (Use numeric argument to turn on) - (tooltip-mode nil) - ;; If tooltips turned on, make tips appear promptly - (setq tooltip-delay 0.1) ; default is one second - )) - -(You will note that instead of typing `(number-to-string 21)', I -decided to save typing and wrote `21' as a string, `"21"', rather -than convert it from an integer to a string. In this instance, this -expression is better than the longer, but more general -`(number-to-string 21)'. However, if you do not know ahead of time -what type of information will be returned, then the -`number-to-string' function will be needed.) - ----------- Footnotes ---------- - -(1) When I start instances of Emacs that do not load my `.emacs' file -or any site file, I also turn off blinking: - - emacs -q --no-site-file -eval '(blink-cursor-mode nil)' - -X11 Colors -========== - -You can specify colors when you use Emacs with the MIT X Windowing -system. - -I dislike the default colors and specify my own. - -Here are the expressions in my `.emacs' file that set values: - - ;; Set cursor color - (set-cursor-color "white") - - ;; Set mouse color - (set-mouse-color "white") - - ;; Set foreground and background - (set-foreground-color "white") - (set-background-color "darkblue") - - ;;; Set highlighting colors for isearch and drag - (set-face-foreground 'highlight "white") - (set-face-background 'highlight "blue") - - (set-face-foreground 'region "cyan") - (set-face-background 'region "blue") - - (set-face-foreground 'secondary-selection "skyblue") - (set-face-background 'secondary-selection "darkblue") - - ;; Set calendar highlighting colors - (setq calendar-load-hook - '(lambda () - (set-face-foreground 'diary-face "skyblue") - (set-face-background 'holiday-face "slate blue") - (set-face-foreground 'holiday-face "white"))) - -The various shades of blue soothe my eye and prevent me from seeing -the screen flicker. - -Alternatively, I could have set my specifications in various X -initialization files. For example, I could set the foreground, -background, cursor, and pointer (i.e., mouse) colors in my -`~/.Xresources' file like this: - - Emacs*foreground: white - Emacs*background: darkblue - Emacs*cursorColor: white - Emacs*pointerColor: white - -In any event, since it is not part of Emacs, I set the root color of -my X window in my `~/.xinitrc' file, like this(1): - - # I use TWM for window manager. - xsetroot -solid Navy -fg white & - ----------- Footnotes ---------- - -(1) I occasionally run more modern window managers, such as Sawfish -with GNOME, Enlightenment, SCWM, or KDE; in those cases, I often -specify an image rather than a plain color. - -Miscellaneous Settings for a `.emacs' File -========================================== - -Here are a few miscellaneous settings: - - - Set the shape and color of the mouse cursor: - ; Cursor shapes are defined in - ; `/usr/include/X11/cursorfont.h'; - ; for example, the `target' cursor is number 128; - ; the `top_left_arrow' cursor is number 132. - - (let ((mpointer (x-get-resource "*mpointer" - "*emacs*mpointer"))) - ;; If you have not set your mouse pointer - ;; then set it, otherwise leave as is: - (if (eq mpointer nil) - (setq mpointer "132")) ; top_left_arrow - (setq x-pointer-shape (string-to-int mpointer)) - (set-mouse-color "white")) - -A Modified Mode Line -==================== - -Finally, a feature I really like: a modified mode line. - -When I work over a network, I forget which machine I am using. Also, -I tend to I lose track of where I am, and which line point is on. - -So I reset my mode line to look like this: - - -:-- foo.texi rattlesnake:/home/bob/ Line 1 (Texinfo Fill) Top - -I am visiting a file called `foo.texi', on my machine `rattlesnake' -in my `/home/bob' buffer. I am on line 1, in Texinfo mode, and am at -the top of the buffer. - -My `.emacs' file has a section that looks like this: - - ;; Set a Mode Line that tells me which machine, which directory, - ;; and which line I am on, plus the other customary information. - (setq default-mode-line-format - (quote - (#("-" 0 1 - (help-echo - "mouse-1: select window, mouse-2: delete others ...")) - mode-line-mule-info - mode-line-modified - mode-line-frame-identification - " " - mode-line-buffer-identification - " " - (:eval (substring - (system-name) 0 (string-match "\\..+" (system-name)))) - ":" - default-directory - #(" " 0 1 - (help-echo - "mouse-1: select window, mouse-2: delete others ...")) - (line-number-mode " Line %l ") - global-mode-string - #(" %[(" 0 6 - (help-echo - "mouse-1: select window, mouse-2: delete others ...")) - (:eval (mode-line-mode-name)) - mode-line-process - minor-mode-alist - #("%n" 0 2 (help-echo "mouse-2: widen" local-map (keymap ...))) - ")%] " - (-3 . "%P") - ;; "-%-" - ))) - -Here, I redefine the default mode line. Most of the parts are from -the original; but I make a few changes. I set the _default_ mode -line format so as to permit various modes, such as Info, to override -it. - -Many elements in the list are self-explanatory: `mode-line-modified' -is a variable that tells whether the buffer has been modified, -`mode-name' tells the name of the mode, and so on. However, the -format looks complicated because of two features we have not -discussed. - -The first string in the mode line is a dash or hyphen, `-'. In the -old days, it would have been specified simply as `"-"'. But -nowadays, Emacs can add properties to a string, such as highlighting -or, as in this case, a help feature. If you place your mouse cursor -over the hyphen, some help information appears (By default, you must -wait one second before the information appears. You can change that -timing by changing the value of `tooltip-delay'.) - -The new string format has a special syntax: - - #("-" 0 1 (help-echo "mouse-1: select window, ...")) - -The `#(' begins a list. The first element of the list is the string -itself, just one `-'. The second and third elements specify the -range over which the fourth element applies. A range starts _after_ -a character, so a zero means the range starts just before the first -character; a 1 means that the range ends just after the first -character. The third element is the property for the range. It -consists of a property list, a property name, in this case, -`help-echo', followed by a value, in this case, a string. The -second, third, and fourth elements of this new string format can be -repeated. - -*Note Text Properties in String: (elisp)Text Props and Strings, and -see *Note Mode Line Format: (elisp)Mode Line Format, for more -information. - -`mode-line-buffer-identification' displays the current buffer name. -It is a list beginning `(#("%12b" 0 4 ...'. The `#(' begins the list. - -The `"%12b"' displays the current buffer name, using the -`buffer-name' function with which we are familiar; the `12' specifies -the maximum number of characters that will be displayed. When a name -has fewer characters, whitespace is added to fill out to this number. -(Buffer names can and often should be longer than 12 characters; -this length works well in a typical 80 column wide window.) - -`:eval' is a new feature in GNU Emacs version 21. It says to -evaluate the following form and use the result as a string to display. -In this case, the expression displays the first component of the full -system name. The end of the first component is a `.' (`period'), so -I use the `string-match' function to tell me the length of the first -component. The substring from the zeroth character to that length is -the name of the machine. - -This is the expression: - - (:eval (substring - (system-name) 0 (string-match "\\..+" (system-name)))) - -`%[' and `%]' cause a pair of square brackets to appear for each -recursive editing level. `%n' says `Narrow' when narrowing is in -effect. `%P' tells you the percentage of the buffer that is above -the bottom of the window, or `Top', `Bottom', or `All'. (A lower -case `p' tell you the percentage above the _top_ of the window.) -`%-' inserts enough dashes to fill out the line. - -Remember, "You don't have to like Emacs to like it" -- your own Emacs -can have different colors, different commands, and different keys -than a default Emacs. - -On the other hand, if you want to bring up a plain `out of the box' -Emacs, with no customization, type: - - emacs -q - -This will start an Emacs that does _not_ load your `~/.emacs' -initialization file. A plain, default Emacs. Nothing more. - -Debugging -********* - -GNU Emacs has two debuggers, `debug' and `edebug'. The first is -built into the internals of Emacs and is always with you; the second -requires that you instrument a function before you can use it. - -Both debuggers are described extensively in *Note Debugging Lisp -Programs: (elisp)Debugging. In this chapter, I will walk through a -short example of each. - -`debug' -======= - -Suppose you have written a function definition that is intended to -return the sum of the numbers 1 through a given number. (This is the -`triangle' function discussed earlier. *Note Example with -Decrementing Counter: Decrementing Example, for a discussion.) - -However, your function definition has a bug. You have mistyped `1=' -for `1-'. Here is the broken definition: - - (defun triangle-bugged (number) - "Return sum of numbers 1 through NUMBER inclusive." - (let ((total 0)) - (while (> number 0) - (setq total (+ total number)) - (setq number (1= number))) ; Error here. - total)) - -If you are reading this in Info, you can evaluate this definition in -the normal fashion. You will see `triangle-bugged' appear in the -echo area. - -Now evaluate the `triangle-bugged' function with an argument of 4: - - (triangle-bugged 4) - -In GNU Emacs version 21, you will create and enter a `*Backtrace*' -buffer that says: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--Lisp error: (void-function 1=) - (1= number) - (setq number (1= number)) - (while (> number 0) (setq total (+ total number)) - (setq number (1= number))) - (let ((total 0)) (while (> number 0) (setq total ...) - (setq number ...)) total) - triangle-bugged(4) - eval((triangle-bugged 4)) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -(I have reformatted this example slightly; the debugger does not fold -long lines. As usual, you can quit the debugger by typing `q' in the -`*Backtrace*' buffer.) - -In practice, for a bug as simple as this, the `Lisp error' line will -tell you what you need to know to correct the definition. The -function `1=' is `void'. - -In GNU Emacs 20 and before, you will see: - - Symbol's function definition is void: 1= - -which has the same meaning as the `*Backtrace*' buffer line in -version 21. - -However, suppose you are not quite certain what is going on? You can -read the complete backtrace. - -In this case, you need to run GNU Emacs 21, which automatically starts -the debugger that puts you in the `*Backtrace*' buffer; or else, you -need to start the debugger manually as described below. - -Read the `*Backtrace*' buffer from the bottom up; it tells you what -Emacs did that led to the error. Emacs made an interactive call to -`C-x C-e' (`eval-last-sexp'), which led to the evaluation of the -`triangle-bugged' expression. Each line above tells you what the -Lisp interpreter evaluated next. - -The third line from the top of the buffer is - - (setq number (1= number)) - -Emacs tried to evaluate this expression; in order to do so, it tried -to evaluate the inner expression shown on the second line from the -top: - - (1= number) - -This is where the error occurred; as the top line says: - - Debugger entered--Lisp error: (void-function 1=) - -You can correct the mistake, re-evaluate the function definition, and -then run your test again. - -`debug-on-entry' -================ - -GNU Emacs 21 starts the debugger automatically when your function has -an error. GNU Emacs version 20 and before did not; it simply -presented you with an error message. You had to start the debugger -manually. - -You can start the debugger manually for all versions of Emacs; the -advantage is that the debugger runs even if you do not have a bug in -your code. Sometimes your code will be free of bugs! - -You can enter the debugger when you call the function by calling -`debug-on-entry'. - -Type: - - M-x debug-on-entry RET triangle-bugged RET - -Now, evaluate the following: - - (triangle-bugged 5) - -All versions of Emacs will create a `*Backtrace*' buffer and tell you -that it is beginning to evaluate the `triangle-bugged' function: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--entering a function: - * triangle-bugged(5) - eval((triangle-bugged 5)) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -In the `*Backtrace*' buffer, type `d'. Emacs will evaluate the first -expression in `triangle-bugged'; the buffer will look like this: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--beginning evaluation of function call form: - * (let ((total 0)) (while (> number 0) (setq total ...) - (setq number ...)) total) - * triangle-bugged(5) - eval((triangle-bugged 5)) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -Now, type `d' again, eight times, slowly. Each time you type `d', -Emacs will evaluate another expression in the function definition. - -Eventually, the buffer will look like this: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--beginning evaluation of function call form: - * (setq number (1= number)) - * (while (> number 0) (setq total (+ total number)) - (setq number (1= number))) - * (let ((total 0)) (while (> number 0) (setq total ...) - (setq number ...)) total) - * triangle-bugged(5) - eval((triangle-bugged 5)) - eval-last-sexp-1(nil) - eval-last-sexp(nil) - call-interactively(eval-last-sexp) - ---------- Buffer: *Backtrace* ---------- - -Finally, after you type `d' two more times, Emacs will reach the -error, and the top two lines of the `*Backtrace*' buffer will look -like this: - - ---------- Buffer: *Backtrace* ---------- - Debugger entered--Lisp error: (void-function 1=) - * (1= number) - ... - ---------- Buffer: *Backtrace* ---------- - -By typing `d', you were able to step through the function. - -You can quit a `*Backtrace*' buffer by typing `q' in it; this quits -the trace, but does not cancel `debug-on-entry'. - -To cancel the effect of `debug-on-entry', call -`cancel-debug-on-entry' and the name of the function, like this: - - M-x cancel-debug-on-entry RET triangle-bugged RET - -(If you are reading this in Info, cancel `debug-on-entry' now.) - -`debug-on-quit' and `(debug)' -============================= - -In addition to setting `debug-on-error' or calling `debug-on-entry', -there are two other ways to start `debug'. - -You can start `debug' whenever you type `C-g' (`keyboard-quit') by -setting the variable `debug-on-quit' to `t'. This is useful for -debugging infinite loops. - -Or, you can insert a line that says `(debug)' into your code where -you want the debugger to start, like this: - - (defun triangle-bugged (number) - "Return sum of numbers 1 through NUMBER inclusive." - (let ((total 0)) - (while (> number 0) - (setq total (+ total number)) - (debug) ; Start debugger. - (setq number (1= number))) ; Error here. - total)) - -The `debug' function is described in detail in *Note The Lisp -Debugger: (elisp)Debugger. - -The `edebug' Source Level Debugger -================================== - -Edebug is a source level debugger. Edebug normally displays the -source of the code you are debugging, with an arrow at the left that -shows which line you are currently executing. - -You can walk through the execution of a function, line by line, or run -quickly until reaching a "breakpoint" where execution stops. - -Edebug is described in *Note Edebug: (elisp)edebug. - -Here is a bugged function definition for `triangle-recursively'. -*Note Recursion in place of a counter: Recursive triangle function, -for a review of it. - - (defun triangle-recursively-bugged (number) - "Return sum of numbers 1 through NUMBER inclusive. - Uses recursion." - (if (= number 1) - 1 - (+ number - (triangle-recursively-bugged - (1= number))))) ; Error here. - -Normally, you would install this definition by positioning your cursor -after the function's closing parenthesis and typing `C-x C-e' -(`eval-last-sexp') or else by positioning your cursor within the -definition and typing `C-M-x' (`eval-defun'). (By default, the -`eval-defun' command works only in Emacs Lisp mode or in Lisp -Interactive mode.) - -However, to prepare this function definition for Edebug, you must -first "instrument" the code using a different command. You can do -this by positioning your cursor within the definition and typing - - M-x edebug-defun RET - -This will cause Emacs to load Edebug automatically if it is not -already loaded, and properly instrument the function. - -After instrumenting the function, place your cursor after the -following expression and type `C-x C-e' (`eval-last-sexp'): - - (triangle-recursively-bugged 3) - -You will be jumped back to the source for -`triangle-recursively-bugged' and the cursor positioned at the -beginning of the `if' line of the function. Also, you will see an -arrowhead at the left hand side of that line. The arrowhead marks -the line where the function is executing. (In the following examples, -we show the arrowhead with `=>'; in a windowing system, you may see -the arrowhead as a solid triangle in the window `fringe'.) - - =>-!-(if (= number 1) - -In the example, the location of point is displayed as `-!-' (in a -printed book, it is displayed with a five pointed star). - -If you now press <SPC>, point will move to the next expression to be -executed; the line will look like this: - - =>(if -!-(= number 1) - -As you continue to press <SPC>, point will move from expression to -expression. At the same time, whenever an expression returns a value, -that value will be displayed in the echo area. For example, after you -move point past `number', you will see the following: - - Result: 3 = C-c - -This means the value of `number' is 3, which is ASCII `control-c' -(the third letter of the alphabet). - -You can continue moving through the code until you reach the line with -the error. Before evaluation, that line looks like this: - - => -!-(1= number))))) ; Error here. - -When you press <SPC> once again, you will produce an error message -that says: - - Symbol's function definition is void: 1= - -This is the bug. - -Press `q' to quit Edebug. - -To remove instrumentation from a function definition, simply -re-evaluate it with a command that does not instrument it. For -example, you could place your cursor after the definition's closing -parenthesis and type `C-x C-e'. - -Edebug does a great deal more than walk with you through a function. -You can set it so it races through on its own, stopping only at an -error or at specified stopping points; you can cause it to display the -changing values of various expressions; you can find out how many -times a function is called, and more. - -Edebug is described in *Note Edebug: (elisp)edebug. - -Debugging Exercises -=================== - - * Install the `count-words-region' function and then cause it to - enter the built-in debugger when you call it. Run the command - on a region containing two words. You will need to press `d' a - remarkable number of times. On your system, is a `hook' called - after the command finishes? (For information on hooks, see - *Note Command Loop Overview: (elisp)Command Overview.) - - * Copy `count-words-region' into the `*scratch*' buffer, - instrument the function for Edebug, and walk through its - execution. The function does not need to have a bug, although - you can introduce one if you wish. If the function lacks a bug, - the walk-through completes without problems. - - * While running Edebug, type `?' to see a list of all the Edebug - commands. (The `global-edebug-prefix' is usually `C-x X', i.e. - `<CTL>-x' followed by an upper case `X'; use this prefix for - commands made outside of the Edebug debugging buffer.) - - * In the Edebug debugging buffer, use the `p' - (`edebug-bounce-point') command to see where in the region the - `count-words-region' is working. - - * Move point to some spot further down function and then type the - `h' (`edebug-goto-here') command to jump to that location. - - * Use the `t' (`edebug-trace-mode') command to cause Edebug to - walk through the function on its own; use an upper case `T' for - `edebug-Trace-fast-mode'. - - * Set a breakpoint, then run Edebug in Trace mode until it reaches - the stopping point. - -Conclusion -********** - -We have now reached the end of this Introduction. You have now -learned enough about programming in Emacs Lisp to set values, to write -simple `.emacs' files for yourself and your friends, and write simple -customizations and extensions to Emacs. - -This is a place to stop. Or, if you wish, you can now go onward, and -teach yourself. - -You have learned some of the basic nuts and bolts of programming. But -only some. There are a great many more brackets and hinges that are -easy to use that we have not touched. - -A path you can follow right now lies among the sources to GNU Emacs -and in *Note The GNU Emacs Lisp Reference Manual: (elisp)Top. - -The Emacs Lisp sources are an adventure. When you read the sources -and come across a function or expression that is unfamiliar, you need -to figure out or find out what it does. - -Go to the Reference Manual. It is a thorough, complete, and fairly -easy-to-read description of Emacs Lisp. It is written not only for -experts, but for people who know what you know. (The `Reference -Manual' comes with the standard GNU Emacs distribution. Like this -introduction, it comes as a Texinfo source file, so you can read it -on-line and as a typeset, printed book.) - -Go to the other on-line help that is part of GNU Emacs: the on-line -documentation for all functions, and `find-tags', the program that -takes you to sources. - -Here is an example of how I explore the sources. Because of its name, -`simple.el' is the file I looked at first, a long time ago. As it -happens some of the functions in `simple.el' are complicated, or at -least look complicated at first sight. The `open-line' function, for -example, looks complicated. - -You may want to walk through this function slowly, as we did with the -`forward-sentence' function. (*Note forward-sentence::.) Or you may -want to skip that function and look at another, such as `split-line'. -You don't need to read all the functions. According to -`count-words-in-defun', the `split-line' function contains 27 words -and symbols. - -Even though it is short, `split-line' contains four expressions we -have not studied: `skip-chars-forward', `indent-to', `current-column' -and `?\n'. - -Consider the `skip-chars-forward' function. (It is part of the -function definition for `back-to-indentation', which is shown in -*Note Review: Review.) - -In GNU Emacs, you can find out more about `skip-chars-forward' by -typing `C-h f' (`describe-function') and the name of the function. -This gives you the function documentation. - -You may be able to guess what is done by a well named function such as -`indent-to'; or you can look it up, too. Incidentally, the -`describe-function' function itself is in `help.el'; it is one of -those long, but decipherable functions. You can look up -`describe-function' using the `C-h f' command! - -In this instance, since the code is Lisp, the `*Help*' buffer -contains the name of the library containing the function's source. -You can put point over the name of the library and press the RET key, -which in this situation is bound to `help-follow', and be taken -directly to the source, in the same way as `M-.' (`find-tag'). - -The definition for `describe-function' illustrates how to customize -the `interactive' expression without using the standard character -codes; and it shows how to create a temporary buffer. - -(The `indent-to' function is written in C rather than Emacs Lisp; it -is a `built-in' function. `help-follow' only provides you with the -documentation of a built-in function; it does not take you to the -source. But `find-tag' will take you to the source, if properly set -up.) - -You can look at a function's source using `find-tag', which is bound -to `M-.' Finally, you can find out what the Reference Manual has to -say by visiting the manual in Info, and typing `i' (`Info-index') and -the name of the function, or by looking up `skip-chars-forward' in -the index to a printed copy of the manual. - -Similarly, you can find out what is meant by `?\n'. You can try -using `Info-index' with `?\n'. It turns out that this action won't -help; but don't give up. If you search the index for `\n' without -the `?', you will be taken directly to the relevant section of the -manual. (*Note Character Type: (elisp)Character Type. `?\n' stands -for the newline character.) - -Other interesting source files include `paragraphs.el', -`loaddefs.el', and `loadup.el'. The `paragraphs.el' file includes -short, easily understood functions as well as longer ones. The -`loaddefs.el' file contains the many standard autoloads and many -keymaps. I have never looked at it all; only at parts. `loadup.el' -is the file that loads the standard parts of Emacs; it tells you a -great deal about how Emacs is built. (*Note Building Emacs: -(elisp)Building Emacs, for more about building.) - -As I said, you have learned some nuts and bolts; however, and very -importantly, we have hardly touched major aspects of programming; I -have said nothing about how to sort information, except to use the -predefined `sort' function; I have said nothing about how to store -information, except to use variables and lists; I have said nothing -about how to write programs that write programs. These are topics for -another, and different kind of book, a different kind of learning. - -What you have done is learn enough for much practical work with GNU -Emacs. What you have done is get started. This is the end of a -beginning. - -The `the-the' Function -********************** - -Sometimes when you you write text, you duplicate words--as with "you -you" near the beginning of this sentence. I find that most -frequently, I duplicate "the'; hence, I call the function for -detecting duplicated words, `the-the'. - -As a first step, you could use the following regular expression to -search for duplicates: - - \\(\\w+[ \t\n]+\\)\\1 - -This regexp matches one or more word-constituent characters followed -by one or more spaces, tabs, or newlines. However, it does not detect -duplicated words on different lines, since the ending of the first -word, the end of the line, is different from the ending of the second -word, a space. (For more information about regular expressions, see -*Note Regular Expression Searches: Regexp Search, as well as *Note -Syntax of Regular Expressions: (emacs)Regexps, and *Note Regular -Expressions: (elisp)Regular Expressions.) - -You might try searching just for duplicated word-constituent -characters but that does not work since the pattern detects doubles -such as the two occurrences of `th' in `with the'. - -Another possible regexp searches for word-constituent characters -followed by non-word-constituent characters, reduplicated. Here, -`\\w+' matches one or more word-constituent characters and `\\W*' -matches zero or more non-word-constituent characters. - - \\(\\(\\w+\\)\\W*\\)\\1 - -Again, not useful. - -Here is the pattern that I use. It is not perfect, but good enough. -`\\b' matches the empty string, provided it is at the beginning or -end of a word; `[^@ \n\t]+' matches one or more occurrences of any -characters that are _not_ an @-sign, space, newline, or tab. - - \\b\\([^@ \n\t]+\\)[ \n\t]+\\1\\b - -One can write more complicated expressions, but I found that this -expression is good enough, so I use it. - -Here is the `the-the' function, as I include it in my `.emacs' file, -along with a handy global key binding: - - (defun the-the () - "Search forward for for a duplicated word." - (interactive) - (message "Searching for for duplicated words ...") - (push-mark) - ;; This regexp is not perfect - ;; but is fairly good over all: - (if (re-search-forward - "\\b\\([^@ \n\t]+\\)[ \n\t]+\\1\\b" nil 'move) - (message "Found duplicated word.") - (message "End of buffer"))) - - ;; Bind `the-the' to C-c \ - (global-set-key "\C-c\\" 'the-the) - - -Here is test text: - - one two two three four five - five six seven - -You can substitute the other regular expressions shown above in the -function definition and try each of them on this list. - -Handling the Kill Ring -********************** - -The kill ring is a list that is transformed into a ring by the -workings of the `rotate-yank-pointer' function. The `yank' and -`yank-pop' commands use the `rotate-yank-pointer' function. This -appendix describes the `rotate-yank-pointer' function as well as both -the `yank' and the `yank-pop' commands. - -The `rotate-yank-pointer' Function -================================== - -The `rotate-yank-pointer' function changes the element in the kill -ring to which `kill-ring-yank-pointer' points. For example, it can -change `kill-ring-yank-pointer' from pointing to the second element -to point to the third element. - -Here is the code for `rotate-yank-pointer': - - (defun rotate-yank-pointer (arg) - "Rotate the yanking point in the kill ring." - (interactive "p") - (let ((length (length kill-ring))) - (if (zerop length) - ;; then-part - (error "Kill ring is empty") - ;; else-part - (setq kill-ring-yank-pointer - (nthcdr (% (+ arg - (- length - (length - kill-ring-yank-pointer))) - length) - kill-ring))))) - -`rotate-yank-pointer' in Outline --------------------------------- - -The `rotate-yank-pointer' function looks complex, but as usual, it -can be understood by taking it apart piece by piece. First look at -it in skeletal form: - - (defun rotate-yank-pointer (arg) - "Rotate the yanking point in the kill ring." - (interactive "p") - (let VARLIST - BODY...) - -This function takes one argument, called `arg'. It has a brief -documentation string; and it is interactive with a small `p', which -means that the argument must be a processed prefix passed to the -function as a number. - -The body of the function definition is a `let' expression, which -itself has a body as well as a VARLIST. - -The `let' expression declares a variable that will be only usable -within the bounds of this function. This variable is called `length' -and is bound to a value that is equal to the number of items in the -kill ring. This is done by using the function called `length'. -(Note that this function has the same name as the variable called -`length'; but one use of the word is to name the function and the -other is to name the variable. The two are quite distinct. -Similarly, an English speaker will distinguish between the meanings -of the word `ship' when he says: "I must ship this package -immediately." and "I must get aboard the ship immediately.") - -The function `length' tells the number of items there are in a list, -so `(length kill-ring)' returns the number of items there are in the -kill ring. - -The Body of `rotate-yank-pointer' ---------------------------------- - -The body of `rotate-yank-pointer' is a `let' expression and the body -of the `let' expression is an `if' expression. - -The purpose of the `if' expression is to find out whether there is -anything in the kill ring. If the kill ring is empty, the `error' -function stops evaluation of the function and prints a message in the -echo area. On the other hand, if the kill ring has something in it, -the work of the function is done. - -Here is the if-part and then-part of the `if' expression: - - (if (zerop length) ; if-part - (error "Kill ring is empty") ; then-part - ... - -If there is not anything in the kill ring, its length must be zero and -an error message sent to the user: `Kill ring is empty'. The `if' -expression uses the function `zerop' which returns true if the value -it is testing is zero. When `zerop' tests true, the then-part of the -`if' is evaluated. The then-part is a list starting with the -function `error', which is a function that is similar to the -`message' function (*note message::), in that it prints a one-line -message in the echo area. However, in addition to printing a -message, `error' also stops evaluation of the function within which -it is embedded. This means that the rest of the function will not be -evaluated if the length of the kill ring is zero. - -Digression about the word `error' -................................. - -(In my opinion, it is slightly misleading, at least to humans, to use -the term `error' as the name of the `error' function. A better term -would be `cancel'. Strictly speaking, of course, you cannot point -to, much less rotate a pointer to a list that has no length, so from -the point of view of the computer, the word `error' is correct. But -a human expects to attempt this sort of thing, if only to find out -whether the kill ring is full or empty. This is an act of -exploration. - -(From the human point of view, the act of exploration and discovery is -not necessarily an error, and therefore should not be labelled as one, -even in the bowels of a computer. As it is, the code in Emacs implies -that a human who is acting virtuously, by exploring his or her -environment, is making an error. This is bad. Even though the -computer takes the same steps as it does when there is an `error', a -term such as `cancel' would have a clearer connotation.) - -The else-part of the `if' expression -.................................... - -The else-part of the `if' expression is dedicated to setting the -value of `kill-ring-yank-pointer' when the kill ring has something in -it. The code looks like this: - - (setq kill-ring-yank-pointer - (nthcdr (% (+ arg - (- length - (length kill-ring-yank-pointer))) - length) - kill-ring))))) - -This needs some examination. Clearly, `kill-ring-yank-pointer' is -being set to be equal to some CDR of the kill ring, using the -`nthcdr' function that is described in an earlier section. (*Note -copy-region-as-kill::.) But exactly how does it do this? - -Before looking at the details of the code let's first consider the -purpose of the `rotate-yank-pointer' function. - -The `rotate-yank-pointer' function changes what -`kill-ring-yank-pointer' points to. If `kill-ring-yank-pointer' -starts by pointing to the first element of a list, a call to -`rotate-yank-pointer' causes it to point to the second element; and -if `kill-ring-yank-pointer' points to the second element, a call to -`rotate-yank-pointer' causes it to point to the third element. (And -if `rotate-yank-pointer' is given an argument greater than 1, it -jumps the pointer that many elements.) - -The `rotate-yank-pointer' function uses `setq' to reset what the -`kill-ring-yank-pointer' points to. If `kill-ring-yank-pointer' -points to the first element of the kill ring, then, in the simplest -case, the `rotate-yank-pointer' function must cause it to point to -the second element. Put another way, `kill-ring-yank-pointer' must -be reset to have a value equal to the CDR of the kill ring. - -That is, under these circumstances, - - (setq kill-ring-yank-pointer - ("some text" "a different piece of text" "yet more text")) - - (setq kill-ring - ("some text" "a different piece of text" "yet more text")) - -the code should do this: - - (setq kill-ring-yank-pointer (cdr kill-ring)) - -As a result, the `kill-ring-yank-pointer' will look like this: - - kill-ring-yank-pointer - => ("a different piece of text" "yet more text")) - -The actual `setq' expression uses the `nthcdr' function to do the job. - -As we have seen before (*note nthcdr::), the `nthcdr' function works -by repeatedly taking the CDR of a list--it takes the CDR of the CDR -of the CDR ... - -The two following expressions produce the same result: - - (setq kill-ring-yank-pointer (cdr kill-ring)) - - (setq kill-ring-yank-pointer (nthcdr 1 kill-ring)) - -In the `rotate-yank-pointer' function, however, the first argument to -`nthcdr' is a rather complex looking expression with lots of -arithmetic inside of it: - - (% (+ arg - (- length - (length kill-ring-yank-pointer))) - length) - -As usual, we need to look at the most deeply embedded expression first -and then work our way towards the light. - -The most deeply embedded expression is `(length -kill-ring-yank-pointer)'. This finds the length of the current value -of the `kill-ring-yank-pointer'. (Remember that the -`kill-ring-yank-pointer' is the name of a variable whose value is a -list.) - -The measurement of the length is inside the expression: - - (- length (length kill-ring-yank-pointer)) - -In this expression, the first `length' is the variable that was -assigned the length of the kill ring in the `let' statement at the -beginning of the function. (One might think this function would be -clearer if the variable `length' were named `length-of-kill-ring' -instead; but if you look at the text of the whole function, you will -see that it is so short that naming this variable `length' is not a -bother, unless you are pulling the function apart into very tiny -pieces as we are doing here.) - -So the line `(- length (length kill-ring-yank-pointer))' tells the -difference between the length of the kill ring and the length of the -list whose name is `kill-ring-yank-pointer'. - -To see how all this fits into the `rotate-yank-pointer' function, -let's begin by analyzing the case where `kill-ring-yank-pointer' -points to the first element of the kill ring, just as `kill-ring' -does, and see what happens when `rotate-yank-pointer' is called with -an argument of 1. - -The variable `length' and the value of the expression `(length -kill-ring-yank-pointer)' will be the same since the variable `length' -is the length of the kill ring and the `kill-ring-yank-pointer' is -pointing to the whole kill ring. Consequently, the value of - - (- length (length kill-ring-yank-pointer)) - -will be zero. Since the value of `arg' will be 1, this will mean -that the value of the whole expression - - (+ arg (- length (length kill-ring-yank-pointer))) - -will be 1. - -Consequently, the argument to `nthcdr' will be found as the result of -the expression - - (% 1 length) - -The `%' remainder function -.......................... - -To understand `(% 1 length)', we need to understand `%'. According -to its documentation (which I just found by typing `C-h f % <RET>'), -the `%' function returns the remainder of its first argument divided -by its second argument. For example, the remainder of 5 divided by 2 -is 1. (2 goes into 5 twice with a remainder of 1.) - -What surprises people who don't often do arithmetic is that a smaller -number can be divided by a larger number and have a remainder. In the -example we just used, 5 was divided by 2. We can reverse that and -ask, what is the result of dividing 2 by 5? If you can use -fractions, the answer is obviously 2/5 or .4; but if, as here, you -can only use whole numbers, the result has to be something different. -Clearly, 5 can go into 2 zero times, but what of the remainder? To -see what the answer is, consider a case that has to be familiar from -childhood: - - * 5 divided by 5 is 1 with a remainder of 0; - - * 6 divided by 5 is 1 with a remainder of 1; - - * 7 divided by 5 is 1 with a remainder of 2. - - * Similarly, 10 divided by 5 is 2 with a remainder of 0; - - * 11 divided by 5 is 2 with a remainder of 1; - - * 12 divided by 5 is 1 with a remainder of 2. - -By considering the cases as parallel, we can see that - - * zero divided by 5 must be zero with a remainder of zero; - - * 1 divided by 5 must be zero with a remainder of 1; - - * 2 divided by 5 must be zero with a remainder of 2; - -and so on. - -So, in this code, if the value of `length' is 5, then the result of -evaluating - - (% 1 5) - -is 1. (I just checked this by placing the cursor after the expression -and typing `C-x C-e'. Indeed, 1 is printed in the echo area.) - -Using `%' in `rotate-yank-pointer' -.................................. - -When the `kill-ring-yank-pointer' points to the beginning of the kill -ring, and the argument passed to `rotate-yank-pointer' is 1, the `%' -expression returns 1: - - (- length (length kill-ring-yank-pointer)) - => 0 - -therefore, - - (+ arg (- length (length kill-ring-yank-pointer))) - => 1 - -and consequently: - - (% (+ arg (- length (length kill-ring-yank-pointer))) - length) - => 1 - -regardless of the value of `length'. - -As a result of this, the `setq kill-ring-yank-pointer' expression -simplifies to: - - (setq kill-ring-yank-pointer (nthcdr 1 kill-ring)) - -What it does is now easy to understand. Instead of pointing as it did -to the first element of the kill ring, the `kill-ring-yank-pointer' -is set to point to the second element. - -Clearly, if the argument passed to `rotate-yank-pointer' is two, then -the `kill-ring-yank-pointer' is set to `(nthcdr 2 kill-ring)'; and so -on for different values of the argument. - -Similarly, if the `kill-ring-yank-pointer' starts out pointing to the -second element of the kill ring, its length is shorter than the -length of the kill ring by 1, so the computation of the remainder is -based on the expression `(% (+ arg 1) length)'. This means that the -`kill-ring-yank-pointer' is moved from the second element of the kill -ring to the third element if the argument passed to -`rotate-yank-pointer' is 1. - -Pointing to the last element -............................ - -The final question is, what happens if the `kill-ring-yank-pointer' -is set to the _last_ element of the kill ring? Will a call to -`rotate-yank-pointer' mean that nothing more can be taken from the -kill ring? The answer is no. What happens is different and useful. -The `kill-ring-yank-pointer' is set to point to the beginning of the -kill ring instead. - -Let's see how this works by looking at the code, assuming the length -of the kill ring is 5 and the argument passed to -`rotate-yank-pointer' is 1. When the `kill-ring-yank-pointer' points -to the last element of the kill ring, its length is 1. The code -looks like this: - - (% (+ arg (- length (length kill-ring-yank-pointer))) length) - -When the variables are replaced by their numeric values, the -expression looks like this: - - (% (+ 1 (- 5 1)) 5) - -This expression can be evaluated by looking at the most embedded inner -expression first and working outwards: The value of `(- 5 1)' is 4; -the sum of `(+ 1 4)' is 5; and the remainder of dividing 5 by 5 is -zero. So what `rotate-yank-pointer' will do is - - (setq kill-ring-yank-pointer (nthcdr 0 kill-ring)) - -which will set the `kill-ring-yank-pointer' to point to the beginning -of the kill ring. - -So what happens with successive calls to `rotate-yank-pointer' is that -it moves the `kill-ring-yank-pointer' from element to element in the -kill ring until it reaches the end; then it jumps back to the -beginning. And this is why the kill ring is called a ring, since by -jumping back to the beginning, it is as if the list has no end! (And -what is a ring, but an entity with no end?) - -`yank' -====== - -After learning about `rotate-yank-pointer', the code for the `yank' -function is almost easy. It has only one tricky part, which is the -computation of the argument to be passed to `rotate-yank-pointer'. - -The code looks like this: - - (defun yank (&optional arg) - "Reinsert the last stretch of killed text. - More precisely, reinsert the stretch of killed text most - recently killed OR yanked. - With just C-U as argument, same but put point in front - (and mark at end). With argument n, reinsert the nth - most recently killed stretch of killed text. - See also the command \\[yank-pop]." - - (interactive "*P") - (rotate-yank-pointer (if (listp arg) 0 - (if (eq arg '-) -1 - (1- arg)))) - (push-mark (point)) - (insert (car kill-ring-yank-pointer)) - (if (consp arg) - (exchange-point-and-mark))) - -Glancing over this code, we can understand the last few lines readily -enough. The mark is pushed, that is, remembered; then the first -element (the CAR) of what the `kill-ring-yank-pointer' points to is -inserted; and then, if the argument passed the function is a `cons', -point and mark are exchanged so the point is put in the front of the -inserted text rather than at the end. This option is explained in -the documentation. The function itself is interactive with `"*P"'. -This means it will not work on a read-only buffer, and that the -unprocessed prefix argument is passed to the function. - -Passing the argument -.................... - -The hard part of `yank' is understanding the computation that -determines the value of the argument passed to `rotate-yank-pointer'. -Fortunately, it is not so difficult as it looks at first sight. - -What happens is that the result of evaluating one or both of the `if' -expressions will be a number and that number will be the argument -passed to `rotate-yank-pointer'. - -Laid out with comments, the code looks like this: - - (if (listp arg) ; if-part - 0 ; then-part - (if (eq arg '-) ; else-part, inner if - -1 ; inner if's then-part - (1- arg)))) ; inner if's else-part - -This code consists of two `if' expression, one the else-part of the -other. - -The first or outer `if' expression tests whether the argument passed -to `yank' is a list. Oddly enough, this will be true if `yank' is -called without an argument--because then it will be passed the value -of `nil' for the optional argument and an evaluation of `(listp nil)' -returns true! So, if no argument is passed to `yank', the argument -passed to `rotate-yank-pointer' inside of `yank' is zero. This means -the pointer is not moved and the first element to which -`kill-ring-yank-pointer' points is inserted, as we expect. -Similarly, if the argument for `yank' is `C-u', this will be read as -a list, so again, a zero will be passed to `rotate-yank-pointer'. -(`C-u' produces an unprocessed prefix argument of `(4)', which is a -list of one element.) At the same time, later in the function, this -argument will be read as a `cons' so point will be put in the front -and mark at the end of the insertion. (The `P' argument to -`interactive' is designed to provide these values for the case when -an optional argument is not provided or when it is `C-u'.) - -The then-part of the outer `if' expression handles the case when -there is no argument or when it is `C-u'. The else-part handles the -other situations. The else-part is itself another `if' expression. - -The inner `if' expression tests whether the argument is a minus sign. -(This is done by pressing the <META> and `-' keys at the same time, -or the <ESC> key and then the `-' key). In this case, the -`rotate-yank-pointer' function is passed `-1' as an argument. This -moves the `kill-ring-yank-pointer' backwards, which is what is -desired. - -If the true-or-false-test of the inner `if' expression is false (that -is, if the argument is not a minus sign), the else-part of the -expression is evaluated. This is the expression `(1- arg)'. Because -of the two `if' expressions, it will only occur when the argument is -a positive number or when it is a negative number (not just a minus -sign on its own). What `(1- arg)' does is decrement the number and -return it. (The `1-' function subtracts one from its argument.) -This means that if the argument to `rotate-yank-pointer' is 1, it is -reduced to zero, which means the first element to which -`kill-ring-yank-pointer' points is yanked back, as you would expect. - -Passing a negative argument -........................... - -Finally, the question arises, what happens if either the remainder -function, `%', or the `nthcdr' function is passed a negative -argument, as they quite well may? - -The answers can be found by a quick test. When `(% -1 5)' is -evaluated, a negative number is returned; and if `nthcdr' is called -with a negative number, it returns the same value as if it were -called with a first argument of zero. This can be seen by evaluating -the following code. - -Here the `=>' points to the result of evaluating the code preceding -it. This was done by positioning the cursor after the code and -typing `C-x C-e' (`eval-last-sexp') in the usual fashion. You can do -this if you are reading this in Info inside of GNU Emacs. - - (% -1 5) - => -1 - - (setq animals '(cats dogs elephants)) - => (cats dogs elephants) - - (nthcdr 1 animals) - => (dogs elephants) - - (nthcdr 0 animals) - => (cats dogs elephants) - - (nthcdr -1 animals) - => (cats dogs elephants) - -So, if a minus sign or a negative number is passed to `yank', the -`kill-ring-yank-point' is rotated backwards until it reaches the -beginning of the list. Then it stays there. Unlike the other case, -when it jumps from the end of the list to the beginning of the list, -making a ring, it stops. This makes sense. You often want to get -back to the most recently clipped out piece of text, but you don't -usually want to insert text from as many as thirty kill commands ago. -So you need to work through the ring to get to the end, but won't -cycle around it inadvertently if you are trying to come back to the -beginning. - -Incidentally, any number passed to `yank' with a minus sign preceding -it will be treated as -1. This is evidently a simplification for -writing the program. You don't need to jump back towards the -beginning of the kill ring more than one place at a time and doing -this is easier than writing a function to determine the magnitude of -the number that follows the minus sign. - -`yank-pop' -========== - -After understanding `yank', the `yank-pop' function is easy. Leaving -out the documentation to save space, it looks like this: - - (defun yank-pop (arg) - (interactive "*p") - (if (not (eq last-command 'yank)) - (error "Previous command was not a yank")) - (setq this-command 'yank) - (let ((before (< (point) (mark)))) - (delete-region (point) (mark)) - (rotate-yank-pointer arg) - (set-mark (point)) - (insert (car kill-ring-yank-pointer)) - (if before (exchange-point-and-mark)))) - -The function is interactive with a small `p' so the prefix argument -is processed and passed to the function. The command can only be -used after a previous yank; otherwise an error message is sent. This -check uses the variable `last-command' which is discussed elsewhere. -(*Note copy-region-as-kill::.) - -The `let' clause sets the variable `before' to true or false -depending whether point is before or after mark and then the region -between point and mark is deleted. This is the region that was just -inserted by the previous yank and it is this text that will be -replaced. Next the `kill-ring-yank-pointer' is rotated so that the -previously inserted text is not reinserted yet again. Mark is set at -the beginning of the place the new text will be inserted and then the -first element to which `kill-ring-yank-pointer' points is inserted. -This leaves point after the new text. If in the previous yank, point -was left before the inserted text, point and mark are now exchanged -so point is again left in front of the newly inserted text. That is -all there is to it! - -A Graph with Labelled Axes -************************** - -Printed axes help you understand a graph. They convey scale. In an -earlier chapter (*note Readying a Graph: Readying a Graph.), we wrote -the code to print the body of a graph. Here we write the code for -printing and labelling vertical and horizontal axes, along with the -body itself. - -Labelled Example Graph -====================== - -Since insertions fill a buffer to the right and below point, the new -graph printing function should first print the Y or vertical axis, -then the body of the graph, and finally the X or horizontal axis. -This sequence lays out for us the contents of the function: - - 1. Set up code. - - 2. Print Y axis. - - 3. Print body of graph. - - 4. Print X axis. - -Here is an example of how a finished graph should look: - - 10 - - * - * * - * ** - * *** - 5 - * ******* - * *** ******* - ************* - *************** - 1 - **************** - | | | | - 1 5 10 15 - -In this graph, both the vertical and the horizontal axes are labelled -with numbers. However, in some graphs, the horizontal axis is time -and would be better labelled with months, like this: - - 5 - * - * ** * - ******* - ********** ** - 1 - ************** - | ^ | - Jan June Jan - -Indeed, with a little thought, we can easily come up with a variety of -vertical and horizontal labelling schemes. Our task could become -complicated. But complications breed confusion. Rather than permit -this, it is better choose a simple labelling scheme for our first -effort, and to modify or replace it later. - -These considerations suggest the following outline for the -`print-graph' function: - - (defun print-graph (numbers-list) - "DOCUMENTATION..." - (let ((height ... - ...)) - (print-Y-axis height ... ) - (graph-body-print numbers-list) - (print-X-axis ... ))) - -We can work on each part of the `print-graph' function definition in -turn. - -The `print-graph' Varlist -========================= - -In writing the `print-graph' function, the first task is to write the -varlist in the `let' expression. (We will leave aside for the moment -any thoughts about making the function interactive or about the -contents of its documentation string.) - -The varlist should set several values. Clearly, the top of the label -for the vertical axis must be at least the height of the graph, which -means that we must obtain this information here. Note that the -`print-graph-body' function also requires this information. There is -no reason to calculate the height of the graph in two different -places, so we should change `print-graph-body' from the way we -defined it earlier to take advantage of the calculation. - -Similarly, both the function for printing the X axis labels and the -`print-graph-body' function need to learn the value of the width of -each symbol. We can perform the calculation here and change the -definition for `print-graph-body' from the way we defined it in the -previous chapter. - -The length of the label for the horizontal axis must be at least as -long as the graph. However, this information is used only in the -function that prints the horizontal axis, so it does not need to be -calculated here. - -These thoughts lead us directly to the following form for the varlist -in the `let' for `print-graph': - - (let ((height (apply 'max numbers-list)) ; First version. - (symbol-width (length graph-blank))) - -As we shall see, this expression is not quite right. - -The `print-Y-axis' Function -=========================== - -The job of the `print-Y-axis' function is to print a label for the -vertical axis that looks like this: - - 10 - - - - - - 5 - - - - - 1 - - -The function should be passed the height of the graph, and then should -construct and insert the appropriate numbers and marks. - -It is easy enough to see in the figure what the Y axis label should -look like; but to say in words, and then to write a function -definition to do the job is another matter. It is not quite true to -say that we want a number and a tic every five lines: there are only -three lines between the `1' and the `5' (lines 2, 3, and 4), but four -lines between the `5' and the `10' (lines 6, 7, 8, and 9). It is -better to say that we want a number and a tic mark on the base line -(number 1) and then that we want a number and a tic on the fifth line -from the bottom and on every line that is a multiple of five. - -What height should the label be? --------------------------------- - -The next issue is what height the label should be? Suppose the -maximum height of tallest column of the graph is seven. Should the -highest label on the Y axis be `5 -', and should the graph stick up -above the label? Or should the highest label be `7 -', and mark the -peak of the graph? Or should the highest label be `10 -', which is a -multiple of five, and be higher than the topmost value of the graph? - -The latter form is preferred. Most graphs are drawn within rectangles -whose sides are an integral number of steps long--5, 10, 15, and so -on for a step distance of five. But as soon as we decide to use a -step height for the vertical axis, we discover that the simple -expression in the varlist for computing the height is wrong. The -expression is `(apply 'max numbers-list)'. This returns the precise -height, not the maximum height plus whatever is necessary to round up -to the nearest multiple of five. A more complex expression is -required. - -As usual in cases like this, a complex problem becomes simpler if it -is divided into several smaller problems. - -First, consider the case when the highest value of the graph is an -integral multiple of five--when it is 5, 10, 15 ,or some higher -multiple of five. We can use this value as the Y axis height. - -A fairly simply way to determine whether a number is a multiple of -five is to divide it by five and see if the division results in a -remainder. If there is no remainder, the number is a multiple of -five. Thus, seven divided by five has a remainder of two, and seven -is not an integral multiple of five. Put in slightly different -language, more reminiscent of the classroom, five goes into seven -once, with a remainder of two. However, five goes into ten twice, -with no remainder: ten is an integral multiple of five. - -Side Trip: Compute a Remainder ------------------------------- - -In Lisp, the function for computing a remainder is `%'. The function -returns the remainder of its first argument divided by its second -argument. As it happens, `%' is a function in Emacs Lisp that you -cannot discover using `apropos': you find nothing if you type `M-x -apropos <RET> remainder <RET>'. The only way to learn of the -existence of `%' is to read about it in a book such as this or in the -Emacs Lisp sources. The `%' function is used in the code for -`rotate-yank-pointer', which is described in an appendix. (*Note The -Body of `rotate-yank-pointer': rotate-yk-ptr body.) - -You can try the `%' function by evaluating the following two -expressions: - - (% 7 5) - - (% 10 5) - -The first expression returns 2 and the second expression returns 0. - -To test whether the returned value is zero or some other number, we -can use the `zerop' function. This function returns `t' if its -argument, which must be a number, is zero. - - (zerop (% 7 5)) - => nil - - (zerop (% 10 5)) - => t - -Thus, the following expression will return `t' if the height of the -graph is evenly divisible by five: - - (zerop (% height 5)) - -(The value of `height', of course, can be found from `(apply 'max -numbers-list)'.) - -On the other hand, if the value of `height' is not a multiple of -five, we want to reset the value to the next higher multiple of five. -This is straightforward arithmetic using functions with which we are -already familiar. First, we divide the value of `height' by five to -determine how many times five goes into the number. Thus, five goes -into twelve twice. If we add one to this quotient and multiply by -five, we will obtain the value of the next multiple of five that is -larger than the height. Five goes into twelve twice. Add one to two, -and multiply by five; the result is fifteen, which is the next -multiple of five that is higher than twelve. The Lisp expression for -this is: - - (* (1+ (/ height 5)) 5) - -For example, if you evaluate the following, the result is 15: - - (* (1+ (/ 12 5)) 5) - -All through this discussion, we have been using `five' as the value -for spacing labels on the Y axis; but we may want to use some other -value. For generality, we should replace `five' with a variable to -which we can assign a value. The best name I can think of for this -variable is `Y-axis-label-spacing'. - -Using this term, and an `if' expression, we produce the following: - - (if (zerop (% height Y-axis-label-spacing)) - height - ;; else - (* (1+ (/ height Y-axis-label-spacing)) - Y-axis-label-spacing)) - -This expression returns the value of `height' itself if the height is -an even multiple of the value of the `Y-axis-label-spacing' or else -it computes and returns a value of `height' that is equal to the next -higher multiple of the value of the `Y-axis-label-spacing'. - -We can now include this expression in the `let' expression of the -`print-graph' function (after first setting the value of -`Y-axis-label-spacing'): - - (defvar Y-axis-label-spacing 5 - "Number of lines from one Y axis label to next.") - - ... - (let* ((height (apply 'max numbers-list)) - (height-of-top-line - (if (zerop (% height Y-axis-label-spacing)) - height - ;; else - (* (1+ (/ height Y-axis-label-spacing)) - Y-axis-label-spacing))) - (symbol-width (length graph-blank)))) - ... - -(Note use of the `let*' function: the initial value of height is -computed once by the `(apply 'max numbers-list)' expression and then -the resulting value of `height' is used to compute its final value. -*Note The `let*' expression: fwd-para let, for more about `let*'.) - -Construct a Y Axis Element --------------------------- - -When we print the vertical axis, we want to insert strings such as -`5 -' and `10 - ' every five lines. Moreover, we want the numbers -and dashes to line up, so shorter numbers must be padded with leading -spaces. If some of the strings use two digit numbers, the strings -with single digit numbers must include a leading blank space before -the number. - -To figure out the length of the number, the `length' function is -used. But the `length' function works only with a string, not with a -number. So the number has to be converted from being a number to -being a string. This is done with the `number-to-string' function. -For example, - - (length (number-to-string 35)) - => 2 - - (length (number-to-string 100)) - => 3 - -(`number-to-string' is also called `int-to-string'; you will see this -alternative name in various sources.) - -In addition, in each label, each number is followed by a string such -as ` - ', which we will call the `Y-axis-tic' marker. This variable -is defined with `defvar': - - (defvar Y-axis-tic " - " - "String that follows number in a Y axis label.") - -The length of the Y label is the sum of the length of the Y axis tic -mark and the length of the number of the top of the graph. - - (length (concat (number-to-string height) Y-axis-tic))) - -This value will be calculated by the `print-graph' function in its -varlist as `full-Y-label-width' and passed on. (Note that we did not -think to include this in the varlist when we first proposed it.) - -To make a complete vertical axis label, a tic mark is concatenated -with a number; and the two together may be preceded by one or more -spaces depending on how long the number is. The label consists of -three parts: the (optional) leading spaces, the number, and the tic -mark. The function is passed the value of the number for the specific -row, and the value of the width of the top line, which is calculated -(just once) by `print-graph'. - - (defun Y-axis-element (number full-Y-label-width) - "Construct a NUMBERed label element. - A numbered element looks like this ` 5 - ', - and is padded as needed so all line up with - the element for the largest number." - (let* ((leading-spaces - (- full-Y-label-width - (length - (concat (number-to-string number) - Y-axis-tic))))) - (concat - (make-string leading-spaces ? ) - (number-to-string number) - Y-axis-tic))) - -The `Y-axis-element' function concatenates together the leading -spaces, if any; the number, as a string; and the tic mark. - -To figure out how many leading spaces the label will need, the -function subtracts the actual length of the label--the length of the -number plus the length of the tic mark--from the desired label width. - -Blank spaces are inserted using the `make-string' function. This -function takes two arguments: the first tells it how long the string -will be and the second is a symbol for the character to insert, in a -special format. The format is a question mark followed by a blank -space, like this, `? '. *Note Character Type: (elisp)Character Type, -for a description of the syntax for characters. - -The `number-to-string' function is used in the concatenation -expression, to convert the number to a string that is concatenated -with the leading spaces and the tic mark. - -Create a Y Axis Column ----------------------- - -The preceding functions provide all the tools needed to construct a -function that generates a list of numbered and blank strings to insert -as the label for the vertical axis: - - (defun Y-axis-column (height width-of-label) - "Construct list of Y axis labels and blank strings. - For HEIGHT of line above base and WIDTH-OF-LABEL." - (let (Y-axis) - (while (> height 1) - (if (zerop (% height Y-axis-label-spacing)) - ;; Insert label. - (setq Y-axis - (cons - (Y-axis-element height width-of-label) - Y-axis)) - ;; Else, insert blanks. - (setq Y-axis - (cons - (make-string width-of-label ? ) - Y-axis))) - (setq height (1- height))) - ;; Insert base line. - (setq Y-axis - (cons (Y-axis-element 1 width-of-label) Y-axis)) - (nreverse Y-axis))) - -In this function, we start with the value of `height' and -repetitively subtract one from its value. After each subtraction, we -test to see whether the value is an integral multiple of the -`Y-axis-label-spacing'. If it is, we construct a numbered label -using the `Y-axis-element' function; if not, we construct a blank -label using the `make-string' function. The base line consists of -the number one followed by a tic mark. - -The Not Quite Final Version of `print-Y-axis' ---------------------------------------------- - -The list constructed by the `Y-axis-column' function is passed to the -`print-Y-axis' function, which inserts the list as a column. - - (defun print-Y-axis (height full-Y-label-width) - "Insert Y axis using HEIGHT and FULL-Y-LABEL-WIDTH. - Height must be the maximum height of the graph. - Full width is the width of the highest label element." - ;; Value of height and full-Y-label-width - ;; are passed by `print-graph'. - (let ((start (point))) - (insert-rectangle - (Y-axis-column height full-Y-label-width)) - ;; Place point ready for inserting graph. - (goto-char start) - ;; Move point forward by value of full-Y-label-width - (forward-char full-Y-label-width))) - -The `print-Y-axis' uses the `insert-rectangle' function to insert the -Y axis labels created by the `Y-axis-column' function. In addition, -it places point at the correct position for printing the body of the -graph. - -You can test `print-Y-axis': - - 1. Install - - Y-axis-label-spacing - Y-axis-tic - Y-axis-element - Y-axis-column - print-Y-axis - - 2. Copy the following expression: - - (print-Y-axis 12 5) - - 3. Switch to the `*scratch*' buffer and place the cursor where you - want the axis labels to start. - - 4. Type `M-:' (`eval-expression'). - - 5. Yank the `graph-body-print' expression into the minibuffer with - `C-y' (`yank)'. - - 6. Press <RET> to evaluate the expression. - -Emacs will print labels vertically, the top one being `10 - '. (The -`print-graph' function will pass the value of `height-of-top-line', -which in this case would end up as 15.) - -The `print-X-axis' Function -=========================== - -X axis labels are much like Y axis labels, except that the tics are -on a line above the numbers. Labels should look like this: - - | | | | - 1 5 10 15 - -The first tic is under the first column of the graph and is preceded -by several blank spaces. These spaces provide room in rows above for -the Y axis labels. The second, third, fourth, and subsequent tics -are all spaced equally, according to the value of -`X-axis-label-spacing'. - -The second row of the X axis consists of numbers, preceded by several -blank spaces and also separated according to the value of the variable -`X-axis-label-spacing'. - -The value of the variable `X-axis-label-spacing' should itself be -measured in units of `symbol-width', since you may want to change the -width of the symbols that you are using to print the body of the -graph without changing the ways the graph is labelled. - -Similarities and differences ----------------------------- - -The `print-X-axis' function is constructed in more or less the same -fashion as the `print-Y-axis' function except that it has two lines: -the line of tic marks and the numbers. We will write a separate -function to print each line and then combine them within the -`print-X-axis' function. - -This is a three step process: - - 1. Write a function to print the X axis tic marks, - `print-X-axis-tic-line'. - - 2. Write a function to print the X numbers, - `print-X-axis-numbered-line'. - - 3. Write a function to print both lines, the `print-X-axis' - function, using `print-X-axis-tic-line' and - `print-X-axis-numbered-line'. - -X Axis Tic Marks ----------------- - -The first function should print the X axis tic marks. We must specify -the tic marks themselves and their spacing: - - (defvar X-axis-label-spacing - (if (boundp 'graph-blank) - (* 5 (length graph-blank)) 5) - "Number of units from one X axis label to next.") - -(Note that the value of `graph-blank' is set by another `defvar'. -The `boundp' predicate checks whether it has already been set; -`boundp' returns `nil' if it has not. If `graph-blank' were unbound -and we did not use this conditional construction, in GNU Emacs 21, we -would enter the debugger and see an error message saying -`Debugger entered--Lisp error: (void-variable graph-blank)'.) - -Here is the `defvar' for `X-axis-tic-symbol': - - (defvar X-axis-tic-symbol "|" - "String to insert to point to a column in X axis.") - -The goal is to make a line that looks like this: - - | | | | - -The first tic is indented so that it is under the first column, which -is indented to provide space for the Y axis labels. - -A tic element consists of the blank spaces that stretch from one tic -to the next plus a tic symbol. The number of blanks is determined by -the width of the tic symbol and the `X-axis-label-spacing'. - -The code looks like this: - - ;;; X-axis-tic-element - ... - (concat - (make-string - ;; Make a string of blanks. - (- (* symbol-width X-axis-label-spacing) - (length X-axis-tic-symbol)) - ? ) - ;; Concatenate blanks with tic symbol. - X-axis-tic-symbol) - ... - -Next, we determine how many blanks are needed to indent the first tic -mark to the first column of the graph. This uses the value of -`full-Y-label-width' passed it by the `print-graph' function. - -The code to make `X-axis-leading-spaces' looks like this: - - ;; X-axis-leading-spaces - ... - (make-string full-Y-label-width ? ) - ... - -We also need to determine the length of the horizontal axis, which is -the length of the numbers list, and the number of tics in the -horizontal axis: - - ;; X-length - ... - (length numbers-list) - - ;; tic-width - ... - (* symbol-width X-axis-label-spacing) - - ;; number-of-X-tics - (if (zerop (% (X-length tic-width))) - (/ (X-length tic-width)) - (1+ (/ (X-length tic-width)))) - -All this leads us directly to the function for printing the X axis -tic line: - - (defun print-X-axis-tic-line - (number-of-X-tics X-axis-leading-spaces X-axis-tic-element) - "Print tics for X axis." - (insert X-axis-leading-spaces) - (insert X-axis-tic-symbol) ; Under first column. - ;; Insert second tic in the right spot. - (insert (concat - (make-string - (- (* symbol-width X-axis-label-spacing) - ;; Insert white space up to second tic symbol. - (* 2 (length X-axis-tic-symbol))) - ? ) - X-axis-tic-symbol)) - ;; Insert remaining tics. - (while (> number-of-X-tics 1) - (insert X-axis-tic-element) - (setq number-of-X-tics (1- number-of-X-tics)))) - -The line of numbers is equally straightforward: - -First, we create a numbered element with blank spaces before each -number: - - (defun X-axis-element (number) - "Construct a numbered X axis element." - (let ((leading-spaces - (- (* symbol-width X-axis-label-spacing) - (length (number-to-string number))))) - (concat (make-string leading-spaces ? ) - (number-to-string number)))) - -Next, we create the function to print the numbered line, starting with -the number "1" under the first column: - - (defun print-X-axis-numbered-line - (number-of-X-tics X-axis-leading-spaces) - "Print line of X-axis numbers" - (let ((number X-axis-label-spacing)) - (insert X-axis-leading-spaces) - (insert "1") - (insert (concat - (make-string - ;; Insert white space up to next number. - (- (* symbol-width X-axis-label-spacing) 2) - ? ) - (number-to-string number))) - ;; Insert remaining numbers. - (setq number (+ number X-axis-label-spacing)) - (while (> number-of-X-tics 1) - (insert (X-axis-element number)) - (setq number (+ number X-axis-label-spacing)) - (setq number-of-X-tics (1- number-of-X-tics))))) - -Finally, we need to write the `print-X-axis' that uses -`print-X-axis-tic-line' and `print-X-axis-numbered-line'. - -The function must determine the local values of the variables used by -both `print-X-axis-tic-line' and `print-X-axis-numbered-line', and -then it must call them. Also, it must print the carriage return that -separates the two lines. - -The function consists of a varlist that specifies five local -variables, and calls to each of the two line printing functions: - - (defun print-X-axis (numbers-list) - "Print X axis labels to length of NUMBERS-LIST." - (let* ((leading-spaces - (make-string full-Y-label-width ? )) - ;; symbol-width is provided by graph-body-print - (tic-width (* symbol-width X-axis-label-spacing)) - (X-length (length numbers-list)) - (X-tic - (concat - (make-string - ;; Make a string of blanks. - (- (* symbol-width X-axis-label-spacing) - (length X-axis-tic-symbol)) - ? ) - ;; Concatenate blanks with tic symbol. - X-axis-tic-symbol)) - (tic-number - (if (zerop (% X-length tic-width)) - (/ X-length tic-width) - (1+ (/ X-length tic-width))))) - (print-X-axis-tic-line tic-number leading-spaces X-tic) - (insert "\n") - (print-X-axis-numbered-line tic-number leading-spaces))) - -You can test `print-X-axis': - - 1. Install `X-axis-tic-symbol', `X-axis-label-spacing', - `print-X-axis-tic-line', as well as `X-axis-element', - `print-X-axis-numbered-line', and `print-X-axis'. - - 2. Copy the following expression: - - (progn - (let ((full-Y-label-width 5) - (symbol-width 1)) - (print-X-axis - '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)))) - - 3. Switch to the `*scratch*' buffer and place the cursor where you - want the axis labels to start. - - 4. Type `M-:' (`eval-expression'). - - 5. Yank the test expression into the minibuffer with `C-y' (`yank)'. - - 6. Press <RET> to evaluate the expression. - -Emacs will print the horizontal axis like this: - - | | | | | - 1 5 10 15 20 - -Printing the Whole Graph -======================== - -Now we are nearly ready to print the whole graph. - -The function to print the graph with the proper labels follows the -outline we created earlier (*note A Graph with Labelled Axes: Full -Graph.), but with additions. - -Here is the outline: - - (defun print-graph (numbers-list) - "DOCUMENTATION..." - (let ((height ... - ...)) - (print-Y-axis height ... ) - (graph-body-print numbers-list) - (print-X-axis ... ))) - -Changes for the Final Version ------------------------------ - -The final version is different from what we planned in two ways: -first, it contains additional values calculated once in the varlist; -second, it carries an option to specify the labels' increment per row. -This latter feature turns out to be essential; otherwise, a graph may -have more rows than fit on a display or on a sheet of paper. - -This new feature requires a change to the `Y-axis-column' function, -to add `vertical-step' to it. The function looks like this: - - ;;; Final version. - (defun Y-axis-column - (height width-of-label &optional vertical-step) - "Construct list of labels for Y axis. - HEIGHT is maximum height of graph. - WIDTH-OF-LABEL is maximum width of label. - VERTICAL-STEP, an option, is a positive integer - that specifies how much a Y axis label increments - for each line. For example, a step of 5 means - that each line is five units of the graph." - (let (Y-axis - (number-per-line (or vertical-step 1))) - (while (> height 1) - (if (zerop (% height Y-axis-label-spacing)) - ;; Insert label. - (setq Y-axis - (cons - (Y-axis-element - (* height number-per-line) - width-of-label) - Y-axis)) - ;; Else, insert blanks. - (setq Y-axis - (cons - (make-string width-of-label ? ) - Y-axis))) - (setq height (1- height))) - ;; Insert base line. - (setq Y-axis (cons (Y-axis-element - (or vertical-step 1) - width-of-label) - Y-axis)) - (nreverse Y-axis))) - -The values for the maximum height of graph and the width of a symbol -are computed by `print-graph' in its `let' expression; so -`graph-body-print' must be changed to accept them. - - ;;; Final version. - (defun graph-body-print (numbers-list height symbol-width) - "Print a bar graph of the NUMBERS-LIST. - The numbers-list consists of the Y-axis values. - HEIGHT is maximum height of graph. - SYMBOL-WIDTH is number of each column." - (let (from-position) - (while numbers-list - (setq from-position (point)) - (insert-rectangle - (column-of-graph height (car numbers-list))) - (goto-char from-position) - (forward-char symbol-width) - ;; Draw graph column by column. - (sit-for 0) - (setq numbers-list (cdr numbers-list))) - ;; Place point for X axis labels. - (forward-line height) - (insert "\n"))) - -Finally, the code for the `print-graph' function: - - ;;; Final version. - (defun print-graph - (numbers-list &optional vertical-step) - "Print labelled bar graph of the NUMBERS-LIST. - The numbers-list consists of the Y-axis values. - - Optionally, VERTICAL-STEP, a positive integer, - specifies how much a Y axis label increments for - each line. For example, a step of 5 means that - each row is five units." - (let* ((symbol-width (length graph-blank)) - ;; `height' is both the largest number - ;; and the number with the most digits. - (height (apply 'max numbers-list)) - (height-of-top-line - (if (zerop (% height Y-axis-label-spacing)) - height - ;; else - (* (1+ (/ height Y-axis-label-spacing)) - Y-axis-label-spacing))) - (vertical-step (or vertical-step 1)) - (full-Y-label-width - (length - (concat - (number-to-string - (* height-of-top-line vertical-step)) - Y-axis-tic)))) - - (print-Y-axis - height-of-top-line full-Y-label-width vertical-step) - (graph-body-print - numbers-list height-of-top-line symbol-width) - (print-X-axis numbers-list))) - -Testing `print-graph' ---------------------- - -We can test the `print-graph' function with a short list of numbers: - - 1. Install the final versions of `Y-axis-column', - `graph-body-print', and `print-graph' (in addition to the rest - of the code.) - - 2. Copy the following expression: - - (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1)) - - 3. Switch to the `*scratch*' buffer and place the cursor where you - want the axis labels to start. - - 4. Type `M-:' (`eval-expression'). - - 5. Yank the test expression into the minibuffer with `C-y' (`yank)'. - - 6. Press <RET> to evaluate the expression. - -Emacs will print a graph that looks like this: - - 10 - - - - * - ** * - 5 - **** * - **** *** - * ********* - ************ - 1 - ************* - - | | | | - 1 5 10 15 - -On the other hand, if you pass `print-graph' a `vertical-step' value -of 2, by evaluating this expression: - - (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2) - -The graph looks like this: - - 20 - - - - * - ** * - 10 - **** * - **** *** - * ********* - ************ - 2 - ************* - - | | | | - 1 5 10 15 - -(A question: is the `2' on the bottom of the vertical axis a bug or a -feature? If you think it is a bug, and should be a `1' instead, (or -even a `0'), you can modify the sources.) - -Graphing Numbers of Words and Symbols -------------------------------------- - -Now for the graph for which all this code was written: a graph that -shows how many function definitions contain fewer than 10 words and -symbols, how many contain between 10 and 19 words and symbols, how -many contain between 20 and 29 words and symbols, and so on. - -This is a multi-step process. First make sure you have loaded all the -requisite code. - -It is a good idea to reset the value of `top-of-ranges' in case you -have set it to some different value. You can evaluate the following: - - (setq top-of-ranges - '(10 20 30 40 50 - 60 70 80 90 100 - 110 120 130 140 150 - 160 170 180 190 200 - 210 220 230 240 250 - 260 270 280 290 300) - -Next create a list of the number of words and symbols in each range. - -Evaluate the following: - - (setq list-for-graph - (defuns-per-range - (sort - (recursive-lengths-list-many-files - (directory-files "/usr/local/emacs/lisp" - t ".+el$")) - '<) - top-of-ranges)) - -On my machine, this takes about an hour. It looks though 303 Lisp -files in my copy of Emacs version 19.23. After all that computing, -the `list-for-graph' has this value: - - (537 1027 955 785 594 483 349 292 224 199 166 120 116 99 - 90 80 67 48 52 45 41 33 28 26 25 20 12 28 11 13 220) - -This means that my copy of Emacs has 537 function definitions with -fewer than 10 words or symbols in them, 1,027 function definitions -with 10 to 19 words or symbols in them, 955 function definitions with -20 to 29 words or symbols in them, and so on. - -Clearly, just by looking at this list we can see that most function -definitions contain ten to thirty words and symbols. - -Now for printing. We do _not_ want to print a graph that is 1,030 -lines high ... Instead, we should print a graph that is fewer than -twenty-five lines high. A graph that height can be displayed on -almost any monitor, and easily printed on a sheet of paper. - -This means that each value in `list-for-graph' must be reduced to -one-fiftieth its present value. - -Here is a short function to do just that, using two functions we have -not yet seen, `mapcar' and `lambda'. - - (defun one-fiftieth (full-range) - "Return list, each number one-fiftieth of previous." - (mapcar '(lambda (arg) (/ arg 50)) full-range)) - -A `lambda' Expression: Useful Anonymity ---------------------------------------- - -`lambda' is the symbol for an anonymous function, a function without -a name. Every time you use an anonymous function, you need to -include its whole body. - -Thus, - - (lambda (arg) (/ arg 50)) - -is a function definition that says `return the value resulting from -dividing whatever is passed to me as `arg' by 50'. - -Earlier, for example, we had a function `multiply-by-seven'; it -multiplied its argument by 7. This function is similar, except it -divides its argument by 50; and, it has no name. The anonymous -equivalent of `multiply-by-seven' is: - - (lambda (number) (* 7 number)) - -(*Note The `defun' Special Form: defun.) - -If we want to multiply 3 by 7, we can write: - - (multiply-by-seven 3) - \_______________/ ^ - | | - function argument - - - -This expression returns 21. - -Similarly, we can write: - - ((lambda (number) (* 7 number)) 3) - \____________________________/ ^ - | | - anonymous function argument - - - -If we want to divide 100 by 50, we can write: - - ((lambda (arg) (/ arg 50)) 100) - \______________________/ \_/ - | | - anonymous function argument - - - -This expression returns 2. The 100 is passed to the function, which -divides that number by 50. - -*Note Lambda Expressions: (elisp)Lambda Expressions, for more about -`lambda'. Lisp and lambda expressions derive from the Lambda -Calculus. - -The `mapcar' Function ---------------------- - -`mapcar' is a function that calls its first argument with each -element of its second argument, in turn. The second argument must be -a sequence. - -The `map' part of the name comes from the mathematical phrase, -`mapping over a domain', meaning to apply a function to each of the -elements in a domain. The mathematical phrase is based on the -metaphor of a surveyor walking, one step at a time, over an area he is -mapping. And `car', of course, comes from the Lisp notion of the -first of a list. - -For example, - - (mapcar '1+ '(2 4 6)) - => (3 5 7) - -The function `1+' which adds one to its argument, is executed on -_each_ element of the list, and a new list is returned. - -Contrast this with `apply', which applies its first argument to all -the remaining. (*Note Readying a Graph: Readying a Graph, for a -explanation of `apply'.) - -In the definition of `one-fiftieth', the first argument is the -anonymous function: - - (lambda (arg) (/ arg 50)) - -and the second argument is `full-range', which will be bound to -`list-for-graph'. - -The whole expression looks like this: - - (mapcar '(lambda (arg) (/ arg 50)) full-range)) - -*Note Mapping Functions: (elisp)Mapping Functions, for more about -`mapcar'. - -Using the `one-fiftieth' function, we can generate a list in which -each element is one-fiftieth the size of the corresponding element in -`list-for-graph'. - - (setq fiftieth-list-for-graph - (one-fiftieth list-for-graph)) - -The resulting list looks like this: - - (10 20 19 15 11 9 6 5 4 3 3 2 2 - 1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 4) - -This, we are almost ready to print! (We also notice the loss of -information: many of the higher ranges are 0, meaning that fewer than -50 defuns had that many words or symbols--but not necessarily meaning -that none had that many words or symbols.) - -Another Bug ... Most Insidious ------------------------------- - -I said `almost ready to print'! Of course, there is a bug in the -`print-graph' function ... It has a `vertical-step' option, but not -a `horizontal-step' option. The `top-of-range' scale goes from 10 to -300 by tens. But the `print-graph' function will print only by ones. - -This is a classic example of what some consider the most insidious -type of bug, the bug of omission. This is not the kind of bug you can -find by studying the code, for it is not in the code; it is an omitted -feature. Your best actions are to try your program early and often; -and try to arrange, as much as you can, to write code that is easy to -understand and easy to change. Try to be aware, whenever you can, -that whatever you have written, _will_ be rewritten, if not soon, -eventually. A hard maxim to follow. - -It is the `print-X-axis-numbered-line' function that needs the work; -and then the `print-X-axis' and the `print-graph' functions need to -be adapted. Not much needs to be done; there is one nicety: the -numbers ought to line up under the tic marks. This takes a little -thought. - -Here is the corrected `print-X-axis-numbered-line': - - (defun print-X-axis-numbered-line - (number-of-X-tics X-axis-leading-spaces - &optional horizontal-step) - "Print line of X-axis numbers" - (let ((number X-axis-label-spacing) - (horizontal-step (or horizontal-step 1))) - (insert X-axis-leading-spaces) - ;; Delete extra leading spaces. - (delete-char - (- (1- - (length (number-to-string horizontal-step))))) - (insert (concat - (make-string - ;; Insert white space. - (- (* symbol-width - X-axis-label-spacing) - (1- - (length - (number-to-string horizontal-step))) - 2) - ? ) - (number-to-string - (* number horizontal-step)))) - ;; Insert remaining numbers. - (setq number (+ number X-axis-label-spacing)) - (while (> number-of-X-tics 1) - (insert (X-axis-element - (* number horizontal-step))) - (setq number (+ number X-axis-label-spacing)) - (setq number-of-X-tics (1- number-of-X-tics))))) - -If you are reading this in Info, you can see the new versions of -`print-X-axis' `print-graph' and evaluate them. If you are reading -this in a printed book, you can see the changed lines here (the full -text is too much to print). - - (defun print-X-axis (numbers-list horizontal-step) - "Print X axis labels to length of NUMBERS-LIST. - Optionally, HORIZONTAL-STEP, a positive integer, - specifies how much an X axis label increments for - each column." - ;; Value of symbol-width and full-Y-label-width - ;; are passed by `print-graph'. - (let* ((leading-spaces - (make-string full-Y-label-width ? )) - ;; symbol-width is provided by graph-body-print - (tic-width (* symbol-width X-axis-label-spacing)) - (X-length (length numbers-list)) - (X-tic - (concat - (make-string - ;; Make a string of blanks. - (- (* symbol-width X-axis-label-spacing) - (length X-axis-tic-symbol)) - ? ) - ;; Concatenate blanks with tic symbol. - X-axis-tic-symbol)) - (tic-number - (if (zerop (% X-length tic-width)) - (/ X-length tic-width) - (1+ (/ X-length tic-width))))) - - (print-X-axis-tic-line - tic-number leading-spaces X-tic) - (insert "\n") - (print-X-axis-numbered-line - tic-number leading-spaces horizontal-step))) - - (defun print-graph - (numbers-list &optional vertical-step horizontal-step) - "Print labelled bar graph of the NUMBERS-LIST. - The numbers-list consists of the Y-axis values. - - Optionally, VERTICAL-STEP, a positive integer, - specifies how much a Y axis label increments for - each line. For example, a step of 5 means that - each row is five units. - - Optionally, HORIZONTAL-STEP, a positive integer, - specifies how much an X axis label increments for - each column." - (let* ((symbol-width (length graph-blank)) - ;; `height' is both the largest number - ;; and the number with the most digits. - (height (apply 'max numbers-list)) - (height-of-top-line - (if (zerop (% height Y-axis-label-spacing)) - height - ;; else - (* (1+ (/ height Y-axis-label-spacing)) - Y-axis-label-spacing))) - (vertical-step (or vertical-step 1)) - (full-Y-label-width - (length - (concat - (number-to-string - (* height-of-top-line vertical-step)) - Y-axis-tic)))) - (print-Y-axis - height-of-top-line full-Y-label-width vertical-step) - (graph-body-print - numbers-list height-of-top-line symbol-width) - (print-X-axis numbers-list horizontal-step))) - -The Printed Graph ------------------ - -When made and installed, you can call the `print-graph' command like -this: - - (print-graph fiftieth-list-for-graph 50 10) - -Here is the graph: - - - - 1000 - * - ** - ** - ** - ** - 750 - *** - *** - *** - *** - **** - 500 - ***** - ****** - ****** - ****** - ******* - 250 - ******** - ********* * - *********** * - ************* * - 50 - ***************** * * - | | | | | | | | - 10 50 100 150 200 250 300 350 - - - -The largest group of functions contain 10 - 19 words and symbols each. - -GNU Free Documentation License -****************************** - - Version 1.1, March 2000 - Copyright (C) 2000 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - 0. PREAMBLE - - The purpose of this License is to make a manual, textbook, or - other written document "free" in the sense of freedom: to assure - everyone the effective freedom to copy and redistribute it, with - or without modifying it, either commercially or noncommercially. - Secondarily, this License preserves for the author and - publisher a way to get credit for their work, while not being - considered responsible for modifications made by others. - - This License is a kind of "copyleft", which means that derivative - works of the document must themselves be free in the same sense. - It complements the GNU General Public License, which is a - copyleft license designed for free software. - - We have designed this License in order to use it for manuals for - free software, because free software needs free documentation: a - free program should come with manuals providing the same - freedoms that the software does. But this License is not - limited to software manuals; it can be used for any textual - work, regardless of subject matter or whether it is published as - a printed book. We recommend this License principally for works - whose purpose is instruction or reference. - - 1. APPLICABILITY AND DEFINITIONS - - This License applies to any manual or other work that contains a - notice placed by the copyright holder saying it can be - distributed under the terms of this License. The "Document", - below, refers to any such manual or work. Any member of the - public is a licensee, and is addressed as "you". - - A "Modified Version" of the Document means any work containing - the Document or a portion of it, either copied verbatim, or with - modifications and/or translated into another language. - - A "Secondary Section" is a named appendix or a front-matter - section of the Document that deals exclusively with the - relationship of the publishers or authors of the Document to the - Document's overall subject (or to related matters) and contains - nothing that could fall directly within that overall subject. - (For example, if the Document is in part a textbook of - mathematics, a Secondary Section may not explain any - mathematics.) The relationship could be a matter of historical - connection with the subject or with related matters, or of legal, - commercial, philosophical, ethical or political position - regarding them. - - The "Invariant Sections" are certain Secondary Sections whose - titles are designated, as being those of Invariant Sections, in - the notice that says that the Document is released under this - License. - - The "Cover Texts" are certain short passages of text that are - listed, as Front-Cover Texts or Back-Cover Texts, in the notice - that says that the Document is released under this License. - - A "Transparent" copy of the Document means a machine-readable - copy, represented in a format whose specification is available - to the general public, whose contents can be viewed and edited - directly and straightforwardly with generic text editors or (for - images composed of pixels) generic paint programs or (for - drawings) some widely available drawing editor, and that is - suitable for input to text formatters or for automatic - translation to a variety of formats suitable for input to text - formatters. A copy made in an otherwise Transparent file format - whose markup has been designed to thwart or discourage - subsequent modification by readers is not Transparent. A copy - that is not "Transparent" is called "Opaque". - - Examples of suitable formats for Transparent copies include plain - ASCII without markup, Texinfo input format, LaTeX input format, - SGML or XML using a publicly available DTD, and - standard-conforming simple HTML designed for human modification. - Opaque formats include PostScript, PDF, proprietary formats - that can be read and edited only by proprietary word processors, - SGML or XML for which the DTD and/or processing tools are not - generally available, and the machine-generated HTML produced by - some word processors for output purposes only. - - The "Title Page" means, for a printed book, the title page - itself, plus such following pages as are needed to hold, - legibly, the material this License requires to appear in the - title page. For works in formats which do not have any title - page as such, "Title Page" means the text near the most - prominent appearance of the work's title, preceding the - beginning of the body of the text. - - 2. VERBATIM COPYING - - You may copy and distribute the Document in any medium, either - commercially or noncommercially, provided that this License, the - copyright notices, and the license notice saying this License - applies to the Document are reproduced in all copies, and that - you add no other conditions whatsoever to those of this License. - You may not use technical measures to obstruct or control the - reading or further copying of the copies you make or distribute. - However, you may accept compensation in exchange for copies. - If you distribute a large enough number of copies you must also - follow the conditions in section 3. - - You may also lend copies, under the same conditions stated - above, and you may publicly display copies. - - 3. COPYING IN QUANTITY - - If you publish printed copies of the Document numbering more - than 100, and the Document's license notice requires Cover - Texts, you must enclose the copies in covers that carry, clearly - and legibly, all these Cover Texts: Front-Cover Texts on the - front cover, and Back-Cover Texts on the back cover. Both - covers must also clearly and legibly identify you as the - publisher of these copies. The front cover must present the - full title with all words of the title equally prominent and - visible. You may add other material on the covers in addition. - Copying with changes limited to the covers, as long as they - preserve the title of the Document and satisfy these conditions, - can be treated as verbatim copying in other respects. - - If the required texts for either cover are too voluminous to fit - legibly, you should put the first ones listed (as many as fit - reasonably) on the actual cover, and continue the rest onto - adjacent pages. - - If you publish or distribute Opaque copies of the Document - numbering more than 100, you must either include a - machine-readable Transparent copy along with each Opaque copy, - or state in or with each Opaque copy a publicly-accessible - computer-network location containing a complete Transparent copy - of the Document, free of added material, which the general - network-using public has access to download anonymously at no - charge using public-standard network protocols. If you use the - latter option, you must take reasonably prudent steps, when you - begin distribution of Opaque copies in quantity, to ensure that - this Transparent copy will remain thus accessible at the stated - location until at least one year after the last time you - distribute an Opaque copy (directly or through your agents or - retailers) of that edition to the public. - - It is requested, but not required, that you contact the authors - of the Document well before redistributing any large number of - copies, to give them a chance to provide you with an updated - version of the Document. - - 4. MODIFICATIONS - - You may copy and distribute a Modified Version of the Document - under the conditions of sections 2 and 3 above, provided that - you release the Modified Version under precisely this License, - with the Modified Version filling the role of the Document, thus - licensing distribution and modification of the Modified Version - to whoever possesses a copy of it. In addition, you must do - these things in the Modified Version: - - A. Use in the Title Page (and on the covers, if any) a title - distinct from that of the Document, and from those of - previous versions (which should, if there were any, be - listed in the History section of the Document). You may - use the same title as a previous version if the original - publisher of that version gives permission. - - B. List on the Title Page, as authors, one or more persons or - entities responsible for authorship of the modifications in - the Modified Version, together with at least five of the - principal authors of the Document (all of its principal - authors, if it has less than five). - - C. State on the Title page the name of the publisher of the - Modified Version, as the publisher. - - D. Preserve all the copyright notices of the Document. - - E. Add an appropriate copyright notice for your modifications - adjacent to the other copyright notices. - - F. Include, immediately after the copyright notices, a license - notice giving the public permission to use the Modified - Version under the terms of this License, in the form shown - in the Addendum below. - - G. Preserve in that license notice the full lists of Invariant - Sections and required Cover Texts given in the Document's - license notice. - - H. Include an unaltered copy of this License. - - I. Preserve the section entitled "History", and its title, and - add to it an item stating at least the title, year, new - authors, and publisher of the Modified Version as given on - the Title Page. If there is no section entitled "History" - in the Document, create one stating the title, year, - authors, and publisher of the Document as given on its - Title Page, then add an item describing the Modified - Version as stated in the previous sentence. - - J. Preserve the network location, if any, given in the - Document for public access to a Transparent copy of the - Document, and likewise the network locations given in the - Document for previous versions it was based on. These may - be placed in the "History" section. You may omit a network - location for a work that was published at least four years - before the Document itself, or if the original publisher of - the version it refers to gives permission. - - K. In any section entitled "Acknowledgments" or "Dedications", - preserve the section's title, and preserve in the section - all the substance and tone of each of the contributor - acknowledgments and/or dedications given therein. - - L. Preserve all the Invariant Sections of the Document, - unaltered in their text and in their titles. Section - numbers or the equivalent are not considered part of the - section titles. - - M. Delete any section entitled "Endorsements". Such a section - may not be included in the Modified Version. - - N. Do not retitle any existing section as "Endorsements" or to - conflict in title with any Invariant Section. - - If the Modified Version includes new front-matter sections or - appendices that qualify as Secondary Sections and contain no - material copied from the Document, you may at your option - designate some or all of these sections as invariant. To do - this, add their titles to the list of Invariant Sections in the - Modified Version's license notice. These titles must be - distinct from any other section titles. - - You may add a section entitled "Endorsements", provided it - contains nothing but endorsements of your Modified Version by - various parties--for example, statements of peer review or that - the text has been approved by an organization as the - authoritative definition of a standard. - - You may add a passage of up to five words as a Front-Cover Text, - and a passage of up to 25 words as a Back-Cover Text, to the end - of the list of Cover Texts in the Modified Version. Only one - passage of Front-Cover Text and one of Back-Cover Text may be - added by (or through arrangements made by) any one entity. If - the Document already includes a cover text for the same cover, - previously added by you or by arrangement made by the same - entity you are acting on behalf of, you may not add another; but - you may replace the old one, on explicit permission from the - previous publisher that added the old one. - - The author(s) and publisher(s) of the Document do not by this - License give permission to use their names for publicity for or - to assert or imply endorsement of any Modified Version. - - 5. COMBINING DOCUMENTS - - You may combine the Document with other documents released under - this License, under the terms defined in section 4 above for - modified versions, provided that you include in the combination - all of the Invariant Sections of all of the original documents, - unmodified, and list them all as Invariant Sections of your - combined work in its license notice. - - The combined work need only contain one copy of this License, and - multiple identical Invariant Sections may be replaced with a - single copy. If there are multiple Invariant Sections with the - same name but different contents, make the title of each such - section unique by adding at the end of it, in parentheses, the - name of the original author or publisher of that section if - known, or else a unique number. Make the same adjustment to the - section titles in the list of Invariant Sections in the license - notice of the combined work. - - In the combination, you must combine any sections entitled - "History" in the various original documents, forming one section - entitled "History"; likewise combine any sections entitled - "Acknowledgments", and any sections entitled "Dedications". You - must delete all sections entitled "Endorsements." - - 6. COLLECTIONS OF DOCUMENTS - - You may make a collection consisting of the Document and other - documents released under this License, and replace the - individual copies of this License in the various documents with - a single copy that is included in the collection, provided that - you follow the rules of this License for verbatim copying of - each of the documents in all other respects. - - You may extract a single document from such a collection, and - distribute it individually under this License, provided you - insert a copy of this License into the extracted document, and - follow this License in all other respects regarding verbatim - copying of that document. - - 7. AGGREGATION WITH INDEPENDENT WORKS - - A compilation of the Document or its derivatives with other - separate and independent documents or works, in or on a volume - of a storage or distribution medium, does not as a whole count - as a Modified Version of the Document, provided no compilation - copyright is claimed for the compilation. Such a compilation is - called an "aggregate", and this License does not apply to the - other self-contained works thus compiled with the Document, on - account of their being thus compiled, if they are not themselves - derivative works of the Document. - - If the Cover Text requirement of section 3 is applicable to these - copies of the Document, then if the Document is less than one - quarter of the entire aggregate, the Document's Cover Texts may - be placed on covers that surround only the Document within the - aggregate. Otherwise they must appear on covers around the - whole aggregate. - - 8. TRANSLATION - - Translation is considered a kind of modification, so you may - distribute translations of the Document under the terms of - section 4. Replacing Invariant Sections with translations - requires special permission from their copyright holders, but - you may include translations of some or all Invariant Sections - in addition to the original versions of these Invariant - Sections. You may include a translation of this License - provided that you also include the original English version of - this License. In case of a disagreement between the translation - and the original English version of this License, the original - English version will prevail. - - 9. TERMINATION - - You may not copy, modify, sublicense, or distribute the Document - except as expressly provided for under this License. Any other - attempt to copy, modify, sublicense or distribute the Document - is void, and will automatically terminate your rights under this - License. However, parties who have received copies, or rights, - from you under this License will not have their licenses - terminated so long as such parties remain in full compliance. - - 10. FUTURE REVISIONS OF THIS LICENSE - - The Free Software Foundation may publish new, revised versions - of the GNU Free Documentation License from time to time. Such - new versions will be similar in spirit to the present version, - but may differ in detail to address new problems or concerns. - See `http://www.gnu.org/copyleft/'. - - Each version of the License is given a distinguishing version - number. If the Document specifies that a particular numbered - version of this License "or any later version" applies to it, - you have the option of following the terms and conditions either - of that specified version or of any later version that has been - published (not as a draft) by the Free Software Foundation. If - the Document does not specify a version number of this License, - you may choose any version ever published (not as a draft) by - the Free Software Foundation. - -Index -***** - -% (remainder function): - See ``Side Trip: Compute a Remainder''. -(debug) in code: - See ```debug-on-quit' and `(debug)'''. -* (multiplication): - See ``The `defun' Special Form''. -* for read-only buffer: - See ``A Read-only Buffer''. -*scratch* buffer: - See ``An Example: `print-elements-of-list'''. -.emacs file: - See ``Your `.emacs' File''. -.emacs file, beginning of: - See ``Beginning a `.emacs' File''. -/ (division): - See ``What happens in a large buffer''. -<= (less than or equal): - See ``The parts of the function definition''. -> (greater than): - See ```if' in more detail''. -Accumulate, type of recursive pattern: - See ``Recursive Pattern: _accumulate_''. -add-hook: - See ``Text and Auto Fill Mode''. -and <1>: - See ``The `let*' expression''. -and: - See ``The `kill-new' function''. -and, introduced: - See ``The `kill-new' function''. -Anonymous function: - See ``A `lambda' Expression: Useful Anonymity''. -append-to-buffer: - See ``The Definition of `append-to-buffer'''. -apply: - See ``Printing the Columns of a Graph''. -apropos: - See ``Printing the Columns of a Graph''. -Argument as local variable: - See ``Putting the function definition together''. -argument defined: - See ``Arguments''. -argument list defined: - See ``The `defun' Special Form''. -Argument, wrong type of: - See ``Using the Wrong Type Object as an Argument''. -Arguments: - See ``Arguments''. -Arguments' data types: - See ``Arguments' Data Types''. -Arguments, variable number of: - See ``Variable Number of Arguments''. -Asterisk for read-only buffer: - See ``A Read-only Buffer''. -Auto Fill mode turned on: - See ``Text and Auto Fill Mode''. -autoload: - See ``Autoloading''. -Automatic mode selection: - See ``Text and Auto Fill Mode''. -Axis, print horizontal: - See ``The `print-X-axis' Function''. -Axis, print vertical: - See ``The `print-Y-axis' Function''. -beginning-of-buffer: - See ``Complete Definition of `beginning-of-buffer'''. -bind defined: - See ``Setting the Value of a Variable''. -body defined: - See ``The `defun' Special Form''. -Body of graph: - See ``Readying a Graph''. -Buffer size: - See ``Buffer Size and the Location of Point''. -Buffer, history of word: - See ``Buffer Names''. -buffer-file-name: - See ``Buffer Names''. -buffer-menu, bound to key: - See ``Some Keybindings''. -buffer-name: - See ``Buffer Names''. -Bug, most insidious type: - See ``Another Bug ... Most Insidious''. -Building robots: - See ``Building Robots: Extending the Metaphor''. -Building Tags in the Emacs sources: - See ``Create Your Own `TAGS' File''. -Byte compiling: - See ``Byte Compiling''. -C language primitives: - See ``An Aside about Primitive Functions''. -C, a digression into: - See ``Digression into C''. -call defined: - See ``Switching Buffers''. -cancel-debug-on-entry: - See ```debug-on-entry'''. -car, introduced: - See ```car', `cdr', `cons': Fundamental Functions''. -cdr, introduced: - See ```car', `cdr', `cons': Fundamental Functions''. -Changing a function definition: - See ``Change a Function Definition''. -Chest of Drawers, metaphor for a symbol: - See ``Symbols as a Chest of Drawers''. -Clipping text: - See ``Cutting and Storing Text''. -Code installation: - See ``Install Code Permanently''. -command defined: - See ``How to Evaluate''. -Comments in Lisp code: - See ``Change a Function Definition''. -Common Lisp: - See ``Lisp History''. -compare-windows: - See ``Some Keybindings''. -concat: - See ``Arguments' Data Types''. -cond: - See ``Recursion Example Using `cond'''. -condition-case: - See ```condition-case'''. -Conditional 'twixt two versions of Emacs: - See ``A Simple Extension: `line-to-top-of-window'''. -Conditional with if: - See ``The `if' Special Form''. -cons, example: - See ``The `kill-new' function''. -cons, introduced: - See ```cons'''. -copy-region-as-kill: - See ```copy-region-as-kill'''. -copy-to-buffer: - See ``The Definition of `copy-to-buffer'''. -Count words recursively: - See ``Count Words Recursively''. -count-words-in-defun: - See ``The `count-words-in-defun' Function''. -count-words-region: - See ``The `count-words-region' Function''. -Counting: - See ``Counting''. -Counting words in a defun <1>: - See ``The `count-words-in-defun' Function''. -Counting words in a defun: - See ``Counting Words in a `defun'''. -current-buffer: - See ``Getting Buffers''. -Customizing your .emacs file: - See ``Your `.emacs' File''. -Cutting and storing text: - See ``Cutting and Storing Text''. -Data types: - See ``Arguments' Data Types''. -debug: - See ```debug'''. -debug-on-entry: - See ```debug-on-entry'''. -debug-on-quit: - See ```debug-on-quit' and `(debug)'''. -debugging: - See ``Debugging''. -default-mode-line-format: - See ``A Modified Mode Line''. -default.el init file: - See ``Site-wide Initialization Files''. -defcustom: - See ``Specifying Variables using `defcustom'''. -Deferment in recursion: - See ``Recursion without Deferments''. -Defermentless solution: - See ``No Deferment Solution''. -Definition installation: - See ``Install a Function Definition''. -Definition writing: - See ``How To Write Function Definitions''. -Definition, how to change: - See ``Change a Function Definition''. -defun: - See ``The `defun' Special Form''. -defvar: - See ``Initializing a Variable with `defvar'''. -defvar for a user customizable variable: - See ```defvar' and an asterisk''. -defvar with an asterisk: - See ```defvar' and an asterisk''. -delete-and-extract-region <1>: - See ``Digression into C''. -delete-and-extract-region: - See ```delete-and-extract-region'''. -Deleting text: - See ``Cutting and Storing Text''. -describe-function: - See ``A Simplified `beginning-of-buffer' Definition''. -describe-function, introduced: - See ``Finding More Information''. -Digression into C: - See ``Digression into C''. -directory-files: - See ``Making a List of Files''. -Division: - See ``What happens in a large buffer''. -dolist: - See ``The `dolist' Macro''. -dotimes: - See ``The `dotimes' Macro''. -Drawers, Chest of, metaphor for a symbol: - See ``Symbols as a Chest of Drawers''. -Duplicated words function: - See ``The `the-the' Function''. -edebug: - See ``The `edebug' Source Level Debugger''. -edit-options: - See ```defvar' and an asterisk''. -Else: - See ``If-then-else Expressions''. -Emacs version, choosing: - See ``A Simple Extension: `line-to-top-of-window'''. -empty list defined: - See ``Lisp Atoms''. -empty string defined: - See ``Review''. -eobp: - See ``Between paragraphs''. -eq: - See ``Review''. -eq (example of use): - See ```last-command' and `this-command'''. -equal: - See ``Review''. -Erasing text: - See ``Cutting and Storing Text''. -error: - See ``The Body of `rotate-yank-pointer'''. -Error for symbol without function: - See ``Error Message for a Symbol Without a Function''. -Error for symbol without value: - See ``Error Message for a Symbol Without a Value''. -Error message generation: - See ``Generate an Error Message''. -etags: - See ``Create Your Own `TAGS' File''. -evaluate defined: - See ``Run a Program''. -Evaluating inner lists: - See ``Evaluating Inner Lists''. -Evaluation: - See ``Evaluation''. -Evaluation practice: - See ``Practicing Evaluation''. -Every, type of recursive pattern: - See ``Recursive Pattern: _every_''. -Example variable, fill-column: - See ```fill-column', an Example Variable''. -expression defined: - See ``Lisp Atoms''. -Falsehood and truth in Emacs Lisp: - See ``Truth and Falsehood in Emacs Lisp''. -FDL, GNU Free Documentation License: - See ``GNU Free Documentation License''. -files-in-below-directory: - See ``Making a List of Files''. -fill-column, an example variable: - See ```fill-column', an Example Variable''. -Find a File: - See ``Find a File''. -Find function documentation: - See ``Finding More Information''. -Find source of function: - See ``Finding More Information''. -find-tags: - See ``Finding More Information''. -Flowers in a field: - See ``Lisp Lists''. -Focusing attention (narrowing): - See ``Narrowing and Widening''. -form defined: - See ``Lisp Atoms''. -Formatting convention: - See ```save-excursion' in `append-to-buffer'''. -Formatting help: - See ``GNU Emacs Helps You Type Lists''. -forward-paragraph: - See ```forward-paragraph': a Goldmine of Functions''. -forward-sentence: - See ```forward-sentence'''. -function defined: - See ``Generate an Error Message''. -function definition defined: - See ``The `defun' Special Form''. -Function definition installation: - See ``Install a Function Definition''. -Function definition writing: - See ``How To Write Function Definitions''. -Function definition, how to change: - See ``Change a Function Definition''. -Functions, primitive: - See ``An Aside about Primitive Functions''. -Generate an error message: - See ``Generate an Error Message''. -Getting a buffer: - See ``Getting Buffers''. -Global set key: - See ``Some Keybindings''. -global-set-key: - See ``Some Keybindings''. -global-unset-key: - See ``Some Keybindings''. -Graph prototype: - See ``Readying a Graph''. -Graph, printing all: - See ``Printing the Whole Graph''. -graph-body-print: - See ``The `graph-body-print' Function''. -graph-body-print Final version.: - See ``Changes for the Final Version''. -Handling the kill ring: - See ``Handling the Kill Ring''. -Help typing lists: - See ``GNU Emacs Helps You Type Lists''. -Horizontal axis printing: - See ``The `print-X-axis' Function''. -if: - See ``The `if' Special Form''. -if-part defined: - See ```if' in more detail''. -indent-tabs-mode: - See ``Indent Tabs Mode''. -Indentation for formatting: - See ```save-excursion' in `append-to-buffer'''. -Initialization file: - See ``Your `.emacs' File''. -Initializing a variable: - See ``Initializing a Variable with `defvar'''. -Inner list evaluation: - See ``Evaluating Inner Lists''. -insert-buffer: - See ``The Definition of `insert-buffer'''. -insert-buffer-substring: - See ``An Overview of `append-to-buffer'''. -Insidious type of bug: - See ``Another Bug ... Most Insidious''. -Install a Function Definition: - See ``Install a Function Definition''. -Install code permanently: - See ``Install Code Permanently''. -interactive: - See ``Make a Function Interactive''. -interactive function defined: - See ``How to Evaluate''. -Interactive functions: - See ``Make a Function Interactive''. -Interactive options: - See ``Different Options for `interactive'''. -interactive, example use of: - See ``The Interactive Expression in `insert-buffer'''. -Interpreter, Lisp, explained: - See ``Run a Program''. -Interpreter, what it does: - See ``The Lisp Interpreter''. -Keep, type of recursive pattern: - See ``Recursive Pattern: _keep_''. -Key setting globally: - See ``Some Keybindings''. -Key unbinding: - See ``Some Keybindings''. -Keymaps: - See ``Keymaps''. -Keyword: - See ``Optional Arguments''. -Kill ring handling: - See ``Handling the Kill Ring''. -Kill ring overview: - See ``Kill Ring Overview''. -kill-append: - See ``The `kill-append' function''. -kill-new: - See ``The `kill-new' function''. -kill-region: - See ```kill-region'''. -Killing text: - See ``Cutting and Storing Text''. -lambda: - See ``A `lambda' Expression: Useful Anonymity''. -length: - See ``Find the Length of a List: `length'''. -lengths-list-file: - See ```lengths-list-file' in Detail''. -lengths-list-many-files: - See ``Determine the lengths of `defuns'''. -let: - See ```let'''. -let expression sample: - See ``Sample `let' Expression''. -let expression, parts of: - See ``The Parts of a `let' Expression''. -let variables uninitialized: - See ``Uninitialized Variables in a `let' Statement''. -Library, as term for `file': - See ``Finding More Information''. -line-to-top-of-window: - See ``A Simple Extension: `line-to-top-of-window'''. -Lisp Atoms: - See ``Lisp Atoms''. -Lisp history: - See ``Lisp History''. -Lisp interpreter, explained: - See ``Run a Program''. -Lisp interpreter, what it does: - See ``The Lisp Interpreter''. -Lisp Lists: - See ``Lisp Lists''. -Lisp macro: - See ```delete-and-extract-region'''. -list-buffers, rebound: - See ``Some Keybindings''. -Lists in a computer: - See ``How Lists are Implemented''. -load-library: - See ``Loading Files''. -load-path: - See ``Loading Files''. -Loading files: - See ``Loading Files''. -local variable defined: - See ```let' Prevents Confusion''. -Local variables list, per-buffer,: - See ``Text and Auto Fill Mode''. -Location of point: - See ``Buffer Size and the Location of Point''. -looking-at: - See ``Between paragraphs''. -Loops: - See ```while'''. -Loops and recursion: - See ``Loops and Recursion''. -Maclisp: - See ``Lisp History''. -Macro, lisp: - See ```delete-and-extract-region'''. -Mail aliases: - See ``Mail Aliases''. -make tags: - See ``Create Your Own `TAGS' File''. -make-string: - See ``Construct a Y Axis Element''. -mapcar: - See ``The `mapcar' Function''. -mark: - See ```save-excursion'''. -mark-whole-buffer: - See ``The Definition of `mark-whole-buffer'''. -match-beginning: - See ``No fill prefix''. -max: - See ``Printing the Columns of a Graph''. -message: - See ``The `message' Function''. -min: - See ``Printing the Columns of a Graph''. -Mode line format: - See ``A Modified Mode Line''. -Mode selection, automatic: - See ``Text and Auto Fill Mode''. -Motion by sentence and paragraph: - See ``Regular Expression Searches''. -Narrowing: - See ``Narrowing and Widening''. -narrowing defined: - See ``Buffer Size and the Location of Point''. -nil: - See ``Truth and Falsehood in Emacs Lisp''. -nil, history of word: - See ``Buffer Names''. -No deferment solution: - See ``No Deferment Solution''. -nreverse: - See ``Counting function definitions''. -nth: - See ```nth'''. -nthcdr <1>: - See ```copy-region-as-kill'''. -nthcdr: - See ```nthcdr'''. -nthcdr, example: - See ``The `kill-new' function''. -number-to-string: - See ``Construct a Y Axis Element''. -occur: - See ``Some Keybindings''. -optional: - See ``Optional Arguments''. -Optional arguments: - See ``Optional Arguments''. -Options for interactive: - See ``Different Options for `interactive'''. -or: - See ``The `or' in the Body''. -other-buffer: - See ``Getting Buffers''. -Paragraphs, movement by: - See ``Regular Expression Searches''. -Parts of a Recursive Definition: - See ``The Parts of a Recursive Definition''. -Parts of let expression: - See ``The Parts of a `let' Expression''. -Passing information to functions: - See ``Arguments''. -Pasting text: - See ``Yanking Text Back''. -Patterns, searching for: - See ``Regular Expression Searches''. -Per-buffer, local variables list: - See ``Text and Auto Fill Mode''. -Permanent code installation: - See ``Install Code Permanently''. -point: - See ```save-excursion'''. -point defined: - See ``Buffer Size and the Location of Point''. -Point location: - See ``Buffer Size and the Location of Point''. -Point, mark, buffer preservation: - See ```save-excursion'''. -Practicing evaluation: - See ``Practicing Evaluation''. -Preserving point, mark, and buffer: - See ```save-excursion'''. -Primitive functions: - See ``An Aside about Primitive Functions''. -Primitives written in C: - See ``An Aside about Primitive Functions''. -Print horizontal axis: - See ``The `print-X-axis' Function''. -Print vertical axis: - See ``The `print-Y-axis' Function''. -print-elements-of-list: - See ``An Example: `print-elements-of-list'''. -print-elements-recursively: - See ``Recursion with a List''. -print-graph Final version.: - See ``Changes for the Final Version''. -print-graph varlist: - See ``The `print-graph' Varlist''. -print-X-axis: - See ``X Axis Tic Marks''. -print-X-axis-numbered-line: - See ``X Axis Tic Marks''. -print-X-axis-tic-line: - See ``X Axis Tic Marks''. -print-Y-axis: - See ``The Not Quite Final Version of `print-Y-axis'''. -Printing the whole graph: - See ``Printing the Whole Graph''. -prog1: - See ``Between paragraphs''. -progn: - See ``The `progn' Special Form''. -Program, running one: - See ``Run a Program''. -Prototype graph: - See ``Readying a Graph''. -re-search-forward: - See ``The `re-search-forward' Function''. -Read-only buffer: - See ``A Read-only Buffer''. -Readying a graph: - See ``Readying a Graph''. -Rebinding keys: - See ``Keymaps''. -Recursion: - See ``Recursion''. -Recursion and loops: - See ``Loops and Recursion''. -Recursion without Deferments: - See ``Recursion without Deferments''. -Recursive Definition Parts: - See ``The Parts of a Recursive Definition''. -Recursive pattern: accumulate: - See ``Recursive Pattern: _accumulate_''. -Recursive pattern: every: - See ``Recursive Pattern: _every_''. -Recursive pattern: keep: - See ``Recursive Pattern: _keep_''. -Recursive Patterns: - See ``Recursive Patterns''. -recursive-count-words: - See ``Count Words Recursively''. -recursive-graph-body-print: - See ``The `recursive-graph-body-print' Function''. -recursive-lengths-list-many-files: - See ``Recursively Count Words in Different Files''. -Recursively counting words: - See ``Count Words Recursively''. -regexp-quote: - See ``The `let*' expression''. -Region, what it is: - See ```save-excursion'''. -Regular expression searches: - See ``Regular Expression Searches''. -Regular expressions for word counting: - See ``Counting: Repetition and Regexps''. -Remainder function, %: - See ``Side Trip: Compute a Remainder''. -Repetition (loops): - See ``Loops and Recursion''. -Repetition for word counting: - See ``Counting: Repetition and Regexps''. -Retrieving text: - See ``Yanking Text Back''. -reverse: - See ``Counting function definitions''. -Ring, making a list like a: - See ``Handling the Kill Ring''. -Robots, building: - See ``Building Robots: Extending the Metaphor''. -rotate-yank-pointer <1>: - See ``The `rotate-yank-pointer' Function''. -rotate-yank-pointer: - See ``Yanking Text Back''. -Run a program: - See ``Run a Program''. -Sample let expression: - See ``Sample `let' Expression''. -save-excursion: - See ```save-excursion'''. -save-restriction: - See ``The `save-restriction' Special Form''. -search-forward: - See ``The `search-forward' Function''. -Searches, illustrating: - See ``Regular Expression Searches''. -sentence-end: - See ``The Regular Expression for `sentence-end'''. -Sentences, movement by: - See ``Regular Expression Searches''. -set: - See ``Using `set'''. -set-buffer: - See ``Switching Buffers''. -setcar: - See ```setcar'''. -setcdr: - See ```setcdr'''. -setcdr, example: - See ``The `kill-new' function''. -setq: - See ``Using `setq'''. -Setting a key globally: - See ``Some Keybindings''. -Setting value of variable: - See ``Setting the Value of a Variable''. -side effect defined: - See ``Evaluation''. -Simple extension in .emacs file: - See ``A Simple Extension: `line-to-top-of-window'''. -simplified-beginning-of-buffer: - See ``A Simplified `beginning-of-buffer' Definition''. -site-init.el init file: - See ``Site-wide Initialization Files''. -site-load.el init file: - See ``Site-wide Initialization Files''. -Size of buffer: - See ``Buffer Size and the Location of Point''. -Solution without deferment: - See ``No Deferment Solution''. -sort: - See ``Sorting Lists''. -Source level debugger: - See ``The `edebug' Source Level Debugger''. -Special form: - See ``Complications''. -Special form of defun: - See ``The `defun' Special Form''. -Storing and cutting text: - See ``Cutting and Storing Text''. -string defined: - See ``Lisp Atoms''. -switch-to-buffer: - See ``Switching Buffers''. -Switching to a buffer: - See ``Switching Buffers''. -Symbol names: - See ``Symbol Names and Function Definitions''. -Symbol without function error: - See ``Error Message for a Symbol Without a Function''. -Symbol without value error: - See ``Error Message for a Symbol Without a Value''. -Symbolic expressions, introduced: - See ``Lisp Atoms''. -Symbols as a Chest of Drawers: - See ``Symbols as a Chest of Drawers''. -Syntax categories and tables: - See ``What Constitutes a Word or Symbol?''. -Tabs, preventing: - See ``Indent Tabs Mode''. -TAGS file, create own: - See ``Create Your Own `TAGS' File''. -Tags in the Emacs sources: - See ``Create Your Own `TAGS' File''. -TAGS table, specifying: - See ``Finding More Information''. -Text between double quotation marks: - See ``Lisp Atoms''. -Text Mode turned on: - See ``Text and Auto Fill Mode''. -Text retrieval: - See ``Yanking Text Back''. -the-the: - See ``The `the-the' Function''. -then-part defined: - See ```if' in more detail''. -top-of-ranges: - See ``Counting function definitions''. -triangle-bugged: - See ```debug'''. -triangle-recursively: - See ``Recursion in Place of a Counter''. -Truth and falsehood in Emacs Lisp: - See ``Truth and Falsehood in Emacs Lisp''. -Types of data: - See ``Arguments' Data Types''. -Unbinding key: - See ``Some Keybindings''. -Uninitialized let variables: - See ``Uninitialized Variables in a `let' Statement''. -Variable initialization: - See ``Initializing a Variable with `defvar'''. -Variable number of arguments: - See ``Variable Number of Arguments''. -Variable, example of, fill-column: - See ```fill-column', an Example Variable''. -Variable, setting value: - See ``Setting the Value of a Variable''. -Variables: - See ``Variables''. -varlist defined: - See ``The Parts of a `let' Expression''. -Version of Emacs, choosing: - See ``A Simple Extension: `line-to-top-of-window'''. -Vertical axis printing: - See ``The `print-Y-axis' Function''. -what-line: - See ```what-line'''. -while: - See ```while'''. -Whitespace in lists: - See ``Whitespace in Lists''. -Whole graph printing: - See ``Printing the Whole Graph''. -Widening: - See ``Narrowing and Widening''. -Widening, example of: - See ```what-line'''. -Word counting in a defun: - See ``Counting Words in a `defun'''. -Words and symbols in defun: - See ``What to Count?''. -Words, counted recursively: - See ``Count Words Recursively''. -Words, duplicated: - See ``The `the-the' Function''. -Writing a function definition: - See ``How To Write Function Definitions''. -Wrong type of argument: - See ``Using the Wrong Type Object as an Argument''. -X axis printing: - See ``The `print-X-axis' Function''. -X-axis-element: - See ``X Axis Tic Marks''. -Y axis printing: - See ``The `print-Y-axis' Function''. -Y-axis-column: - See ``Create a Y Axis Column''. -Y-axis-column Final version.: - See ``Changes for the Final Version''. -Y-axis-label-spacing: - See ``Side Trip: Compute a Remainder''. -Y-axis-tic: - See ``Construct a Y Axis Element''. -yank <1>: - See ```yank'''. -yank: - See ``Yanking Text Back''. -yank-pop: - See ```yank-pop'''. -zap-to-char: - See ```zap-to-char'''. -zerop: - See ``The Body of `rotate-yank-pointer'''. -About the Author -**************** - - Robert J. Chassell has worked with GNU Emacs since 1985. He - writes and edits, teaches Emacs and Emacs Lisp, and speaks - throughout the world on software freedom. Chassell was a - founding Director and Treasurer of the Free Software Foundation, - Inc. He is co-author of the `Texinfo' manual, and has edited - more than a dozen other books. He graduated from Cambridge - University, in England. He has an abiding interest in social - and economic history and flies his own airplane. - -