1. Trang chủ
  2. » Công Nghệ Thông Tin

An Introduction to Programming in Emacs Lisp phần 4 pot

31 429 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề An Introduction to Programming in Emacs Lisp phần 4 pot
Trường học University of Example
Chuyên ngành Computer Science
Thể loại Lecture Notes
Năm xuất bản 2024
Thành phố Hanoi
Định dạng
Số trang 31
Dung lượng 369,62 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

When car and cdr are applied to a list made up of symbols, such as thelist pine fir oak maple, the element of the list returned by the functioncar is the symbol pine without any parenthe

Trang 1

The save-restriction Special Form 77

6 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 otherparts Narrowing is normally disabled since it can confuse novices

With narrowing, the rest of a buffer is made invisible, as if it weren’tthere This is an advantage if, for example, you want to replace a word inone part of a buffer but not in another: you narrow to the part you wantand the replacement is carried out only in that section, not in the rest ofthe buffer Searches will only work within a narrowed region, not outside ofone, so if you are fixing a part of a document, you can keep yourself fromaccidentally 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 canscare 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; orconversely, an Emacs Lisp function needs to work on all of a buffer thathas been narrowed The what-line function, for example, removes thenarrowing from a buffer, if it has any narrowing and when it has finished itsjob, restores the narrowing to what it was On the other hand, the count-lines function, which is called by what-line, uses narrowing to restrictitself to just that portion of the buffer in which it is interested and thenrestores the previous situation

6.1 The save-restriction Special Form

In Emacs Lisp, you can use the save-restriction special form to keeptrack of whatever narrowing is in effect, if any When the Lisp interpretermeets with save-restriction, it executes the code in the body of the save-restriction expression, and then undoes any changes to narrowing that thecode caused If, for example, the buffer is narrowed and the code that followssave-restriction gets rid of the narrowing, save-restriction returns thebuffer to its narrowed region afterwards In the what-line command, anynarrowing the buffer may have is undone by the widen command that im-mediately follows the save-restriction command Any original narrowing

is restored just before the completion of the function

Trang 2

The template for a save-restriction expression is simple:

save-in the buffer to which Emacs switches after callsave-ing save-excursion Thus,when written together, save-excursion and save-restriction should bewritten like this:

in the body of the save-restriction has been evaluated

Trang 3

Exercise with Narrowing 79

The save-restriction special form is followed by widen This functionundoes any narrowing the current buffer may have had when what-linewas called (The narrowing that was there is the narrowing that save-restriction remembers.) This widening makes it possible for the linecounting commands to count from the beginning of the buffer Otherwise,they would have been limited to counting within the accessible region Anyoriginal narrowing is restored just before the completion of the function bythe save-restriction special form

The call to widen is followed by save-excursion, which saves the tion of the cursor (i.e., of point) and of the mark, and restores them afterthe code in the body of the save-excursion uses the beginning-of-linefunction to move point

loca-(Note that the (widen) expression comes between the save-restrictionand 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 thenumber of lines in the buffer and then print the number in the echo area

The number that is printed in place of the ‘%d’ is computed by the lastline of the function:

(1+ (count-lines 1 (point)))

What this does is count the lines from the first position of the buffer, cated 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

indi-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 inthe echo area, the save-excursion restores point and mark to their originalpositions; and save-restriction restores the original narrowing, if any.6.3 Exercise with Narrowing

Write a function that will display the first 60 characters of the currentbuffer, even if you have narrowed the buffer to its latter half so that the firstline 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

Trang 5

car and cdr 81

7 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 takethem apart

In the walk through of the copy-region-as-kill function, we will seecons as well as two variants on cdr, namely, setcdr and nthcdr (SeeSection 8.5, “copy-region-as-kill”, page 102.)

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 theother hand, are esoteric: car is an acronym from the phrase ‘Contents ofthe Address part of the Register’; and cdr (pronounced ‘could-er’) is anacronym 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 phraseshave been completely irrelevant for more than 25 years to anyone thinkingabout Lisp Nonetheless, although a few brave scholars have begun to usemore reasonable names for these functions, the old terms are still in use Inparticular, since the terms are used in the Emacs Lisp source code, we willuse them in this introduction

7.1 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 ating the following:

evalu-(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 firstand 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 Inthe 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 returnsthe part of the list that follows the first item Thus, while the car of thelist ’(rose violet daisy buttercup) is rose, the rest of the list, the valuereturned by the cdr function, is (violet daisy buttercup)

Trang 6

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 echoarea

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, theLisp 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 verycarefully what you are doing, since you may be stuck with the names for farlonger 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 avoidusing 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 thelist (pine fir oak maple), the element of the list returned by the functioncar is the symbol pine without any parentheses around it pine is the firstelement in the list However, the cdr of the list is a list itself, (fir oakmaple), as you can see by evaluating the following expressions in the usualway:

(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 carreturns this first element as a list For example, the following list containsthree sub-lists, a list of carnivores, a list of herbivores and a list of seamammals:

(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 antelopezebra) (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 veryimportant for how they are used

Trang 7

cons 83

Also, in the first chapter, in the discussion about atoms, I said that inLisp, “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.”(See Section 1.1.1, “Lisp Atoms”, page 1.) The car and cdr functions areused for splitting lists and are considered fundamental to Lisp Since theycannot split or gain access to the parts of an array, an array is considered anatom Conversely, the other fundamental function, cons, can put together

or construct a list, but not an array (Arrays are handled by array-specific

functions See section “Arrays” in The GNU Emacs Lisp Reference Manual.)

7.2 cons

The cons function constructs lists; it is the inverse of car and cdr Forexample, cons can be used to make a four element list from the three elementlist, (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 puts a new element at the beginning of a list;

it attaches or pushes elements onto the list

cons must have a list to attach to.1 You cannot start from absolutelynothing If you are building a list, you need to provide at least an emptylist 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 evaluateeach 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 yousee is (buttercup) The empty list is not counted as an element of a list

1 Actually, you can cons an element to an atom to produce a dotted pair Dotted pairs

are not discussed here; see section “Dotted Pair Notation” in The GNU Emacs Lisp Reference Manual.

Trang 8

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 thirdexample constructs a three element list by putting violet in front of daisyand buttercup

7.2.1 Find the Length of a List: length

You can find out how many elements there are in a list by using the Lispfunction length, as in the following examples:

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 findthe 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 ofthe function This is written with a special notation, ‘#<subr’, that indicatesthat the function length is one of the primitive functions written in C ratherthan in Emacs Lisp (‘subr’ is an abbreviation for ‘subroutine’.) See section

“What Is a Function?” in The GNU Emacs Lisp Reference Manual, for more

about subroutines

Trang 9

nthcdr 857.3 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 returnedthe list (fir oak maple) If you repeat this on what was returned, youwill be returned the list (oak maple) (Of course, repeated cdring on theoriginal list will just give you the original cdr since the function does notchange the list You need to evaluate the cdr of the cdr and so on.) If youcontinue this, eventually you will be returned an empty list, which in thiscase, 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))

The nthcdr function does the same as repeating the call to cdr In thefollowing example, the argument 2 is passed to the function nthcdr, alongwith 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)

Trang 10

Using the original four element list, we can see what happens when variousnumeric 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))

"Returns the Nth element of LIST.

N counts from zero If LIST is not that long, nil is returned."

Trang 11

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 thisexpression 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 computingenvironment.)

When we evaluate the variable animals, we see that it is bound to thelist (antelope giraffe lion tiger):

animals

⇒ (antelope giraffe lion tiger)

Put another way, the variable animals points to the list (antelope giraffelion tiger)

Next, evaluate the function setcar while passing it two arguments, thevariable animals and the quoted symbol hippopotamus; this is done bywriting the three element list (setcar animals ’hippopotamus) and thenevaluating it in the usual fashion:

(setcar animals ’hippopotamus)

After evaluating this expression, evaluate the variable animals again Youwill see that the list of animals has changed:

animals

⇒ (hippopotamus giraffe lion tiger)

The first element on the list, antelope is replaced by hippopotamus

Trang 12

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.

7.6 setcdr

The setcdr function is similar to the setcar function, except that thefunction replaces the second and subsequent elements of a list rather thanthe first element

To see how this works, set the value of the variable to a list of cated animals by evaluating the following expression:

domesti-(setq domesticated-animals ’(horse cow sheep goat))

If you now evaluate the list, you will be returned the list (horse cow sheepgoat):

domesticated-animals

⇒ (horse cow sheep goat)

Next, evaluate setcdr with two arguments, the name of the variablewhich has a list as its value, and the list to which the cdr of the first listwill be set;

(setcdr domesticated-animals ’(cat dog))

If you evaluate this expression, the list (cat dog) will appear in the echoarea This is the value returned by the function The result we are inter-ested in is the “side effect”, which we can see by evaluating the variabledomesticated-animals:

domesticated-animals

⇒ (horse cat dog)

Indeed, the list is changed from (horse cow sheep goat) to (horse catdog) The cdr of the list is changed from (cow sheep goat) to (cat dog).7.7 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 firstelement of the list of four birds with a fish Replace the rest of that list with

a list of other fish

Trang 13

zap-to-char 89

8 Cutting and Storing Text

Whenever you cut or clip text out of a buffer with a ‘kill’ command inGNU 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 killcommands do; they clip text out of a buffer and put it into storage fromwhich it can be brought back I have often been tempted to replace globallyall occurrences of ‘kill’ in the Emacs sources with ‘clip’ and all occurrences

of ‘killed’ with ‘clipped’.)

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 add a piece of text to the 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 theecho area:

("another piece" "a piece of text" "previous piece")

With the car and nthcdr functions, you can retrieve whichever piece oftext you want For example, in the following code, nthcdr 1 returnsthe list with the first item removed; and the car returns the first element ofthat 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 Emacscan 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 shouldgive 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 howthe zap-to-char function works This function uses (or ‘calls’) a functionthat invokes a function that manipulates the kill ring Thus, before reachingthe mountains, we climb the foothills

A subsequent chapter describes how text that is cut from the buffer isretrieved See Chapter 10, “Yanking Text Back”, page 117

Trang 14

8.1 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 tion, kill-region, which enjoyed a major rewrite on the way to version21

func-The kill-region function in Emacs 19 is complex, but does not use codethat is important at this time We will skip it

The kill-region function in Emacs 21 is easier to read than the samefunction in Emacs 19 and introduces a very important concept, that of errorhandling We will walk through the function

But first, let us look at the interactive zap-to-char function

The GNU Emacs version 19 and version 21 implementations of the to-char function are nearly identical in form, and they work alike Thefunction 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 charac-ter The text that zap-to-char removes is put in the kill ring; and it can be

zap-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, ifthe 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 “Searchfailed”, tell you the character you typed, and not remove any text

In order to determine how much text to remove, zap-to-char uses asearch 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))))

8.1.1 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 threedifferent things First, and most simply, the asterisk, ‘*’, causes an error to

Trang 15

The search-forward Function 91

be signalled if the buffer is read-only This means that if you try char in a read-only buffer you will not be able to remove text, and you willreceive a message that says “Buffer is read-only”; your terminal may beep

zap-to-at you as well

The version 21 implementation does not have the asterisk, ‘*’ The tion works the same as in version 19: in both cases, it cannot remove textfrom a read-only buffer but the function does copy the text that would havebeen removed to the kill ring Also, in both cases, you see an error message.However, the version 19 implementation copies text from a read-onlybuffer only because of a mistake in the implementation of interactive.According to the documentation for interactive, the asterisk, ‘*’, shouldprevent the zap-to-char function from doing anything at all when the buffer

func-is read only The function should not copy the text to the kill ring It func-is abug 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 ‘*’ andevaluate the function definition, then the next time you run the zap-to-charfunction 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 rated from the next part by a newline, ‘\n’ The ‘p’ means that the firstargument to the function will be passed the value of a ‘processed prefix’

sepa-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 theargument 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

8.1.2 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 lookslike 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 theprogn consists of calls to search-forward and point

Ngày đăng: 09/08/2014, 12:22

TỪ KHÓA LIÊN QUAN