ComintMode

What is Comint Mode?

Comint mode is a package that defines a general command-interpreter-in-a-buffer. The idea is that you can build specific process-in-a-buffer modes on top of comint mode – e.g., lisp, shell, scheme, T, soar, …. This way, all these specific packages share a common base functionality, and a common set of bindings, which makes them easier to use (and saves code, implementation time, etc., etc.).

Examples

Find examples of ComintModes.

Leveraging Comint

Since SqlMode is based on comint-mode, several aspects of SQLi buffers can be controlled by setting comint variables: automatically truncate buffers to a certain size, size of the input ring (history). You can either set these variables globally in your .emacs (in which case they will affect other modes such as shell-mode), or you can set these variables on a sql-interactive-mode-hook:

    (add-hook 'sql-interactive-mode-hook
              (function (lambda ()
                          (setq comint-output-filter-functions 'comint-truncate-buffer
                                comint-buffer-maximum-size 5000
                                comint-scroll-show-maximum-output t
                                comint-input-ring-size 500))))

Similar settings make sense for other ComintMode based code such as ShellMode.

Compilation inside an existing Comint buffer

Sometimes you’d like to run a compilation within an existing comint buffer instead of starting a new buffer like `M-x compile`. To send the default compile command to a comint buffer called *PowerShell* running a process called shell, you can use the following command:

(defun my-compile (&optional arg)
  "Switch to correct buffer, then compile."
  (interactive)
  (let ((b (get-buffer "*PowerShell*"))
        (p (get-process "shell")))
    (if (and b p)
        (with-current-buffer b
          (apply comint-input-sender (list p compile-command))))))

Clearing the buffer

Lots of times, the buffer just grows and grows, especially if you do a lot of commands in shell mode. If I’m doing interative work like looking through repeated find results, I clear the buffer constantly so C-a C-s will search through only what I care about.

  (defun cmg:shell-clear-region ()
    (interactive)
    (delete-region (point-min) (point-max))
    (comint-send-input))

Icicles Enhancements to Comint Mode

You can use Icicles completion in Comint mode. Whenever there are multiple completion candidates, Icicles completion is used (if Icicle minor mode is on). This means you can cycle to choose a candidate, complete using one or more substrings or regexps (progressive completion), and so on. See Icicles - Completion in Comint Modes.

You can also use `C-`’ to quickly find, reuse, and edit a previous shell input, matching it in several ways. See Icicles - Reuse Comint Inputs.

Handy functions for navigating history

Here’s a couple of functions that I find useful for comint buffers.

  (defun comint-jump-to-input-ring ()
    "Jump to the buffer containing the input history."
    (interactive)
    (progn
      (comint-dynamic-list-input-ring)
      (other-window 1)))
  (defun comint-goto-first-input nil
    "Move the command history back to the first input."
    (interactive)
    (if comint-input-ring-index
        (comint-previous-input (- comint-input-ring-index))))

You can bind them to keys by adding them to the comint-mode-hook like this:

  (add-hook 'comint-mode-hook
  	  (function (lambda ()
  		      (local-set-key (kbd "C-<f7>") 'comint-jump-to-input-ring)
  		      (local-set-key (kbd "C-<") 'comint-goto-first-input))))

JoeBloggs

Multiline History (Emacs 20)

If you are using Emacs 20, take a look at ComintPatched if you are interested in recovering multiline statements from the history.

Problems

If you find that the input prompt does not redisplay after output has been received try adding a function to ‘comint-output-filter-functions’ to pause a short while:

  (add-hook 'comint-output-filter-functions (lambda (arg) (sleep-for 0.05)) t)

It can be removed by evaluating the following form:

  (remove-hook 'comint-output-filter-functions (lambda (arg) (sleep-for 0.05)))

JoeBloggs