|
|
1.1 root 1: ;;
2: ;; copyright (C) 1987, 1988 Franz Inc, Berkeley, Ca.
3: ;;
4: ;; The software, data and information contained herein are the property
5: ;; of Franz, Inc.
6: ;;
7: ;; This file (or any derivation of it) may be distributed without
8: ;; further permission from Franz Inc. as long as:
9: ;;
10: ;; * it is not part of a product for sale,
11: ;; * no charge is made for the distribution, other than a tape
12: ;; fee, and
13: ;; * all copyright notices and this notice are preserved.
14: ;;
15: ;; If you have any comments or questions on this interface, please feel
16: ;; free to contact Franz Inc. at
17: ;; Franz Inc.
18: ;; Attn: Kevin Layer
19: ;; 1995 University Ave
20: ;; Suite 275
21: ;; Berkeley, CA 94704
22: ;; (415) 548-3600
23: ;; or
24: ;; emacs-info%[email protected]
25: ;; ucbvax!franz!emacs-info
26:
27: ;; $Header: subproc.el,v 1.46 88/11/22 20:21:39 layer Exp $
28:
29: ;; This file has its (distant) roots in lisp/shell.el, so:
30: ;;
31: ;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
32: ;;
33: ;; This file is derived from part of GNU Emacs.
34: ;;
35: ;; GNU Emacs is distributed in the hope that it will be useful,
36: ;; but WITHOUT ANY WARRANTY. No author or distributor
37: ;; accepts responsibility to anyone for the consequences of using it
38: ;; or for whether it serves any particular purpose or works at all,
39: ;; unless he says so in writing. Refer to the GNU Emacs General Public
40: ;; License for full details.
41: ;;
42: ;; Everyone is granted permission to copy, modify and redistribute
43: ;; GNU Emacs, but only under the conditions described in the
44: ;; GNU Emacs General Public License. A copy of this license is
45: ;; supposed to have been given to you along with GNU Emacs so you
46: ;; can know your rights and responsibilities. It should be in a
47: ;; file named COPYING. Among other things, the copyright notice
48: ;; and this notice must be preserved on all copies.
49:
50: ;; Low-level subprocess mode guts
51:
52: ;;;;
53: ;;; Variables and Constants
54: ;;;;
55:
56: (defvar fi:common-lisp-image-name "cl"
57: "*Default Common Lisp image to invoke from `fi:common-lisp'. If the
58: value is a string then it names the image file or image path that
59: `fi:common-lisp' invokes. Otherwise, the value of this variable is given
60: to funcall, the result of which should yield a string which is the image
61: name or path.")
62:
63: (defvar fi:common-lisp-image-arguments nil
64: "*Default Common Lisp image arguments when invoked from `fi:common-lisp',
65: which must be a list of strings.")
66:
67: (defvar fi:common-lisp-prompt-pattern
68: "^\\(\\[[0-9]+c?\\] \\|\\[step\\] \\)?<[-A-Za-z]* ?[0-9]*?> "
69: "*The regular expression which matches the Common Lisp prompt, used in
70: Inferior Common Lisp mode. Anything from beginning of line up to the end
71: of what this pattern matches is deemed to be a prompt.")
72:
73: (defvar fi:franz-lisp-image-name "lisp"
74: "*Default Franz Lisp image to invoke from `fi:franz-lisp'. If the value
75: is a string then it names the image file or image path that
76: `fi:common-lisp' invokes. Otherwise, the value of this variable is given
77: to funcall, the result of which should yield a string which is the image
78: name or path.")
79:
80: (defvar fi:franz-lisp-image-arguments nil
81: "*Default Franz Lisp image arguments when invoked from `fi:franz-lisp'.")
82:
83: (defvar fi:franz-lisp-prompt-pattern
84: "^[-=]> +\\|^c{[0-9]+} +"
85: "*The regular expression which matches the Franz Lisp prompt, used in
86: Inferior Franz Lisp mode. Anything from beginning of line up to the end
87: of what this pattern matches is deemed to be a prompt.")
88:
89: (defvar fi:shell-popd-regexp ":?popd"
90: "*The regular expression matching the C shell `popd' command. If nil, no
91: automatic directory changes will be made.")
92:
93: (defvar fi:shell-pushd-regexp ":?pushd"
94: "*The regular expression matching the C shell `pushd' command. If nil,
95: no automatic directory changes will be made.")
96:
97: (defvar fi:shell-cd-regexp ":?cd"
98: "*The regular expression matching the C shell `cd' command. If nil,
99: no automatic directory changes will be made.")
100:
101: (defvar fi:common-lisp-package-regexp
102: "(in-package\\>\\|:\\<pa\\>\\|:\\<pac\\>\\|:\\<pack\\>\\|:\\<packa\\>\\|:\\<packag\\>\\|:\\<package\\>"
103: "*The regular expression matching the Common Lisp expression(s) to change
104: packages. If nil, no automatic package tracking will be done.")
105:
106: (defvar fi:subprocess-map-nl-to-cr nil
107: "*If t, then map newline to carriage-return.")
108:
109: (defvar fi:subprocess-continuously-show-output-in-visible-buffer t
110: "*If t, output from a subprocess to a visible buffer is continuously
111: shown. If a subprocess buffer is visible and the window point is beyond
112: the process output marker, output to that buffer from its associated
113: process will be continuously visible. If the window point is before the
114: process output marker, the window is not updated. This is a buffer-local
115: symbol.")
116:
117: (defvar fi:subprocess-write-quantum 120
118: "*Maximum size in bytes of a single write request to a subprocess.")
119:
120: (defvar fi:subprocess-enable-superkeys nil
121: "*If t, certain keys become `superkeys' in subprocess buffers--this
122: should be set before starting any subprocesses. The superkeys are C-a,
123: C-d, C-o,C-u, C-w, C-z, and C-\\, which will behave as they would in the
124: current local keymap when typed at the end of a subprocess buffer. If
125: typed elsewhere, these keys have their normal global binding. This is a
126: buffer-local symbol. Use setq-default to set the default value for this
127: symbol.")
128:
129: (defvar fi:display-buffer-function 'switch-to-buffer
130: "*If non-nil, then it is used as the function which is funcall'd with one
131: argument, a buffer, to display a subprocess buffer when it is created (ie,
132: from `fi:common-lisp').")
133:
134: ;;;;;;;;;;;;;;;;;;;;;; internal vars
135:
136: (defvar fi::cl-package-regexp nil
137: "The real Common Lisp package regexp, which is nil in all buffer except
138: Inferior Common Lisp buffers.")
139:
140: (defvar fi::last-input-start nil
141: "Marker for start of last input in fi:shell-mode or fi:inferior-lisp-mode
142: buffer.")
143:
144: (defvar fi::last-input-end nil
145: "Marker for end of last input in fi:shell-mode or fi:inferior-lisp-mode
146: buffer.")
147:
148: (defvar fi::sublisp-name nil
149: "Name of inferior lisp process.")
150:
151: (defvar fi::freshest-franz-sublisp-name nil
152: "Name of franz lisp subprocess most recently invoked.")
153:
154: (defvar fi::freshest-common-sublisp-name nil
155: "Name of common lisp subprocess most recently invoked.")
156:
157: (defvar fi::shell-directory-stack nil
158: "List of directories saved by pushd in this buffer's shell.")
159:
160: ;;;;
161: ;;; User visible functions
162: ;;;;
163:
164: (defun fi:common-lisp (&optional buffer-number)
165: "Start a Common Lisp subprocess in a buffer whose name is determined
166: from the optional prefix argument BUFFER-NUMBER. Common Lisp buffer names
167: start with `*common-lisp' and end with `*', with an optional `-N' in
168: between. If BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER
169: is >= 0, then the buffer is named `*common-lisp-<BUFFER-NUMBER>*'. If
170: BUFFER-NUMBER is < 0, then the first available buffer name is chosen.
171:
172: The image file and image arguments are taken from the variables
173: `fi:common-lisp-image-name' and `fi:common-lisp-image-arguments'.
174:
175: See fi:explicit-common-lisp."
176: (interactive "p")
177: (let ((proc (fi::make-subprocess
178: buffer-number "common-lisp"
179: 'fi:inferior-common-lisp-mode
180: fi:common-lisp-prompt-pattern
181: fi:common-lisp-image-name
182: fi:common-lisp-image-arguments)))
183: (setq fi::freshest-common-sublisp-name (process-name proc))
184: proc))
185:
186: (defun fi:explicit-common-lisp (&optional buffer-number
187: image-name image-arguments)
188: "The same as fi:common-lisp, except that the image and image arguments
189: are read from the minibuffer."
190: (interactive "p\nsImage name: \nxImage arguments (a list): ")
191: (let ((proc (fi::make-subprocess
192: buffer-number "common-lisp"
193: 'fi:inferior-common-lisp-mode
194: fi:common-lisp-prompt-pattern
195: image-name image-arguments)))
196: (setq fi::freshest-common-sublisp-name (process-name proc))
197: proc))
198:
199: (defun fi:remote-common-lisp (&optional buffer-number host)
200: "Start a Common Lisp subprocess in a buffer whose name is determined
201: from the optional prefix argument BUFFER-NUMBER, where the Common Lisp
202: image is run on another machine. Common Lisp buffer names start with
203: `*common-lisp' and end with `*', with an optional `-N' in between. If
204: BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER is >= 0,
205: then the buffer is named `*common-lisp-<BUFFER-NUMBER>*'. If BUFFER-NUMBER
206: is < 0, then the first available buffer name is chosen.
207:
208: The host on which the image is run is read from the minibuffer.
209:
210: The image file and image arguments are taken from the variables
211: `fi:common-lisp-image-name' and `fi:common-lisp-image-arguments'.
212:
213: See fi:explicit-remote-common-lisp."
214: (interactive "p\nsRemote host name: ")
215: (let ((proc (fi::make-subprocess
216: buffer-number "common-lisp"
217: 'fi:inferior-common-lisp-mode
218: fi:common-lisp-prompt-pattern
219: "rsh"
220: (append (list host fi:common-lisp-image-name)
221: fi:common-lisp-image-arguments))))
222: (setq fi::freshest-common-sublisp-name (process-name proc))
223: proc))
224:
225: (defun fi:explicit-remote-common-lisp (&optional buffer-number host
226: image-name image-arguments)
227: "The same as fi:remote-common-lisp, except that the image and image
228: arguments are read from the minibuffer."
229: (interactive
230: "p\nsRemote host name: \nsImage name: \nxImage arguments (a list): ")
231: (let ((proc (fi::make-subprocess
232: buffer-number "common-lisp"
233: 'fi:inferior-common-lisp-mode
234: fi:common-lisp-prompt-pattern
235: "rsh"
236: (append (list host image-name) image-arguments))))
237: (setq fi::freshest-common-sublisp-name (process-name proc))
238: proc))
239:
240: (defun fi:tcp-common-lisp (&optional buffer-number)
241: "In a buffer whose name is determined from the optional prefix argument
242: BUFFER-NAME, connect to a Common Lisp using either a UNIX domain socket
243: file or internet port number. Common Lisp buffer names start with
244: `*common-lisp' and end with `*', with an optional `-N' in between. If
245: BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER is >= 0,then
246: the buffer is named `*common-lisp-<BUFFER-NUMBER>*'. If BUFFER-NUMBER is <
247: 0, then the first available buffer name is chosen.
248:
249: See `fi:unix-domain' and `fi:explicit-tcp-common-lisp'."
250: (interactive "p")
251: (let ((proc (fi::make-tcp-connection
252: buffer-number "tcp-common-lisp" 'fi:tcp-common-lisp-mode
253: fi:common-lisp-prompt-pattern)))
254: (setq fi::freshest-common-sublisp-name (process-name proc))
255: proc))
256:
257: (defun fi:explicit-tcp-common-lisp (&optional buffer-number host service)
258: "The same as fi:tcp-common-lisp, except that the host name a port number
259: are read from the minibuffer. Use a port number of 0 for UNIX domain
260: sockets."
261: (interactive
262: "p\nsHost name: \nnService port number (0 for UNIX domain): ")
263: (let ((proc (fi::make-tcp-connection
264: buffer-number "tcp-common-lisp" 'fi:tcp-common-lisp-mode
265: fi:common-lisp-prompt-pattern
266: host service)))
267: (setq fi::freshest-common-sublisp-name (process-name proc))
268: proc))
269:
270: (defun fi:franz-lisp (&optional buffer-number)
271: "Start a Franz Lisp subprocess in a buffer whose name is determined
272: from the optional prefix argument BUFFER-NUMBER. Franz Lisp buffer names
273: start with `*franz-lisp' and end with `*', with an optional `-N' in
274: between. If BUFFER-NUMBER is not given it defaults to 1. If BUFFER-NUMBER
275: is >= 0, then the buffer is named `*franz-lisp-<BUFFER-NUMBER>*'. If
276: BUFFER-NUMBER is < 0, then the first available buffer name is chosen.
277:
278: The image file and image arguments are taken from the variables
279: `fi:franz-lisp-image-name' and `fi:franz-lisp-image-arguments'.
280:
281: See fi:explicit-franz-lisp."
282: (interactive "p")
283: (let ((proc (fi::make-subprocess
284: buffer-number "franz-lisp"
285: 'fi:inferior-franz-lisp-mode
286: fi:franz-lisp-prompt-pattern
287: fi:franz-lisp-image-name
288: fi:franz-lisp-image-arguments)))
289: (setq fi::freshest-franz-sublisp-name (process-name proc))
290: proc))
291:
292: (defun fi:explicit-franz-lisp (&optional buffer-number
293: image-name image-arguments)
294: "The same as fi:franz-lisp, except that the image and image arguments
295: are read from the minibuffer."
296: (interactive "p\nsImage name: \nxImage arguments (a list): ")
297: (let ((proc (fi::make-subprocess
298: buffer-number "franz-lisp"
299: 'fi:inferior-franz-lisp-mode
300: fi:franz-lisp-prompt-pattern
301: image-name image-arguments)))
302: (setq fi::freshest-franz-sublisp-name (process-name proc))
303: proc))
304:
305: ;;;;
306: ;;; Internal functions
307: ;;;;
308:
309: (defun fi::make-subprocess (buffer-number process-name mode-function
310: image-prompt image-file
311: image-arguments)
312: (let* ((buffer (fi::make-process-buffer process-name buffer-number))
313: (default-dir default-directory)
314: (buffer-name (buffer-name buffer))
315: (process (get-buffer-process buffer))
316: (status (if process (process-status process)))
317: (runningp (memq status '(run stop)))
318: start-up-feed-name)
319: (if (and (not runningp)
320: (consp image-file))
321: (setq image-file (funcall image-file)))
322: (if fi:display-buffer-function
323: (funcall fi:display-buffer-function buffer)
324: (switch-to-buffer buffer))
325: (if runningp
326: (goto-char (point-max))
327: (setq default-directory default-dir)
328: (if process (delete-process process))
329: (setq process (apply 'start-process
330: (append (list buffer-name buffer image-file)
331: image-arguments)))
332: (set-process-sentinel process 'fi::subprocess-sentinel)
333: (set-process-filter process 'fi::subprocess-filter)
334: (setq start-up-feed-name
335: (if image-file
336: (concat "~/.emacs_" (file-name-nondirectory image-file))))
337: (cond
338: ((and start-up-feed-name (file-exists-p start-up-feed-name))
339: ;; I hope 1 second is enough!
340: (sleep-for 1)
341: (goto-char (point-max))
342: (insert-file-contents start-up-feed-name)
343: (setq start-up-feed-name (buffer-substring (point) (point-max)))
344: (delete-region (point) (point-max))
345: (fi::send-string-split process start-up-feed-name
346: fi:subprocess-map-nl-to-cr)))
347: (goto-char (point-max))
348: (set-marker (process-mark process) (point))
349: (let ((saved-input-ring fi::input-ring))
350: (funcall mode-function)
351: (setq fi::input-ring saved-input-ring))
352: (make-local-variable 'subprocess-prompt-pattern)
353: (setq subprocess-prompt-pattern image-prompt)
354: (fi::make-subprocess-variables))
355: process))
356:
357: (defun fi::make-tcp-connection (buffer-number buffer-name mode image-prompt
358: &optional given-host
359: given-service)
360: (let* ((buffer (fi::make-process-buffer buffer-name buffer-number))
361: (default-dir default-directory)
362: (buffer-name (buffer-name buffer))
363: (host (if given-host
364: (expand-file-name given-host)
365: (if fi:unix-domain
366: (expand-file-name fi:unix-domain-socket)
367: fi:local-host-name)))
368: (service (if given-service
369: given-service
370: (if fi:unix-domain 0 fi:excl-service-name)))
371: proc status)
372: (if fi:display-buffer-function
373: (funcall fi:display-buffer-function buffer)
374: (switch-to-buffer buffer))
375: (setq proc (get-buffer-process buffer))
376: (setq status (if proc (process-status proc)))
377: (if (eq status 'run)
378: (error
379: "can't start a TCP Common Lisp in a buffer which has a subprocess"))
380: (if (eq status 'open)
381: (goto-char (point-max))
382: (setq default-directory default-dir)
383: (setq proc (open-network-stream buffer-name buffer host service))
384: ;;
385: ;; HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
386: ;; The first input the new (Common Lisp) process is sent is the name
387: ;; of the process. This is so that the processes are named similarly
388: ;; in Emacs and Lisp.
389: ;;
390: (process-send-string proc (format "\"%s\"\n" (buffer-name buffer)))
391:
392: (goto-char (point-max))
393: (set-marker (process-mark proc) (point))
394: (let ((saved-input-ring fi::input-ring))
395: (funcall mode)
396: (setq fi::input-ring saved-input-ring))
397: (make-local-variable 'subprocess-prompt-pattern)
398: (setq subprocess-prompt-pattern image-prompt)
399: (fi::make-subprocess-variables))
400: proc))
401:
402: (defun fi::make-process-buffer (name number)
403: (let ((buffer-name
404: (cond
405: ((not (numberp number))
406: (concat "*" name "*"))
407: ((> number 1)
408: ;; just return the buffer name
409: (concat "*" name "-" number "*"))
410: ((< number 0)
411: ;; search for the first available buffer
412: (let (buffer-name n)
413: (if (not (fi::process-running
414: (setq buffer-name (concat "*" name "*"))))
415: buffer-name
416: (setq n 2)
417: (while (fi::process-running (setq buffer-name
418: (concat "*" name "-" n "*")))
419: (setq n (+ n 1)))
420: buffer-name)))
421: (t (concat "*" name "*")))))
422: (or (get-buffer buffer-name)
423: (get-buffer-create buffer-name))))
424:
425: (defun fi::make-subprocess-variables ()
426: (setq fi::input-ring-max fi:default-input-ring-max)
427: (setq fi::input-ring-yank-pointer nil)
428: (setq fi::shell-directory-stack nil)
429: (setq fi::last-input-search-string "")
430: (setq fi::last-input-start (make-marker))
431: (setq fi::last-input-end (make-marker)))
432:
433: (defun fi::send-region-split (process start-position end-position
434: &optional nl-cr)
435: "Send region to process in small pieces."
436: (interactive "sSend region in pieces (to process): \nr")
437: (let* ((start (if (markerp start-position)
438: (marker-position start-position)
439: start-position))
440: (end (if (markerp end-position)
441: (marker-position end-position)
442: end-position))
443: (string (buffer-substring start end)))
444: (fi::send-string-split process string nl-cr)))
445:
446: (defun fi::send-string-split (process string &optional nl-cr)
447: "Send string to process in small pieces using send-string."
448: (interactive "sSend (to process): \nsSend to process in pieces (string): ")
449: (let ((size (length string))
450: (filtered-string
451: (if nl-cr
452: (fi::substitute-chars-in-string '((?\n . ?\r)) string)
453: string))
454: (start 0))
455: (while (and (> size 0)
456: (condition-case nil
457: (progn
458: (send-string
459: process
460: (substring filtered-string
461: start
462: (+ start
463: (min size
464: fi:subprocess-write-quantum))))
465: t)
466: (error
467: (message "Error writing to subprocess.")
468: nil)))
469: (setq size (- size fi:subprocess-write-quantum))
470: (setq start (+ start fi:subprocess-write-quantum)))))
471:
472: ;;; Sentinel and filter for subprocesses. The sentinel is currently
473: ;;; not used.
474: (defun fi::subprocess-sentinel (process status)
475: t)
476:
477: (defun fi::subprocess-filter (process output &optional stay)
478: "Filter output from processes tied to buffers.
479: This function implements continuous output to visible buffers."
480: (let* ((old-buffer (current-buffer))
481: (buffer (process-buffer process))
482: (in-buffer (eq buffer old-buffer))
483: (window-of-buffer (get-buffer-window buffer))
484: (no-window (or (null window-of-buffer)
485: (not (windowp window-of-buffer))))
486: (xmarker (process-mark process))
487: (marker (if (marker-position xmarker)
488: xmarker
489: (set-marker (make-marker) 0 buffer)))
490: (marker-point (marker-position marker))
491: (output-length (length output))
492: old-point
493: point-not-before-marker
494: new-point)
495: ;; The three symbols below are not bound above because `(window-point)'
496: ;; for the selected window does not always return the same thing as the
497: ;; function `(point)' in that window! [Version 18 is supposed to fix
498: ;; this bug.]
499: ;; Note that there is no function that returns all of the windows that
500: ;; are currently displaying a buffer. Because of this, not all windows
501: ;; will be updated properly by this filter function. What should be
502: ;; done is to loop through all windows displaying the buffer and do
503: ;; `(set-window-point)' in each.
504: (if (not in-buffer)
505: (progn
506: (set-buffer buffer)
507: (setq old-point
508: (if no-window
509: (point)
510: (window-point window-of-buffer))))
511: (setq old-point (point)))
512: (setq point-not-before-marker (>= old-point marker-point))
513: (setq new-point (if point-not-before-marker
514: (+ old-point output-length)
515: old-point))
516: (save-excursion
517: ;; Go to point of last output by fi::make-process and insert new
518: ;; output there, preserving position of the marker.
519: (goto-char marker-point)
520: ;; The code below works around what appears to be a display bug
521: ;; in GNU Emacs 17. If `(insert-before-markers)' is used when
522: ;; the process marker (process-mark), window-start point
523: ;; (window-start), and window point (point) are all coincident,
524: ;; the window display `sticks' on the topmost line. We use
525: ;; `(insert-string)' followed by `(set-marker)' to avoid this
526: ;; problem. This also happens to be the way
527: ;; `handle_process_output()' deals with this in `process.c'.
528: (insert-string output)
529: (set-marker marker (point)))
530: (if (not in-buffer)
531: (if (and fi:subprocess-continuously-show-output-in-visible-buffer
532: point-not-before-marker)
533: ;; Keep window's notion of `point' in a constant relationship to
534: ;; the process output marker.
535: (if no-window
536: (goto-char new-point)
537: (set-window-point window-of-buffer new-point))
538: (if no-window
539: t;; Still there.
540: (set-window-point window-of-buffer old-point)))
541: (goto-char new-point))
542: (cond
543: (in-buffer nil)
544: (stay old-buffer)
545: (t (set-buffer old-buffer)))))
546:
547: (defun fi::subprocess-watch-for-special-commands ()
548: "Watch for special commands like, for example, `cd' in a shell."
549: (if (null fi::shell-directory-stack)
550: (setq fi::shell-directory-stack (list default-directory)))
551: (condition-case ()
552: ;; "To err is really not nice." -dkl 11/21/88
553: (save-excursion
554: (goto-char fi::last-input-start)
555: (cond
556: ((and fi::cl-package-regexp (looking-at fi::cl-package-regexp))
557: (goto-char (match-end 0))
558: (cond
559: ((or (looking-at "[ \t]*[':]\\(.*\\)[ \t]*)")
560: (looking-at "[ \t]*\"\\(.*\\)\"[ \t]*)"))
561: ;; (in-package foo)
562: (setq fi:package
563: (buffer-substring (match-beginning 1) (match-end 1))))
564: ((looking-at "[ \t]+\\(.*\\)[ \t]*$")
565: ;; :pa foo
566: (setq fi:package
567: (buffer-substring (match-beginning 1) (match-end 1)))))
568: ;; need to do something here to force the minibuffer to
569: ;; redisplay:
570: (set-buffer-modified-p (buffer-modified-p)))
571: ((and fi:shell-popd-regexp (looking-at fi:shell-popd-regexp))
572: (goto-char (match-end 0))
573: (cond
574: ((looking-at ".*&[ \t]*$")
575: ;; "popd ... &" executes in a subshell!
576: )
577: (t
578: (let ((n (if (looking-at "[ \t]+\\+\\([0-9]*\\)")
579: (car
580: (read-from-string
581: (buffer-substring (match-beginning 1)
582: (match-end 1)))))))
583: (if (null n)
584: (cd (car (setq fi::shell-directory-stack
585: (cdr fi::shell-directory-stack))))
586: ;; pop n'th entry
587: (if (> n (length fi::shell-directory-stack))
588: (message "Directory stack not that deep.")
589: (let ((tail (nthcdr (+ n 1) fi::shell-directory-stack)))
590: (rplacd (nthcdr (- n 1) fi::shell-directory-stack)
591: nil)
592: (setq fi::shell-directory-stack
593: (append fi::shell-directory-stack tail)))))))))
594: ((and fi:shell-pushd-regexp (looking-at fi:shell-pushd-regexp))
595: (goto-char (match-end 0))
596: (cond
597: ((looking-at ".*&[ \t]*$")
598: ;; "pushd ... &" executes in a subshell!
599: )
600: ((looking-at "[ \t]+\\+\\([0-9]+\\)[ \t]*[;\n]")
601: ;; pushd +n
602: (let ((n (car (read-from-string
603: (buffer-substring (match-beginning 1)
604: (match-end 1))))))
605: (if (< n 1)
606: (message "Illegal stack element: %s" n)
607: (if (> n (length fi::shell-directory-stack))
608: (message "Directory stack not that deep.")
609: (let ((head (nthcdr n fi::shell-directory-stack)))
610: (rplacd (nthcdr (- n 1) fi::shell-directory-stack)
611: nil)
612: (setq fi::shell-directory-stack
613: (append head fi::shell-directory-stack))
614: (cd (car head)))))))
615: ((looking-at "[ \t]+\\([^ \t]+\\)[;\n]")
616: ;; pushd dir
617: (let ((dir (expand-file-name
618: (substitute-in-file-name
619: (buffer-substring (match-beginning 1)
620: (match-end 1))))))
621: (if (file-directory-p dir)
622: (progn
623: (setq fi::shell-directory-stack
624: (cons dir fi::shell-directory-stack))
625: (cd dir)))))
626: ((looking-at "[ \t]*[;\n]")
627: ;; pushd
628: (if (< (length fi::shell-directory-stack) 2)
629: (message "Directory stack not that deep.")
630: (setq fi::shell-directory-stack
631: (append (list (car (cdr fi::shell-directory-stack))
632: (car fi::shell-directory-stack))
633: (cdr (cdr fi::shell-directory-stack))))
634: (cd (car fi::shell-directory-stack))))))
635: ((and fi:shell-cd-regexp (looking-at fi:shell-cd-regexp))
636: (goto-char (match-end 0))
637: (cond
638: ((looking-at ".*&[ \t]*$")
639: ;; "cd foo &" executes in a subshell!
640: )
641: ((looking-at "[ \t]*[;\n]")
642: ;; cd
643: (cd (rplaca fi::shell-directory-stack (getenv "HOME"))))
644: ((looking-at "[ \t]+\\([^ \t]+\\)[ \t]*[;\n]")
645: ;; cd dir
646: (let ((dir (expand-file-name
647: (substitute-in-file-name
648: (buffer-substring (match-beginning 1)
649: (match-end 1))))))
650: (if (file-directory-p dir)
651: (progn
652: (rplaca fi::shell-directory-stack dir)
653: (cd dir)))))))))
654: (error nil)))
655:
656: ;;;;
657: ;;; Initializations
658: ;;;;
659:
660: (mapcar 'make-variable-buffer-local
661: '(fi:shell-popd-regexp
662: fi:shell-pushd-regexp
663: fi:shell-cd-regexp
664: fi::cl-package-regexp
665: fi:package
666: fi:subprocess-map-nl-to-cr
667: fi:subprocess-continuously-show-output-in-visible-buffer
668: fi:subprocess-enable-superkeys
669: fi:subprocess-super-key-map
670:
671: fi::shell-directory-stack
672: fi::last-input-start
673: fi::last-input-end
674: fi::input-ring
675: fi::input-ring-max
676: fi::input-ring-yank-pointer
677: fi::last-input-search-string))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.