aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Moellmann1999-11-23 10:20:07 +0000
committerGerd Moellmann1999-11-23 10:20:07 +0000
commit3965beb02c94dd1c91b61b05af9b44eea892e364 (patch)
tree369ddae0ce6edf2a677757a187e857d8fc1051d4
parentbc165bcee0fb371ff0fa86ddc64f0653da1c4bdf (diff)
downloademacs-3965beb02c94dd1c91b61b05af9b44eea892e364.tar.gz
emacs-3965beb02c94dd1c91b61b05af9b44eea892e364.zip
Add redirection.from active comint buffers into
another buffer. Written by Peter Breton.
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/comint.el346
2 files changed, 355 insertions, 4 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index d561c9a2f9f..7528e6b3224 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,19 +1,24 @@
11999-11-23 Gerd Moellmann <gerd@gnu.org>
2
3 * comint.el: Add redirection.from active comint buffers into
4 another buffer. Written by Peter Breton.
5
11999-11-23 Stefan Monnier <monnier@cs.yale.edu> 61999-11-23 Stefan Monnier <monnier@cs.yale.edu>
2 7
3 * emacs-lisp/autoload.el (make-autoload): Recognize the new 8 * emacs-lisp/autoload.el (make-autoload): Recognize the new
4 `define-minor-mode'. 9 `define-minor-mode'.
5 (define-minor-mode): Specify `doc-string-elt'. 10 (define-minor-mode): Specify `doc-string-elt'.
6 11
7 * emacs-lisp/easy-mmode.el: Changed maintainer. 12 * emacs-lisp/easy-mmode.el: Changed maintainer.
8 (easy-mmode-define-toggle): New BODY arg; Never append `-mode'; 13 (easy-mmode-define-toggle): New BODY arg; Never append `-mode';
9 Use defcustom for the hooks; Improve the auto-generated docstrings. 14 Use defcustom for the hooks; Improve the auto-generated docstrings.
10 (easy-mmode-define-minor-mode): Renamed `define-minor-mode'. 15 (easy-mmode-define-minor-mode): Renamed `define-minor-mode'.
11 (define-minor-mode): Add BODY arg; Only declare the keymap if 16 (define-minor-mode): Add BODY arg; Only declare the keymap if
12 provided; Improve the auto-generated docstrings. 17 provided; Improve the auto-generated docstrings.
13 18
141999-11-22 Gerd Moellmann <gerd@gnu.org> 191999-11-22 Gerd Moellmann <gerd@gnu.org>
15 20
16 * textmodes/text-mode.el (text-mode): Contruct paragraph-start so 21 * textmodes/text-mode.el (text-mode): Construct paragraph-start so
17 that the leading `^' is at the start. This is necessary because 22 that the leading `^' is at the start. This is necessary because
18 paragraphs.el tries to remove anchors, but can find them only if 23 paragraphs.el tries to remove anchors, but can find them only if
19 they are the first character. 24 they are the first character.
diff --git a/lisp/comint.el b/lisp/comint.el
index 48c60003b7d..c48182b0988 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -2372,6 +2372,352 @@ the process mark is at the beginning of the accumulated input."
2372 (message "Process mark set"))) 2372 (message "Process mark set")))
2373 2373
2374 2374
2375;; Author: Peter Breton <pbreton@ne.mediaone.net>
2376
2377;; This little add-on for comint is intended to make it easy to get
2378;; output from currently active comint buffers into another buffer,
2379;; or buffers, and then go back to using the comint shell.
2380;;
2381;; My particular use is SQL interpreters; I want to be able to execute a
2382;; query using the process associated with a comint-buffer, and save that
2383;; somewhere else. Because the process might have state (for example, it
2384;; could be in an uncommitted transaction), just running starting a new
2385;; process and having it execute the query and then finish, would not
2386;; work. I'm sure there are other uses as well, although in many cases
2387;; starting a new process is the simpler, and thus preferable, approach.
2388;;
2389;; The basic implementation is as follows: comint-redirect changes the
2390;; preoutput filter functions (comint-preoutput-filter-functions) to use
2391;; its own filter. The filter puts the output into the designated buffer,
2392;; or buffers, until it sees a regexp that tells it to stop (by default,
2393;; this is the prompt for the interpreter, comint-prompt-regexp). When it
2394;; sees the stop regexp, it restores the old filter functions, and runs
2395;; comint-redirect-hook.
2396;;
2397;; Each comint buffer may only use one redirection at a time, but any number
2398;; of different comint buffers may be simultaneously redirected.
2399;;
2400;; NOTE: It is EXTREMELY important that `comint-prompt-regexp' be set to the
2401;; correct prompt for your interpreter, or that you supply a regexp that says
2402;; when the redirection is finished. Otherwise, redirection will continue
2403;; indefinitely. The code now does a sanity check to ensure that it can find
2404;; a prompt in the comint buffer; however, it is still important to ensure that
2405;; this prompt is set correctly.
2406;;
2407
2408;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2409;; Variables
2410;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2411
2412(defcustom comint-redirect-verbose nil
2413 "*If non-nil, print messages each time the redirection filter is invoked.
2414Also print a message when redirection is completed."
2415 :group 'comint
2416 :type 'boolean)
2417
2418;; Directly analagous to comint-preoutput-filter-functions
2419(defvar comint-redirect-filter-functions nil
2420 "List of functions to call before inserting redirected process output.
2421Each function gets one argument, a string containing the text received
2422from the subprocess. It should return the string to insert, perhaps
2423the same string that was received, or perhaps a modified or transformed
2424string.
2425
2426The functions on the list are called sequentially, and each one is given
2427the string returned by the previous one. The string returned by the
2428last function is the text that is actually inserted in the redirection buffer.")
2429
2430(make-variable-buffer-local 'comint-redirect-filter-functions)
2431
2432;; Internal variables
2433
2434(defvar comint-redirect-output-buffer nil
2435 "The buffer or list of buffers to put output into.")
2436
2437(defvar comint-redirect-finished-regexp nil
2438 "Regular expression that determines when to stop redirection in Comint.
2439When the redirection filter function is given output that matches this regexp,
2440the output is inserted as usual, and redirection is completed.")
2441
2442(defvar comint-redirect-insert-matching-regexp nil
2443 "If non-nil, the text that ends a redirection is included in it.
2444More precisely, the text that matches `comint-redirect-finished-regexp'
2445and therefore terminates an output redirection is inserted in the
2446redirection target buffer, along with the preceding output.")
2447
2448(defvar comint-redirect-echo-input nil
2449 "Non-nil means echo input in the process buffer even during redirection.")
2450
2451(defvar comint-redirect-completed nil
2452 "Non-nil if redirection has completed in the current buffer.")
2453
2454(defvar comint-redirect-original-mode-line-process nil
2455 "Original mode line for redirected process.")
2456
2457(defvar comint-redirect-perform-sanity-check t
2458 "If non-nil, check that redirection is likely to complete successfully.
2459More precisely, before starting a redirection, verify that the
2460regular expression `comint-redirect-finished-regexp' that controls
2461when to terminate it actually matches some text already in the process
2462buffer. The idea is that this regular expression should match a prompt
2463string, and that there ought to be at least one copy of your prompt string
2464in the process buffer already.")
2465
2466(defvar comint-redirect-original-filter-function nil
2467 "The process filter that was in place when redirection is started.
2468When redirection is completed, the process filter is restored to
2469this value.")
2470
2471;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2472;; Functions
2473;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2474
2475(defun comint-redirect-setup (output-buffer
2476 comint-buffer
2477 finished-regexp
2478 &optional echo-input)
2479 "Set up for output redirection.
2480This function sets local variables that are used by `comint-redirect-filter'
2481to perform redirection.
2482
2483Output from COMINT-BUFFER is redirected to OUTPUT-BUFFER, until something
2484in the output matches FINISHED-REGEXP.
2485
2486If optional argument ECHO-INPUT is non-nil, output is echoed to the
2487original comint buffer.
2488
2489This function is called by `comint-redirect-send-command-to-process',
2490and does not normally need to be invoked by the end user or programmer."
2491 (with-current-buffer comint-buffer
2492
2493 (make-local-variable 'comint-redirect-original-mode-line-process)
2494 (setq comint-redirect-original-mode-line-process mode-line-process)
2495
2496 (make-local-variable 'comint-redirect-output-buffer)
2497 (setq comint-redirect-output-buffer output-buffer)
2498
2499 (make-local-variable 'comint-redirect-finished-regexp)
2500 (setq comint-redirect-finished-regexp finished-regexp)
2501
2502 (make-local-variable 'comint-redirect-echo-input)
2503 (setq comint-redirect-echo-input echo-input)
2504
2505 (make-local-variable 'comint-redirect-completed)
2506 (setq comint-redirect-completed nil)
2507
2508 (setq mode-line-process
2509 (if mode-line-process
2510 (list (concat (elt mode-line-process 0) " Redirection"))
2511 (list ":%s Redirection")))))
2512
2513(defun comint-redirect-cleanup ()
2514 "End a Comint redirection. See `comint-redirect-send-command'."
2515 (interactive)
2516 ;; Restore the process filter
2517 (set-process-filter (get-buffer-process (current-buffer))
2518 comint-redirect-original-filter-function)
2519 ;; Restore the mode line
2520 (setq mode-line-process comint-redirect-original-mode-line-process)
2521 ;; Set the completed flag
2522 (setq comint-redirect-completed t))
2523
2524;; Because the cleanup happens as a callback, it's not easy to guarantee
2525;; that it really occurs.
2526(defalias 'comint-redirect-remove-redirection 'comint-redirect-cleanup)
2527
2528(defun comint-redirect-filter (process input-string)
2529 "Filter function which redirects output from PROCESS to a buffer or buffers.
2530The variable `comint-redirect-output-buffer' says which buffer(s) to
2531place output in.
2532
2533INPUT-STRING is the input from the comint process.
2534
2535This function runs as a process filter, and does not need to be invoked by the
2536end user."
2537 (and process
2538 (with-current-buffer (process-buffer process)
2539 (comint-redirect-preoutput-filter input-string)
2540 ;; If we have to echo output, give it to the original filter function
2541 (and comint-redirect-echo-input
2542 comint-redirect-original-filter-function
2543 (funcall comint-redirect-original-filter-function
2544 process input-string)))))
2545
2546
2547(defun comint-redirect-preoutput-filter (input-string)
2548 "Comint filter function which redirects comint output to a buffer or buffers.
2549The variable `comint-redirect-output-buffer' says which buffer(s) to
2550place output in.
2551
2552INPUT-STRING is the input from the comint process.
2553
2554This function does not need to be invoked by the end user."
2555 (let ((output-buffer-list
2556 (if (listp comint-redirect-output-buffer)
2557 comint-redirect-output-buffer
2558 (list comint-redirect-output-buffer)))
2559 (filtered-input-string input-string))
2560
2561 ;; If there are any filter functions, give them a chance to modify the string
2562 (let ((functions comint-redirect-filter-functions))
2563 (while (and functions filtered-input-string)
2564 (setq filtered-input-string
2565 (funcall (car functions) filtered-input-string))
2566 (setq functions (cdr functions))))
2567
2568 ;; Clobber `comint-redirect-finished-regexp'
2569 (or comint-redirect-insert-matching-regexp
2570 (and (string-match comint-redirect-finished-regexp filtered-input-string)
2571 (setq filtered-input-string
2572 (replace-match "" nil nil filtered-input-string))))
2573
2574 ;; Send output to all registered buffers
2575 (save-excursion
2576 (mapcar
2577 (function (lambda(buf)
2578 ;; Set this buffer to the output buffer
2579 (set-buffer (get-buffer-create buf))
2580 ;; Go to the end of the buffer
2581 (goto-char (point-max))
2582 ;; Insert the output
2583 (insert filtered-input-string)))
2584 output-buffer-list))
2585
2586 ;; Message
2587 (and comint-redirect-verbose
2588 (message "Redirected output to buffer(s) %s"
2589 (mapconcat 'identity output-buffer-list " ")))
2590
2591 ;; If we see the prompt, tidy up
2592 ;; We'll look for the prompt in the original string, so nobody can
2593 ;; clobber it
2594 (and (string-match comint-redirect-finished-regexp input-string)
2595 (progn
2596 (and comint-redirect-verbose
2597 (message "Redirection completed"))
2598 (comint-redirect-cleanup)
2599 (run-hooks 'comint-redirect-hook)))
2600 ;; Echo input?
2601 (if comint-redirect-echo-input
2602 filtered-input-string
2603 "")))
2604
2605;;;###autoload
2606(defun comint-redirect-send-command (command output-buffer echo &optional no-display)
2607 "Send COMMAND to process in current buffer, with output to OUTPUT-BUFFER.
2608With prefix arg, echo output in process buffer.
2609
2610If NO-DISPLAY is non-nil, do not show the output buffer."
2611 (interactive "sCommand: \nBOutput Buffer: \nP")
2612 (let ((process (get-buffer-process (current-buffer))))
2613 (if process
2614 (comint-redirect-send-command-to-process
2615 command output-buffer (current-buffer) echo no-display)
2616 (error "No process for current buffer"))))
2617
2618;;;###autoload
2619(defun comint-redirect-send-command-to-process
2620 (command output-buffer process echo &optional no-display)
2621 "Send COMMAND to PROCESS, with output to OUTPUT-BUFFER.
2622With prefix arg, echo output in process buffer.
2623
2624If NO-DISPLAY is non-nil, do not show the output buffer."
2625 (interactive "sCommand: \nBOutput Buffer: \nbProcess Buffer: \nP")
2626 (let* (;; The process buffer
2627 (process-buffer (if (processp process)
2628 (process-buffer process)
2629 process))
2630 (proc (get-buffer-process process-buffer)))
2631 ;; Change to the process buffer
2632 (set-buffer process-buffer)
2633
2634 ;; Make sure there's a prompt in the current process buffer
2635 (and comint-redirect-perform-sanity-check
2636 (save-excursion
2637 (goto-char (point-max))
2638 (or (re-search-backward comint-prompt-regexp nil t)
2639 (error "No prompt found or `comint-prompt-regexp' not set properly"))))
2640
2641 ;;;;;;;;;;;;;;;;;;;;;
2642 ;; Set up for redirection
2643 ;;;;;;;;;;;;;;;;;;;;;
2644 (comint-redirect-setup
2645 ;; Output Buffer
2646 output-buffer
2647 ;; Comint Buffer
2648 (current-buffer)
2649 ;; Finished Regexp
2650 comint-prompt-regexp
2651 ;; Echo input
2652 echo)
2653
2654 ;;;;;;;;;;;;;;;;;;;;;
2655 ;; Set the filter
2656 ;;;;;;;;;;;;;;;;;;;;;
2657 ;; Save the old filter
2658 (setq comint-redirect-original-filter-function
2659 (process-filter proc))
2660 (set-process-filter proc 'comint-redirect-filter)
2661
2662 ;;;;;;;;;;;;;;;;;;;;;
2663 ;; Send the command
2664 ;;;;;;;;;;;;;;;;;;;;;
2665 (process-send-string
2666 (current-buffer)
2667 (concat command "\n"))
2668
2669 ;;;;;;;;;;;;;;;;;;;;;
2670 ;; Show the output
2671 ;;;;;;;;;;;;;;;;;;;;;
2672 (or no-display
2673 (display-buffer
2674 (get-buffer-create
2675 (if (listp output-buffer)
2676 (car output-buffer)
2677 output-buffer))))))
2678
2679;;;###autoload
2680(defun comint-redirect-results-list (command regexp regexp-group)
2681 "Send COMMAND to current process.
2682Return a list of expressions in the output which match REGEXP.
2683REGEXP-GROUP is the regular expression group in REGEXP to use."
2684 (interactive)
2685 (comint-redirect-results-list-from-process
2686 (get-buffer-process (current-buffer))
2687 command regexp regexp-group))
2688
2689;;;###autoload
2690(defun comint-redirect-results-list-from-process (process command regexp regexp-group)
2691 "Send COMMAND to PROCESS.
2692Return a list of expressions in the output which match REGEXP.
2693REGEXP-GROUP is the regular expression group in REGEXP to use."
2694 (interactive)
2695 (let ((output-buffer " *Comint Redirect Work Buffer*")
2696 results)
2697 (save-excursion
2698 (set-buffer (get-buffer-create output-buffer))
2699 (erase-buffer)
2700 (comint-redirect-send-command-to-process command
2701 output-buffer process nil t)
2702 ;; Wait for the process to complete
2703 (set-buffer (process-buffer process))
2704 (while (null comint-redirect-completed)
2705 (accept-process-output nil 1))
2706 ;; Collect the output
2707 (set-buffer output-buffer)
2708 (goto-char (point-min))
2709 ;; Skip past the command, if it was echoed
2710 (and (looking-at command)
2711 (forward-line))
2712 (while (re-search-forward regexp nil t)
2713 (setq results
2714 (cons (buffer-substring-no-properties
2715 (match-beginning regexp-group)
2716 (match-end regexp-group))
2717 results)))
2718 results)))
2719
2720
2375;; Converting process modes to use comint mode 2721;; Converting process modes to use comint mode
2376;; =========================================================================== 2722;; ===========================================================================
2377;; The code in the Emacs 19 distribution has all been modified to use comint 2723;; The code in the Emacs 19 distribution has all been modified to use comint