diff options
| author | Gerd Moellmann | 1999-11-23 10:20:07 +0000 |
|---|---|---|
| committer | Gerd Moellmann | 1999-11-23 10:20:07 +0000 |
| commit | 3965beb02c94dd1c91b61b05af9b44eea892e364 (patch) | |
| tree | 369ddae0ce6edf2a677757a187e857d8fc1051d4 | |
| parent | bc165bcee0fb371ff0fa86ddc64f0653da1c4bdf (diff) | |
| download | emacs-3965beb02c94dd1c91b61b05af9b44eea892e364.tar.gz emacs-3965beb02c94dd1c91b61b05af9b44eea892e364.zip | |
Add redirection.from active comint buffers into
another buffer. Written by Peter Breton.
| -rw-r--r-- | lisp/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/comint.el | 346 |
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 @@ | |||
| 1 | 1999-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 | |||
| 1 | 1999-11-23 Stefan Monnier <monnier@cs.yale.edu> | 6 | 1999-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 | ||
| 14 | 1999-11-22 Gerd Moellmann <gerd@gnu.org> | 19 | 1999-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. | ||
| 2414 | Also 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. | ||
| 2421 | Each function gets one argument, a string containing the text received | ||
| 2422 | from the subprocess. It should return the string to insert, perhaps | ||
| 2423 | the same string that was received, or perhaps a modified or transformed | ||
| 2424 | string. | ||
| 2425 | |||
| 2426 | The functions on the list are called sequentially, and each one is given | ||
| 2427 | the string returned by the previous one. The string returned by the | ||
| 2428 | last 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. | ||
| 2439 | When the redirection filter function is given output that matches this regexp, | ||
| 2440 | the 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. | ||
| 2444 | More precisely, the text that matches `comint-redirect-finished-regexp' | ||
| 2445 | and therefore terminates an output redirection is inserted in the | ||
| 2446 | redirection 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. | ||
| 2459 | More precisely, before starting a redirection, verify that the | ||
| 2460 | regular expression `comint-redirect-finished-regexp' that controls | ||
| 2461 | when to terminate it actually matches some text already in the process | ||
| 2462 | buffer. The idea is that this regular expression should match a prompt | ||
| 2463 | string, and that there ought to be at least one copy of your prompt string | ||
| 2464 | in 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. | ||
| 2468 | When redirection is completed, the process filter is restored to | ||
| 2469 | this 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. | ||
| 2480 | This function sets local variables that are used by `comint-redirect-filter' | ||
| 2481 | to perform redirection. | ||
| 2482 | |||
| 2483 | Output from COMINT-BUFFER is redirected to OUTPUT-BUFFER, until something | ||
| 2484 | in the output matches FINISHED-REGEXP. | ||
| 2485 | |||
| 2486 | If optional argument ECHO-INPUT is non-nil, output is echoed to the | ||
| 2487 | original comint buffer. | ||
| 2488 | |||
| 2489 | This function is called by `comint-redirect-send-command-to-process', | ||
| 2490 | and 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. | ||
| 2530 | The variable `comint-redirect-output-buffer' says which buffer(s) to | ||
| 2531 | place output in. | ||
| 2532 | |||
| 2533 | INPUT-STRING is the input from the comint process. | ||
| 2534 | |||
| 2535 | This function runs as a process filter, and does not need to be invoked by the | ||
| 2536 | end 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. | ||
| 2549 | The variable `comint-redirect-output-buffer' says which buffer(s) to | ||
| 2550 | place output in. | ||
| 2551 | |||
| 2552 | INPUT-STRING is the input from the comint process. | ||
| 2553 | |||
| 2554 | This 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. | ||
| 2608 | With prefix arg, echo output in process buffer. | ||
| 2609 | |||
| 2610 | If 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. | ||
| 2622 | With prefix arg, echo output in process buffer. | ||
| 2623 | |||
| 2624 | If 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. | ||
| 2682 | Return a list of expressions in the output which match REGEXP. | ||
| 2683 | REGEXP-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. | ||
| 2692 | Return a list of expressions in the output which match REGEXP. | ||
| 2693 | REGEXP-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 |