[comp.emacs] GNU Emacs Lisp docs - Part 1 of 2

liberte@B.CS.UIUC.EDU (Daniel LaLiberte) (12/20/86)

This is part 1 of 2 of the documentation prepared so far.
Hope it helps.  Please mail comments to the indicated authors.
If you wish to join the mailing list of volunteers, mail to:

	gnu-manual-request@a.cs.uiuc.edu.

Dan LaLiberte
liberte@b.cs.uiuc.edu
liberte@uiuc.csnet
ihnp4!uiucdcs!liberte

-------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh.
# The following files will be created:
#	outline
#	tutorial
# This archive created: Sat Dec 20 00:43:53 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'outline'" '(9622 characters)'
if test -f 'outline'
then
	echo shar: over-writing existing file "'outline'"
fi
sed 's/^X//' << \SHAR_EOF > 'outline'
X
XCopyright (C) 1986 Daniel LaLiberte
X
XGNU Emacs Programmers Manual (outline)
X
XGNU Emacs Lisp
X
XPart I.  Lisp.
X
XObjects and types: 
X	atom, integer, symbol, cons, lists, vector, string,
X	buffer, marker, built-in-function, window, process
X
XLists:
X	atom
X	cons
X	list
X	make-list
X	eq
X	equal
X	null
X	consp
X	listp
X	nlistp
X	sequencep
X	car
X	car-safe
X	cdr
X	cdr-safe
X	setcar
X	setcdr
X	append
X	nthcdr
X	nth
X	memq
X	assq
X	assoc
X	rassq
X	delq
X	nreverse
X	reverse
X	sort
X	nconc
X	mapcar
X
XNumbers:
X	integerp
X	natnump
X	zerop
X	integer-or-marker-p
X	= < > <= >= /=
X	int-to-string
X	string-to-int
X	+ - * / %
X	1+
X	1-
X	max
X	min
X	longand
X	logior
X	logxor
X	lognot
X	ash
X	lsh
X	random
X
XArrays Vectors Sequences:
X	make-vector
X	vector
X	vectorp
X	stringp
X	arrayp
X	sequencep
X	aref
X	aset
X	copy-sequence
X	length
X	elt
X	fillarray
X
XStrings:
X	make-string
X	stringp
X	int-to-string
X	string-to-int
X	char-to-string
X	string-to-char
X	concat
X	vconcat
X	substring
X	string-equal
X	string-lessp
X
XSymbols: 
X	General
X		name, value as variable, function definition, 
X		property list,
X	get
X	put
X	intern
X	intern-soft
X	mapatoms
X	make-symbol
X	symbolp
X	boundp
X	fboundp
X	makunbound
X	fmakeunbound
X	symbol-function
X	symbol-plist
X	symbol-name
X	symbol-value
X	default-value
X	fset
X	set
X	set-default
X	setplist
X
XLisp expressions:
X	variables vs constants vs 
X		function calls vs special forms (a funny sort of function call)
X	Mention eval setq quote.
X	Macros  
X		defmacro 
X		macroexpand
X
XFunctions:
X	function
X	apply
X	funcall
X	defun 
X	autoload
X	fboundp
X	fmakunbound
X	Simple args and rest args.
X	identity
X	call-interactively
X	prefix-numeric-value
X	interactive
X	interactive-p
X	commandp
X	backtrace-debug
X	backtrace
X	mapatoms
X	mapconcat
X
XVariables and binding:
X	setq
X	defvar
X	defconst
X	boundp
X	makunbound
X	Explain dynamic (vs lexical) scope.
X	let let*
X	Variables that Emacs primitives look at vs.
X	Variables that users may access
X	user-variable-p
X	set-variable
X	Per-buffer variables (there are two kinds of these)
X		make-variable-buffer-local
X		make-local-variable
X	global-value
X	global-set
X	hack-local-variables
X
X
XControl Structures
X	progn
X	prog1
X	prog2
X	or
X	and
X	cond
X	if
X	while
X	catch
X	throw
X	unwind-protect
X	eval
X	apply
X	funcall
X	mapcar
X	mapconcat
X
XErrors
X	unwind-protect
X	condition-case
X	signal
X	error
X	backtrace-debug
X	backtrace
X
XEvaluation, Compilation, and Debugging
X	load
X	provide
X	require
X	features
X	eval-region
X	eval-current-buffer
X	eval-expression
X	edit-and-eval-command
X	byte-compile-file
X	byte-recompile-directory
X	batch-byte-compile
X	debug
X	debug-on-entry
X	cancel-debug-on-entry
X	Variables:
X		debug-on-entry
X		debug-on-error
X
XLisp I/O to streams.
X	read
X	print
X	prin1
X	princ
X	Strings as streams.  
X	Buffers as streams.  
X	Markers as streams.
X	Functions as streams.
X	Minibuffer streams.
X
X------------------------------------------------------
X
X
XPart II.  Lisp and Editing
X
X	top-level
X	recursion-depth
X	recursive-edit
X	exit-recursive-edit
X	abort-recursive-edit
X	save-excursion
X
X
XBuffers
X	buffer-list
X	get-buffer
X	get-file-buffer
X	get-buffer-create
X	generate-new-buffer
X	buffer-name
X	buffer-number
X	buffer-file-name
X	buffer-local-variables
X	buffer-modified-p
X	set-buffer-modified-p
X	rename-buffer
X	other-buffer
X	buffer-flush-undo
X	kill-buffer
X	switch-to-buffer
X	pop-to-buffer
X	current-buffer
X	set-buffer
X	barf-if-buffer-read-only
X	bury-buffer
X	erase-buffer
X	list-buffers
X	lock-buffer
X	unlock-buffer
X
X	buffer-size
X	point-min
X	point-max
X
XStandard per-buffer variables and their uses
X
X	make-variable-buffer-local
X	make-local-variable
X	kill-local-variable
X	kill-all-local-variables
X
X
XPositions
X	point
X	window-point
X	set-window-point
X	register-to-point
X	point-to-register
X	buffer-size
X	point-max
X	point-min
X	bobp
X	eobp
X	bolp
X	eolp
X	beginning-of-buffer
X	end-of-buffer
X	goto-char
X	goto-line
X	forward-char
X	backward-char
X	forward-line
X	beginning-of-line
X	end-of-line
X	move-to-column
X
X	following-char
X	preceding-char
X	char-after
X	buffer-substring
X	buffer-string
X
X
X	markers
X	mark
X	set-mark
X	set-mark-command
X	exchange-point-and-mark
X	pop-mark
X	push-mark
X	process-mark
X	abbrev-prefix-mark
X	mark-marker
X	mark-word
X	mark-paragraph
X	mark-sexp
X	mark-page
X	mark-whole-buffer
X
X	markerp
X	integer-or-marker-p
X	make-marker
X	set-marker
X	point-max-marker
X	point-min-marker
X	marker-position
X	marker-buffer
X	point-marker
X	insert-before-markers
X
X	region-beginning
X	region-end
X	count-lines-region
X
X	clipping restrictions
X	narrow-to-region
X	widen
X	point-max
X	point-min
X	point-max-marker
X	point-min-marker
X	save-restriction
X	narrow-to-page
X
XInserting and Deleting
X	insert
X	quoted-insert
X	insert-before-markers
X	self-insert-and-exit
X	self-insert-command
X	insert-buffer-substring
X	newline
X	split-line
X	open-line
X
X	delete-region
X	subst-char-in-region
X
XBuffers and Regions
X	insert-buffer
X	append-to-buffer
X	prepend-to-buffer
X	copy-to-buffer
X
X	subst-char-in-region
X	zap-to-char
X		
X	delete-char
X	delete-backward-char
X	etc.
X
X	undo
X	buffer-flush-undo
X	undo-boundary
X	undo-more
X	undo-start
X	buffer-modified
X
X
XSearching and matching
X
X	looking-at
X	string-match
X	scan-buffer
X	skip-chars-forward
X	skip-chars-backward
X	search-backward
X	search-forward
X	word-search-backward
X	word-search-forward
X	re-search-backward
X	re-search-forward
X	replace-match
X	match-beginning
X	match-end
X	match-data
X	store-match-data
X	regexp-quote
X
X
XParsing and scanning
X
XSyntax Tables
X	syntax-table-p
X	syntax-table
X	standard-syntax-table
X	copy-syntax-table
X	set-syntax-table
X	char-syntax
X	describe-syntax
X
X
XMajor and Minor Modes
X
XKeymaps
X	keymapp
X	make-keymap
X	make-sparse-keymap
X	define-key
X	lookup-key
X	key-binding
X	local-key-binding
X	global-key-binding
X	global-set-key
X	local-set-key
X	global-unset-key
X	local-unset-key
X	define-prefix-command
X	use-global-map
X	use-local-map
X	current-local-map
X	accessible-keymaps
X	key-description
X	single-key-description
X	text-char-description
X	where-is-internal
X	where-is
X	describe-bindings
X	apropos
X	execute-extended-command
X	substitute-command-keys
X
X
XSelf-inserting commands
X
X	auto-fill
X	parenthesis matching
X	Abbreviations
X
XMinibuffer:
X	read-minibuffer
X	eval-minibuffer
X	read-string
X	read-no-blanks-input
X	read-command
X	read-function
X	read-variable
X	read-buffer
X	try-completion
X	all-completions
X	minibuffer-complete
X	minibuffer-complete-and-exit
X	minibuffer-completion-help
X	self-insert-and-exit
X	exit-minibuffer
X	Relate this to interactive.
X	Minibuffer keymaps.
X
XInput/Output
X
X	read-key-sequence
X	command-execute
X	input-pending-p
X	recent-keys
X	this-command-keys
X	open-dribble-file
X	discard-input
X	set-input-mode
X
X	message
X	format
X
X	write-char
X	with-output-to-temp-buffer
X	terpri
X	prin1
X	prin1-to-string
X	princ
X	print
X	read-char
X	get-file-char
X
X	read
X	read-from-string
X
X
XFiles
X	File data transfer.
X	File manipulation.
X
X	list-directory
X	directory-files
X	file-name-completion
X	file-name-all-completions
X	file-attributes
X
X
X	file-name-directory
X	file-name-nondirectory
X	make-temp-name
X	expand-file-name
X	substitute-in-file-name
X	copy-file
X	delete-file
X	rename-file
X	add-name-to-file
X	make-symbolic-link
X	file-exists-p
X	file-writable-p
X	file-symlink-p
X	file-directory-p
X	file-modes
X	set-file-modes
X	file-nlinks
X
X
X	recover-file
X	kill-some-buffers
X	auto-save-mode
X	make-auto-save-file-name
X	auto-save-file-name-p
X	save-buffers-kill-emacs
X	normal-mode
X	set-auto-mode
X	hack-local-variables
X	set-visited-file-name
X	write-file
X	backup-buffer
X	find-backup-file-name
X	save-buffer
X	basic-save-buffer
X	delete-auto-save-file-if-necessary
X	save-some-buffers
X	not-modified
X	toggle-read-only
X	do-auto-save
X	set-buffer-auto-saved
X	recent-auto-save-p
X	read-file-name-internal
X	read-file-name
X
X
X	insert-file-contents
X	insert-file
X	append-to-file
X	revert-buffer
X	recover-file
X
X	write-region
X	verify-visited-file-modtime
X	clear-visited-file-modtime
X
X
X	find-file
X	find-file-other-window
X	find-file-read-only
X	find-alternate-file
X	create-file-buffer
X	find-file-noselect
X	after-find-file
X	
X
X
XCommands and Keymaps 
X	interactive
X	call-interactively
X	vectors as key definitions.
X	strings as key definitions (macros).
X	Manipulating keymaps.
X
XWindows
X	windowp
X	pos-visible-in-window-p
X	window-buffer
X	window-height
X	window-width
X	window-hscroll
X	set-window-hscroll
X	window-edges
X	window-point
X	window-start
X	set-window-point
X	set-window-start
X	delete-window
X	next-window
X	previous-window
X	other-window
X	get-lru-window
X	get-largest-window
X	get-buffer-window
X	delete-other-windows
X	delete-windows-on
X	replace-buffer-in-windows
X	show-buffer
X	selected-window
X	select-window
X	display-buffer
X	split-window
X	enlarge-window
X	shrink-window
X
X	split-window-vertically
X	split-window-horizontally
X	enlarge-window-horizontally
X	shrink-window-horizontally
X
X
X	scroll-up
X	scroll-down
X	scroll-left
X	scroll-right
X	scroll-other-window
X	recenter
X	move-to-window-line
X	save-window-excursion
X
X	redraw-display
X	sit-for
X	sleep-for
X	ding
X
X	open-termscript
X	set-screen-height
X	set-screen-width
X	screen-height
X	screen-width
X	baud-rate
X	send-string-to-terminal
X
X
X
X
X
XProcesses
X	processp
X	get-process
X	get-buffer-process
X	delete-process
X	process-status
X	process-id
X	process-name
X	process-command
X	set-process-buffer
X	process-buffer
X	process-mark
X	set-process-filter
X	process-filter
X	set-process-sentinel
X	process-sentinel
X	process-kill-without-query
X	list-processes
X	start-process
X	accept-process-output
X	send-region
X	send-string
X	interrupt-process
X	kill-process
X	quit-process
X	stop-process
X	continue-process
X	process-send-eof
X	call-process
X	call-process-region
X
XOperating system interface
X	getenv
X	load-average
X	user-login-name
X	user-real-login-name
X	user-full-name
X	system-name
X	current-time-string
X	display-time
X
X	pwd
X	cd
X
X		
X	kill-emacs
X	dump-emacs
X	suspend-emacs
X
X
X	compile
X	grep
X	shell
X	shell-command
X	shell-command-on-region
X
X	rnews
X	rmail
X	mail
X
XPermutted Command Index
XSubject Index
SHAR_EOF
z=`wc -c < 'outline'`
if test 9622 -ne $z
then
	echo shar: error transmitting "'outline'" \($z characters read\)
fi
echo shar: extracting "'tutorial'" '(28064 characters)'
if test -f 'tutorial'
then
	echo shar: over-writing existing file "'tutorial'"
fi
sed 's/^X//' << \SHAR_EOF > 'tutorial'
XCopyright (C) 1986 Brian Marick
X
XHere's a tutorial on customizing Emacs that I put together.  I'd like to
Xknow if you think the basic approach makes sense, whether the structure of
Xthis instance of the approach looks okay, and whether I've picked a good
Xexample.  Thanks.
X
X
XComments to Brian Marick at one of these addresses:
Xmarick@gswd-vms.arpa  		(arpanet)
Xihnp4!uiucdcs!ccvaxa!marick	(usenet)
X
XNOTE: Part of the tutorial describes the code in shell.el.  The
Xdescriptions are accurate for 18.26 and probably for 18.27, 18.28, ...
XThey aren't right for 17.64 -- the most recent general release --
Xbecause the main routine being described was changed.  Since the routine
Xstill does the same thing, only with rearranged code, you should still be
Xable to map the description onto the code.
X
XThere may be other minor incompatibilities with older versions.
X
X---------------------------CUT HERE-------------------------------------
X@setfilename ../info/customizing-tutorial
X@node top, problem, (dir), (dir)
X@chapter A Simple Example of Customizing GNU Emacs
X@heading Introduction
X@subheading What Is This For?
XThe purpose of this tutorial is to demonstrate the process of
Xcustomization by having the reader work through an example.
XIt does not explore any part of GNU Emacs in great detail.
X
XThere's homework at the end, so that you can apply what you've
Xlearned, using a now-familiar chunk of code. (@xref{exercises})
X
X@subheading What Is This?
XThis file is something like a transcript, with commentary, of a GNU
XEmacs customization.  It is written somewhat in the style of the GNU
XEmacs tutorial, so that you can---and should---follow along and do the
Xcustomization yourself.  
X
X@subheading Who Is This For?
XThis particular customization was one of the first I did.  It is not a
Xcontrived example---it's what I actually did, recorded as I did it
X(though since modified for new versions of Emacs).  It's probably most
Xsuited to a person who knows Emacs, C, and some form of Lisp reasonably
Xwell.
X
X@subheading How to Use It?
X
XFirst, make a private directory and run Emacs there.  Run @code{info} and
Xselect @code{(customizing-emacs)}.  (@xref{(info)} for information about
X@code{info}.)  (You may also read this tutorial in hardcopy.  Hardcopy
Xsaves screen space, but you'll still need an info version so that you
Xcan copy text from it.)@refill
X
XRead through the text.  Some parts of the text explain Emacs code---read
Xthe explanation and also the actual code in another window.  Other parts of
Xthe text explain what I did to browse through Emacs code.  Do the same
Xbrowsing---and any other browsing that strikes your fancy.  Browsing is
Xfundamental to understanding.  Other parts of the text have actual large
Xchunks of new code, often following motivation and explanation.
XCopy that code into the working file (named below); install it and use
Xit as explained in the text (usually in paragraphs after the body of the
Xcode).
X
X@subheading Notation 
XFor the rest of this document, I'll assume that @var{gnu} represents the
Xlocation of the Emacs directory on your system.
X
X@subheading Author Information
XThis text is copyright @copyright{} 1986 by Brian Marick.
XPermission is granted to make and distribute verbatim copies,
Xprovided the copyright notice and this permission notice
Xare preserved on all copies.
X
X@ignore
XPermission is granted to process this file through Tex and print the
Xresults, provided the printed document carries copying permission
Xnotice identical to this one except for the removal of this paragraph
X(this paragraph not being relevant to the printed manual).
X@end ignore
X
XPlease send comments on this tutorial to marick@@gswd-vms.arpa or
Xihnp4!uiucdcs!ccvaxa!marick.
X
X
X@node problem, solution, top, top
X@heading The Problem and a Proposed Solution
X
XI make heavy use of the @code{csh(1)} @code{cdpath} feature.
X@code{cdpath} is a variable used by the shell in this way:
X
X@comment Quotation seems closest to the effect I want.
X@quotation
XIf you try to change your working directory to a relative pathname
Xthat is not a subdirectory of the current working directory, the @code{csh}
Xwill then check if the pathname is a subdirectory of any of the
Xdirectories in the @code{cdpath}.
X
XFor example, suppose you are in @file{/mnt/marick} and your @code{cdpath} contains
X@file{/lisp/testing}.  If you type @code{cd tests} and @file{/mnt/marick/tests} exists,
Xyou will change to that directory.  If @file{/mnt/marick/tests} does not
Xexist, but @file{/lisp/testing/tests} does, you will change to that directory.
X@end quotation
X
X@code{cdpath} can cause confusion when you use the shell within an Emacs
Xbuffer.  Emacs calculates the buffer's current working directory by
Xtrying to imitate the actions of the directory-changing commands.  Since
XEmacs doesn't know about the @code{cdpath}, it can't know that @code{cd
Xtests} means @code{cd /lisp/testing/tests}.  Consequently, after you
Xtype @code{cd tests}, Emacs's idea of the current working directory
Xdiffers from the shell's.
X
XOne possible solution would be to let Emacs know about the @code{cdpath}.
XHowever, that wouldn't work for another style of directory-changing.
XMany people use @code{csh} aliases to change directories.  For example, they
Xplace the following in their @file{.cshrc} file:
X
X@example
Xalias tests 'cd /lisp/testing/tests'
X@end example
X
Xso that typing @code{tests} to the shell changes to the 
X@file{/lisp/testing/tests} directory.
X
XThe most general solution seems to be to have all directory-changing
Xcommands and aliases print the directory stack after they do their work:
Xthat is, that they all do what @code{dirs(1)} does.  @code{pushd} and 
X@code{popd} already do
Xthat; this solution requires that users of @code{cd} alias it with@refill
X
X@example
Xalias cd 'cd \!*; dirs'
X@end example
X
Xand that other special aliases do the similar thing.
X
X@node solution, shell-send-input, problem, top
X@heading Implementing The Solution
X
XWhat we're concerned with is what Emacs does when it sends a
Xdirectory-changing command to the shell, which is surely a special case
Xof what it does when sending any command.  A first step is to look at
Xthe function that @key{RET} invokes when in a shell buffer.
X
XCall up a shell buffer with @code{M-x shell @key{RET}}.  Inside the
Xbuffer, type @code{C-h k @key{RET}} to see what function is bound to
X@key{RET}.  You will see that the function is @code{shell-send-input}.
XWe need to find where that function is defined.
X
XUsing @code{dired} on the GNU Emacs Lisp directory is one way to find
Xpossible source files.  (We'll see much better ways later.)
XDo that by typing @kbd{C-X d}.  
XAnswer @code{@var{gnu}/lisp/*.el} to the minibuffer prompt.@refill
X
XBrowing through the directory, we see this line:
X
X@example
X-r--r--r--  1 marick      13150 Jul 18 15:10 shell.el
X@end example
X
XSuch a file looks a likely candidate, so visit it (by typing @kbd{f} when the
Xcursor is on that line).  (Don't view it---we'll want to do
Xcursor-positioning, and view-mode turns off keys like Control-f and 
XControl-e.)
X
X
X@node shell-send-input, reading, solution, top
X@subheading Explanation of @code{shell-send-input}
X
X
X@code{shell-send-input} is indeed in this file.  Find it.
XHere (briefly) is what it does:
X
X@quotation
XThe first fourteen or so lines are concerned with acquiring the text to
Xsend to the shell.  That text is all the text on the current line, less
Xthe shell prompt.  (There are two cases: if the current line is at the
Xend of the buffer, it is newline terminated.  If it is within the
Xbuffer, it is copied to the end.)
X
XBefore sending the text to the shell, @code{shell-send-input} 
Xcalls @code{shell-set-directory}, which must be the code that checks
Xfor directory-changing commands.
X
XNotice that the call to @code{shell-set-directory} is wrapped within a
X@code{condition-case} and a @code{save-excursion}.  A
X@code{condition-case} catches any errors signalled by the enclosed code.
XIn this case, an error causes a call to the
X@code{shell-set-directory-error-hook}.  The default value for that hook
Xfunction is @code{ignore}, which silently ignores the error.@refill
X
XA @code{save-excursion} prevents any changes made to the mark and point
Xfrom affecting their values outside the enclosed code.
X
XWe could, at this point, try to make use of the
X@code{shell-set-directory-error-hook} to solve our problem, but instead
Xlet's continue on our original course and examine
X@code{shell-set-directory}.@refill
X
XIn general, directory-changing commands manipulate the
X@code{shell-directory-stack}.  Note that this stack is not the same as
Xthe shell's stack (as printed by @code{dirs}).  The shell keeps the
Xcurrent directory on the stack; Emacs keeps only old directories.  
X(We must remember to maintain this convention when we make changes.)
X
XIn particular, the code is split into several cases.
X
XIf the command matches the @code{shell-popd-regexp} and the popd has no
Xarguments, the Emacs @code{cd} function is used to change to the top
Xdirectory on the stack and the stack is popped.
X
XIf the command matches the @code{shell-pushd-regexp}, one of two things
Xhappens:
X@enumerate
X
X@item
XIf the @code{pushd} has no arguments, that means ''switch the top two
Xelements of the shell stack''.  That's done by popping and changing to
Xthe top directory on the Emacs stack and pushing the previously-current
Xdirectory on the stack.@refill
X
X@item
XIf the @code{pushd} has an argument, the argument is read and 
Xvariables and special metacharacters are expanded to find a 
Xdirectory to move to.  The previously-current directory is 
Xpushed on the stack, and the current directory is changed.  
XIf, however, the directory doesn't exist 
X(function @code{file-directory-p} returns @code{nil}), the 
XEmacs @code{shell-directory-stack} is not changed, nor is
Xthe current directory.  (Note that this is what would happen 
Xif Emacs tried to execute @code{pushd testing} in our stock 
Xexample.)
X
X@quotation
XTANGENT: the @code{substitute-in-file-name} function is the first one
Xwhose purpose hasn't been reasonably obvious.  We might want to
Xlook at it to see what it does.  First, create a tag file in
Xthis directory by executing the @code{etags} program with
X
X@example
XM-! etags @var{gnu}/lisp/*.el @key{RET}
X@end example
X
Xthen position the cursor over the use of @code{substitute-in-file-name}
Xand type @kbd{Meta-.}.  You'll be asked for a tag to find; typing just a
Xcarriage return will take you to the definition of
X@code{substitute-in-file-name}.  Next, you'll be asked which tag table
Xto visit---make sure you visit the one you've just created.@refill
X
XConfusion!  The search fails.  One possible explanation is that
Xthis function is defined in C, not Lisp.  We need to make our
Xtag table more comprehensive.  Here's a way of doing it:
X
X@example
XM-! etags @var{gnu}/lisp/*.el @var{gnu}/src/*.[ch] @key{RET}
X@end example
X
XNow @kbd{M-. @key{RET}} shows the function.  Reading
X@code{substitute-in-file-name} reveals that it can signal errors, 
Xwhich explains a need for the condition-case, which 
Xcatches and (by default) ignores them.@refill
X@end example
X@end enumerate
X
XContinuing with the explanation of the function:
X
XIf the command matches the @code{shell-cd-regexp}, one of two things happens:
X@enumerate
X
X@item
XIf the command has no arguments, Emacs changes to the home
Xdirectory.  Note that the @code{shell-directory-stack} needn't change.
X
X@item
XIf the command has an argument, it is expanded and Emacs changes
Xto that directory.
X@end enumerate
X@end quotation
X
XReturning to @code{shell-send-input}: after the call to
X@code{shell-set-directory}, we notice the three lines of code that
Xactually send the command to the shell.
X
X
XIt appears that what we need to do is combine and 
Xrearrange the code in this way:
X
X@enumerate
X@item
XCheck and remember if the command matches any of the three regexps.
X@item
XSend the command to shell.
X@item
XIf we saw a matching command,
X@enumerate
X@item
XRead what the shell just printed.
X@item
XIf it wasn't an error message,
X@enumerate
X@item
XParse the string into a list of strings.
X@item
XChange directory to the first one and throw it away.
X@item
XSubstitute and expand the remaining strings.
X@item
XMake that the shell-directory-stack.
X@end enumerate
X@end enumerate
X@end enumerate
X
X@node reading, parsing, shell-send-input, top
X@subheading Subproblem 1:  How to read what the shell prints.  
X
XLooking at the code that sends to the shell, we see that it sends
Xthrough @code{last-input-end}.  The text between 
X@code{last-input-end} and a following
Xnewline ought to be what we want.  The code to extract the shell's output
Xought to look something like the code that's already used to extract 
Xthe argument part of a directory-changing command.@refill
X
XWe should write this code now, before going on.  We begin by editing a
Xfile called @file{custom-shell.el}, which will be used for all our changes to
XEmacs shell interaction code.  We will 
X@enumerate
X
X@item
Xcopy in the code for @code{shell-send-input} and change its name to
X@code{test-shell-send-input}, 
X
X@item
Xremove the code that parses directory-changing commands, since we'll
Xbe letting the shell do that, 
X
X@item
Xand add code that extracts what the shell prints (the @code{dirs}-style 
Xdirectory stack) and displays it.
X@end enumerate
X
XOne question:  how to display what's extracted?---how to debug?
XIf you look at the code
Xfor @code{shell-send-input}, you'll see that it expects to be run when a
X@key{RET} is
Xtyped, since it searches for that character.  That makes it inconvenient
Xto call @code{test-shell-send-input} in any other way.@refill
X
XAn obvious---and generally useful---thing to do is display
Xthe result in the minibuffer.  Fortunately, we remember that changing
Xthe directory in a shell window already prints the new directory in the
Xminibuffer.  So we look at (using tags) 
Xthe @code{cd} function, which leads us to 
X@code{pwd}, which
Xshows us the @code{message} function, which is what we want.@refill
X
XThe final version looks like this, where lines marked with @code{;NEW} are new.
X@group
X
X@example
X(defun test-shell-send-input ()
X  (interactive)
X  (end-of-line)
X  (if (eobp)
X      (progn
X        (move-marker last-input-start
X                     (process-mark (get-buffer-process (current-buffer))))
X        (insert ?\n)
X        (move-marker last-input-end (point)))
X    (beginning-of-line)
X    (re-search-forward shell-prompt-pattern nil t)
X    (let ((copy (buffer-substring (point)
X                                  (progn (forward-line 1) (point)))))
X      (goto-char (point-max))
X      (move-marker last-input-start (point))
X      (insert copy)
X      (move-marker last-input-end (point))))
X  (let ((process (get-buffer-process (current-buffer))))
X    (send-region process last-input-start last-input-end)
X    (set-marker (process-mark process) (point))
X    (accept-process-output process))                            ;NEW
X  (save-excursion                                               ;NEW
X    (message "%s"                                               ;NEW
X             (buffer-substring last-input-end                   ;NEW
X                               (progn                           ;NEW
X                                 (goto-char last-input-end)     ;NEW
X                                 (skip-chars-forward "^\n")     ;NEW
X                                 (point))))))                   ;NEW
X@end example
X
X@end group
XMost of the NEW lines correspond well to what we planned to do.  We
Xprint a message from the end of the input through the next newline.  The
X@code{save-excursion} prevents the changes to the point from contaminating
Xwhere the user left the cursor.
X
XWhat's very different is use of @code{accept-process-output}.  In retrospect,
Xof course, it's obvious why it's necessary, but finding out in the first
Xplace was some work.  The reason is that @code{send-region} sends commands to
Xthe process but doesn't wait for the process to respond.  So if we later
Xtried to skip past a line of the shell's output, we'd get a null string,
Xbecause there isn't any output yet.  @code{accept-process-output} (which we
Xdiscovered by looking at @code{send-region} through the tag table and browsing
Xthrough the file that contained it) waits for process output.
X
XNote that the real version of @code{shell-send-input} should only use
X@code{accept-process-output} when a directory-changing command has been seen.
XWe don't want to block on any arbitrary line of input sent to the
Xshell, only on directory-changing commands.
X
XTry playing around with the code; simulate what's done during debugging.
X(For example, remove the call to @code{accept-process-output}.)  
XTo execute the code, do the following:
X@enumerate
X
X@item
XEvaluate the definition with @kbd{C-M-x}.
X(Note:  @kbd{C-M-x} expects to find @code{(def} at the beginning of the
Xfirst line in the function, so remove the leading blanks.)
X
X@item
XCreate a shell, and install this new function as the function bound to 
X@key{RET} with
X
X@example
XM-x local-set-key @key{RET} @key{RET} test-shell-send-input
X@end example
X
X@item
XType things  to the shell.  (Try @code{echo wombat} and @code{dirs}.)
X@end enumerate
X
X@node parsing, new-shell-send-input, reading, top
X@subheading Subproblem 2:  Parsing shell output.
X
XThe only remaining problematic part of our original plan is parsing the
Xoutput from the shell into a list of strings.  Since strings are a basic
Xdatatype, the routines to manipulate them are probably written in C.
X
XGrepping for string functions with 
X
X@example
XM-x grep 'DEFUN.*string' @var{gnu}/src/*.c
X@end example
X
Xyields a quite a number of functions, including
X
X@example
X../src/fns.c:362:DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
X@end example
X
XBrowsing through @file{fns.c}, we discover a number of useful functions ---
Xnotably @code{elt}, to extract characters from a string.  With those two
Xfunctions and the special form @code{while} that we remember seeing during
Xearlier browsing, it's easy to write a function like we need:
X
X@group
X@example
X;;; This code expects a string of directories.  Each one (including the
X;;; last) should be terminated by a single space, in the style of the
X;;; csh(1) "dirs" command.  That given, it's straightforward to iterate
X;;; down the string, extracting substrings at each space and pushing
X;;; them on a list.  That list (which is now in reverse order) should
X;;; have substitute-in-file-name and expand-file-name applied to each
X;;; element, to get a list of absolute pathnames without metacharacters.
X
X(defun parse-and-expand-directories (shell-directory-stack)
X  (let ((result nil))
X    (let ((first-char 0)		; first character of directory.
X          (pos 0)			; current position rover.
X          (len (length shell-directory-stack)))	; Stop here.
X    
X      (while (< pos len)
X        (cond ((eql (elt shell-directory-stack pos) ?\ )
X               (setq result
X                     (cons (substring shell-directory-stack first-char pos)
X                           result))
X               (setq first-char (+ pos 1))))
X        (setq pos (+ 1 pos))))
X    (mapcar (function (lambda (directory)
X                        (expand-file-name
X                          (substitute-in-file-name directory))))
X            (nreverse result))))
X@end example
X
X@end group
XWe install this function with @kbd{C-M-x}, as we did with @code{shell-send-input.}
XWe then test it by switching to the @samp{*scratch*} buffer, which is a
XLisp-Interaction mode buffer, and typing the following, followed by a
X@key{LFD}.
X
X@example
X(parse-and-expand-directories "~ ~wombat /lisp/bin /tmp/$USER ")
X@end example
X
XThe result looks correct:
X
X@example
X("/mnt/marick" "/mnt/wombat" "/lisp/bin" "/tmp/marick")
X@end example
X
X
X@node new-shell-send-input, exercises, parsing, top
X@subheading Back to the Main Problem:
X
XWe're now ready to write the new version of @code{shell-send-input}.  One
Xremaining question is how to detect when the shell signals an error.
XNote that we depend on a successful directory-change sending back a
Xblank-terminated line.  A couple of simple tests show that error
Xmessages generally are @i{not} blank terminated.  So we'll let the
Xpresence or absence of a trailing blank determine whether an error has
Xoccurred.  (This is, of course, somewhat shaky design---if it proves
Xinadequate, we'll do something else.)
X
XAfter some debugging with a shell window, we arrive at this function:
X@group
X
X@example
X;;; New version of shell-send-input.  The old version could get
X;;; confused about the current working directory.  This version
X;;; expects directory-changing-commands to print a ''dirs(1)''-style
X;;; message after finishing.  This function then reads that line,
X;;; parses it, and installs it as the value of shell-directory-stack.
X;;; Things to know:
X;;; 1.  We detect errors in the directory-changing command by looking
X;;; for a missing space at the end of the output line.  Dirs puts one
X;;; there, error messages don't generally have one.  This is shaky.
X;;; 2.  There's really no point to having a shell-directory-stack any
X;;; more, nor to having three different directory-changing regexps.
X;;; These are retained for compatibility, also in case there's a use
X;;; for them someday.
X
X
X(defun shell-send-input ()
X  "Send input to subshell.
XAt end of buffer, sends all text after last output
X as input to the subshell, including a newline inserted at the end.
XNot at end, copies current line to the end of the buffer and sends it,
Xafter first attempting to discard any prompt at the beginning of the line
Xby matching the regexp that is the value of shell-prompt-pattern if
Xpossible.  This regexp should start with \"^\"."
X  (interactive)
X  (end-of-line)
X  (if (eobp)
X      (progn
X        (move-marker last-input-start
X                     (process-mark (get-buffer-process (current-buffer))))
X        (insert ?\n)
X        (move-marker last-input-end (point)))
X    (beginning-of-line)
X    (re-search-forward shell-prompt-pattern nil t)
X    (let ((copy (buffer-substring (point)
X                                  (progn (forward-line 1) (point)))))
X      (goto-char (point-max))
X      (move-marker last-input-start (point))
X      (insert copy)
X      (move-marker last-input-end (point))))
X  (let ((directory-change-possible
X           (save-excursion
X             (progn
X               (goto-char last-input-start)
X               (or (looking-at shell-popd-regexp)
X                   (looking-at shell-pushd-regexp)
X                   (looking-at shell-cd-regexp))))))
X      ;; Now send the command to the shell.  If a directory change is
X      ;; possible, wait for a reply.
X      (let ((process (get-buffer-process (current-buffer))))
X        (send-region process last-input-start last-input-end)
X        (set-marker (process-mark process) (point))
X        (if directory-change-possible
X            (accept-process-output process)))
X
X      ;; If we might have changed the directory, parse the shell's answer.
X      (if directory-change-possible
X          (let ((shell-answer
X                 (save-excursion
X                   (buffer-substring last-input-end
X                                     (progn
X                                       (goto-char last-input-end)
X                                       (skip-chars-forward "^\n")
X                                       (point))))))
X            ;; Test to see whether we've been given a directory list or
X            ;; an error message.  Determined by whether there's a trailing
X            ;; blank on the line.  If no error, set up the
X            ;; shell-directory-stack.
X            (cond ((eql (elt shell-answer (- (length shell-answer) 1))
X                        ?\ )
X                   (setq shell-directory-stack
X                         (parse-and-expand-directories shell-answer))
X                   (cd (car shell-directory-stack))
X                   (setq shell-directory-stack
X                         (cdr shell-directory-stack))))))))
X@end example
X@end group
X
XTest @code{shell-send-input}.  Notice that @code{shell-send-input}
Xdisplays the new directory on the message line.  When you try to change
Xto a nonsense directory, it displays nothing.  You can see that the
XEmacs buffer's directory is still the same as the shell's by typing
X@code{dirs} to the shell and typing 
X
X@example
XC-h v default-directory @key{RET}
X@end example
X
Xto Emacs.
X
XWhen you're finished testing, place the functions
X@code{parse-and-expand-directories} and @code{shell-send-input} into the
Xfile @file{custom-shell.el}, compile it with
X
X@example
XM-x byte-compile-file @key{RET}
X@end example
X
Xload it with
X
X@example
XM-x load-library @key{RET} custom-shell @key{RET}
X@end example
X
Xand try it out some more.  It still works.
X
XNow we need only install the file in some standard directory and find a
Xway to load it.  The easiest thing to do is just load @file{shell} and
X@file{custom-shell} in our @file{.emacs} file.  (Slightly better is to
Xjust load @file{custom-shell} and have @file{custom-shell.el} include
Xthe line
X
X@example
X(require 'shell)
X@end example
X
Xwhich causes the loading of @file{shell.elc}.)
X
XAlternatively, we can only load @file{custom-shell.el} when a shell process is
Xstarted.  This is done with the following @code{shell-mode-hook}:
X
X@example
X(setq shell-mode-hook
X      '(lambda ()
X         (require 'custom-shell)))
X@end example
X
XWe use @code{require} instead of @code{load} because the
X@code{shell-mode-hook} is executed whenever we switch to the shell
Xbuffer with
X
X@example
XM-x shell
X@end example
X
XWe don't want to reload it quite so often.  Note that we must put a
X
X@example
X(provide 'custom-shell)
X@end example
X
Xin @file{custom-shell.el}.
X
X@node exercises, customization-structure, new-shell-send-input, top
X@heading Exercises
X
X@enumerate
X
X@item
XThere is a flaw in the shell code.  Suppose, for example, that
XI have @code{b} aliased to @code{popd}.  What happens when I type
X@example
Xbm <pattern> <some-enormous-set-of-files>
X@end example
X(@code{bm} is a fast string-search program.)
X
XYou will see that Emacs waits for the command to complete, thinking
Xit's a directory-changing command.  Fix this problem.
X
X@item
XWhat happens if there's extra white space between the prompt and the
Xcommand?  Fix this problem.
X
X@item
XFind a better way to detect shell error messages.
X
X@item
XOur implementation assumes that @code{accept-process-input} will return
Xa complete line.  What if it doesn't?
X
X@item
XNow that you're familiar with the shell command, give users the
Xability to easily create multiple shell buffers.  (For example, 
Xthe @code{shell} command might take a prefix argument, or it might
Xprompt for the name of a shell.)
X@end enumerate
X
X@node customization-structure, top, exercises, top
X@heading A General Problem
X
XNow that you've finished this customization, what do you do with
Xit?  I think that's a general problem: often you want to modify
Xparticular functions within a standard Emacs Lisp file, but you
Xdon't want to change that file.  Neither do you want to copy the
Xentire standard file, since that would isolate you from further
Xchanges to it, changes that might, for example, fix bugs.
X
XA solution might be to have the new file @dfn{shadow} the old one in
Xthe following way:
X
X@enumerate
X@item
XPut the new file in a new directory.  Give it the same name
Xas the shadowed file.  It will now be loaded in preference to
Xthe old file if you have the new directory early in the @code{load-path}.
X
X@item
XTo avoid having to include all of the old file in the new one, arrange for
Xthe new file to load the old file as it itself is being loaded.
X@end enumerate
X
XDick King has suggested another way to accomplish much the same thing.
XHe suggests that @code{defun} come in two versions, aggressive and
Xpassive.  Aggressive @code{defuns} behave as @code{defun} does now.
X(That is, a new defun overrides an old one with the same name.)  Passive
X@code{defuns}, when read from a file, would not override old definitions.
X
XShadowing changes could be made with aggressive @code{defuns}.
XThus, they would be immune to load order---we would not have to
Xcarefully arrange things so that our version of @code{shell-send-input}
Xis loaded only after all of @file{shell.elc} is loaded.
X
X@bye
X
SHAR_EOF
z=`wc -c < 'tutorial'`
if test 28064 -ne $z
then
	echo shar: error transmitting "'tutorial'" \($z characters read\)
fi
#	End of shell archive
exit 0