Skip to content

Instantly share code, notes, and snippets.

Created Oct 5, 2010
What would you like to do?
;I added the component:
; (inferior-ess-search-list-command . "search()\n")
;to S+3-customize-alist and R-customize-alist, and then I redefined the
;ess-create-temp-buffer function as follows:
(defun ess-create-temp-buffer (name)
"Create an empty buffer called NAME."
(let ((buff (get-buffer-create name))
(elca (eval ess-local-customize-alist)))
(set-buffer buff)
(ess-setq-vars-local elca buff))
;;These two steps seem to insure that the temporary buffer in which the
;;search results appear has the correct version of the local variables.
;;I am not that well acquainted with the ess code and don't know whether
;;this is a good fundamental way of fixing the problem, or even whether
;;or not this breaks some other feature of ess-mode that I never use.
;;Thanks for listening.
;;Ed K.
;;Ed Kademan 508.651.3700
;;PHZ Capital Partners 508.653.1745 (fax)
;;321 Commonwealth Road <>
;;Wayland, MA 01778
(defun ess-display-temp-buffer (buff)
"Display the buffer BUFF using `temp-buffer-show-function' and respecting
(let ((display-buffer-reuse-frames ess-display-buffer-reuse-frames))
(funcall (or temp-buffer-show-function 'display-buffer) buff)))
;;*;; Error messages
(defun ess-error (msg)
"Something bad has happened.
Display the S buffer, and cause an error displaying MSG."
(display-buffer (process-buffer (get-ess-process ess-current-process-name)))
(error msg))
; Provide package
(provide 'ess-inf)
; Local variables section
;;; This file is automatically placed in Outline minor mode.
;;; The file is structured as follows:
;;; Chapters: ^L ;
;;; Sections: ;;*;;
;;; Subsections: ;;;*;;;
;;; Components: defuns, defvars, defconsts
;;; Random code beginning with a ;;;;* comment
;;; Local variables:
;;; mode: emacs-lisp
;;; outline-minor-mode: nil
;;; mode: outline-minor
;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
;;; End:
;;; ess-inf.el ends here
;;; linefeeder.el --- send input to subprocesses in a comint buffer line by line
;; Copyright (C) 2010 Lars Schmidt-Thieme <>
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Commentary:
;; Provides an extension to comint mode that sends input to the process
;; line by line (instead of everything at once). This has two benefits:
;; 1. output is immediately below the corresponding input in the
;; comint buffer,
;; 2. the process can be interrupted by calling `comint-interrupt-subjob'
;; even if there is a lot of input still pending.
;; Enable by call `linefeeder-enable' in the comint buffer.
;; To send some input to the process from outside the comint buffer,
;; call `linefeeder-send-string' (with the comint buffer as the current
;; buffer).
;; Linefeeder requires that the program running in the process issues
;; prompts after each line of input, as e.g., done by R.
;;; Code:
(require 'comint)
(defvar linefeeder-pending-input-buffer nil
" Buffer containing the pending input.")
(defvar linefeeder-still-processing-input nil
" t if linefeeder still is processing input, i.e.,
if there is no new prompt since sending last line.")
(defvar linefeeder-stored-incomplete-input
" Contains incomplete input by the user before sending linewise input started.")
(defun linefeeder-enable () (interactive)
" Setup comint mode to send input to the process line by line."
;; a. make variables local
(make-local-variable 'linefeeder-pending-input-buffer)
(make-local-variable 'linefeeder-still-processing-input)
(make-local-variable 'linefeeder-stored-incomplete-input)
(make-local-variable 'comint-pre-interrupt-hooks)
(make-local-variable 'comint-post-interrupt-hooks)
;; b. setup local variables: output filter loop.
(setq linefeeder-pending-input-buffer (generate-new-buffer (generate-new-buffer-name "*pending output*")))
(setq linefeeder-still-processing-input nil)
(setq linefeeder-stored-incomplete-input nil)
(add-hook 'comint-output-filter-functions 'linefeeder-prompt-detector)
;; c. setup hooks for comint-interrupt-subjob
(add-hook 'comint-pre-interrupt-hooks 'linefeeder-delete-pending-input)
(add-hook 'comint-post-interrupt-hooks 'linefeeder-next-line)
(defun linefeeder-send-string (string)
" Send a string to the input of the process (line by line)"
;; a. store all unsent user input
(setq linefeeder-stored-incomplete-input
(or (marker-position comint-accum-marker)
(process-mark (get-buffer-process (current-buffer))))
;; b. append string to pending input buffer
(with-current-buffer linefeeder-pending-input-buffer
(insert string))
;; c. and start to process pending input
;; evtl. send next line of input
(defun linefeeder-evtl-send-next-input-line ()
;; if the process is not already processing input and if there is still pending input
(if (not linefeeder-still-processing-input)
(if (> (buffer-size linefeeder-pending-input-buffer) 0)
;; a. let everybody know that the process will process input shortly
(setq linefeeder-still-processing-input t)
;; b. get next line from pending input:
(with-current-buffer linefeeder-pending-input-buffer
(goto-char (point-min))
(move-end-of-line 1)
(setq line (delete-and-extract-region 1 (point)))
(if (< (point) (point-max))
(delete-char 1))
;; c. insert next input line into process buffer and send it
;; (comint-send-string sprocess line)
(insert line)
;; in the end: evtl. restore initially removed unsent user input.
(if (> (length linefeeder-stored-incomplete-input) 0)
(goto-char (process-mark (get-buffer-process (current-buffer))))
(insert linefeeder-stored-incomplete-input)
(setq linefeeder-stored-incomplete-input nil)))
(defun linefeeder-delete-pending-input () (interactive)
" Delete all pending input."
(with-current-buffer linefeeder-pending-input-buffer
;; signal that a line of input has been processed and goto next line."
(defun linefeeder-next-line ()
(setq linefeeder-still-processing-input nil)
;; output filter that detects prompts:
(defun linefeeder-prompt-detector (string)
(if (string-match comint-prompt-regexp string)
(defun linefeeder-interrupt-subjob () (interactive)
" Interrupt process and discard all pending input."
;; ----------------------------------------------------------------------
;; added a hook to comint-interrupt-subjob
(defvar comint-pre-interrupt-hooks nil
"Functions to call before subjob is interrupted.
These functions get no arguments.
You can use `add-hook' to add functions to this list
either globally or locally.")
(defvar comint-post-interrupt-hooks nil
"Functions to call after subjob has been interrupted.
These functions get no arguments.
You can use `add-hook' to add functions to this list
either globally or locally.")
(defun comint-interrupt-subjob ()
"Interrupt the current subjob.
This command also kills the pending input
between the process mark and point.
It runs `comint-pre-interrupt-hooks' before the interruption and
`comint-post-interrupt-hooks' after the interruption."
(run-hook-with-args 'comint-pre-interrupt-hooks)
(interrupt-process nil comint-ptyp)
(run-hook-with-args 'comint-post-interrupt-hooks)
;; (process-send-string nil "\n")
(provide 'linefeeder)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment