+(defun comint-previous-matching-input-from-input (arg)
+ "Search backwards through input history for match for current input.
+\(Previous history elements are earlier commands.)
+With prefix argument N, search for Nth previous match.
+If N is negative, search forwards for the -Nth following match."
+ (interactive "p")
+ (if (not (memq last-command '(comint-previous-matching-input-from-input
+ comint-next-matching-input-from-input)))
+ ;; Starting a new search
+ (setq comint-matching-input-from-input-string
+ (buffer-substring
+ (process-mark (get-buffer-process (current-buffer)))
+ (point))
+ comint-input-ring-index nil))
+ (comint-previous-matching-input
+ (concat "^" (regexp-quote comint-matching-input-from-input-string))
+ arg))
+
+(defun comint-next-matching-input-from-input (arg)
+ "Search forwards through input history for match for current input.
+\(Following history elements are more recent commands.)
+With prefix argument N, search for Nth following match.
+If N is negative, search backwards for the -Nth previous match."
+ (interactive "p")
+ (comint-previous-matching-input-from-input (- arg)))
+
+
+(defun comint-replace-by-expanded-history (&optional silent)
+ "Expand input command history references before point.
+Expansion is dependent on the value of `comint-input-autoexpand'.
+
+This function depends on the buffer's idea of the input history, which may not
+match the command interpreter's idea, assuming it has one.
+
+Assumes history syntax is like typical Un*x shells'. However, since emacs
+cannot know the interpreter's idea of input line numbers, assuming it has one,
+it cannot expand absolute input line number references.
+
+If the optional argument SILENT is non-nil, never complain
+even if history reference seems erroneous.
+
+See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'.
+
+Returns t if successful."
+ (interactive)
+ (if (and comint-input-autoexpand
+ (string-match "[!^]" (funcall comint-get-old-input))
+ (save-excursion (beginning-of-line)
+ (looking-at comint-prompt-regexp)))
+ ;; Looks like there might be history references in the command.
+ (let ((previous-modified-tick (buffer-modified-tick)))
+ (message "Expanding history references...")
+ (comint-replace-by-expanded-history-before-point silent)
+ (/= previous-modified-tick (buffer-modified-tick)))))
+
+
+(defun comint-replace-by-expanded-history-before-point (silent)
+ "Expand directory stack reference before point.
+See `comint-replace-by-expanded-history'. Returns t if successful."
+ (save-excursion
+ (let ((toend (- (save-excursion (end-of-line nil) (point)) (point)))
+ (start (progn (comint-bol nil) (point))))
+ (while (progn
+ (skip-chars-forward "^!^"
+ (save-excursion
+ (end-of-line nil) (- (point) toend)))
+ (< (point)
+ (save-excursion
+ (end-of-line nil) (- (point) toend))))
+ ;; This seems a bit complex. We look for references such as !!, !-num,
+ ;; !foo, !?foo, !{bar}, !?{bar}, ^oh, ^my^, ^god^it, ^never^ends^.
+ ;; If that wasn't enough, the plings can be suffixed with argument
+ ;; range specifiers.
+ ;; Argument ranges are complex too, so we hive off the input line,
+ ;; referenced with plings, with the range string to `comint-args'.
+ (setq comint-input-ring-index nil)
+ (cond ((or (= (preceding-char) ?\\)
+ (comint-within-quotes start (point)))
+ ;; The history is quoted, or we're in quotes.
+ (goto-char (1+ (point))))
+ ((looking-at "![0-9]+\\($\\|[^-]\\)")
+ ;; We cannot know the interpreter's idea of input line numbers.
+ (goto-char (match-end 0))
+ (message "Absolute reference cannot be expanded"))
+ ((looking-at "!-\\([0-9]+\\)\\(:?[0-9^$*-]+\\)?")
+ ;; Just a number of args from `number' lines backward.
+ (let ((number (1- (string-to-number
+ (buffer-substring (match-beginning 1)
+ (match-end 1))))))
+ (if (<= number (ring-length comint-input-ring))
+ (progn
+ (replace-match
+ (comint-args (comint-previous-input-string number)
+ (match-beginning 2) (match-end 2))
+ t t)
+ (setq comint-input-ring-index number)
+ (message "History item: %d" (1+ number)))
+ (goto-char (match-end 0))
+ (message "Relative reference exceeds input history size"))))
+ ((or (looking-at "!!?:?\\([0-9^$*-]+\\)") (looking-at "!!"))
+ ;; Just a number of args from the previous input line.
+ (replace-match
+ (comint-args (comint-previous-input-string 0)
+ (match-beginning 1) (match-end 1))
+ t t)
+ (message "History item: previous"))
+ ((looking-at
+ "!\\??\\({\\(.+\\)}\\|\\(\\sw+\\)\\)\\(:?[0-9^$*-]+\\)?")
+ ;; Most recent input starting with or containing (possibly
+ ;; protected) string, maybe just a number of args. Phew.
+ (let* ((mb1 (match-beginning 1)) (me1 (match-end 1))
+ (mb2 (match-beginning 2)) (me2 (match-end 2))
+ (exp (buffer-substring (or mb2 mb1) (or me2 me1)))
+ (pref (if (save-match-data (looking-at "!\\?")) "" "^"))
+ (pos (save-match-data
+ (comint-previous-matching-input-string-position
+ (concat pref (regexp-quote exp)) 1))))
+ (if (null pos)
+ (progn
+ (goto-char (match-end 0))
+ (or silent
+ (progn (message "Not found")
+ (ding))))
+ (setq comint-input-ring-index pos)
+ (replace-match
+ (comint-args (ring-ref comint-input-ring pos)
+ (match-beginning 4) (match-end 4))
+ t t)
+ (message "History item: %d" (1+ pos)))))
+ ((looking-at "\\^\\([^^]+\\)\\^?\\([^^]*\\)\\^?")
+ ;; Quick substitution on the previous input line.
+ (let ((old (buffer-substring (match-beginning 1) (match-end 1)))
+ (new (buffer-substring (match-beginning 2) (match-end 2)))
+ (pos nil))
+ (replace-match (comint-previous-input-string 0) t t)
+ (setq pos (point))
+ (goto-char (match-beginning 0))
+ (if (not (search-forward old pos t))
+ (or silent
+ (error "Not found"))
+ (replace-match new t t)
+ (message "History item: substituted"))))
+ (t
+ (goto-char (match-end 0))))))))
+
+
+(defun comint-magic-space (arg)
+ "Expand input history references before point and insert ARG spaces.
+A useful command to bind to SPC. See `comint-replace-by-expanded-history'."
+ (interactive "p")
+ (comint-replace-by-expanded-history)
+ (self-insert-command arg))
+\f
+(defun comint-within-quotes (beg end)
+ "Return t if the number of quotes between BEG and END is odd.
+Quotes are single and double."
+ (let ((countsq (comint-how-many-region "\\(^\\|[^\\\\]\\)\'" beg end))
+ (countdq (comint-how-many-region "\\(^\\|[^\\\\]\\)\"" beg end)))
+ (or (= (mod countsq 2) 1) (= (mod countdq 2) 1))))
+
+(defun comint-how-many-region (regexp beg end)
+ "Return number of matches for REGEXP from BEG to END."
+ (let ((count 0))
+ (save-excursion
+ (save-match-data
+ (goto-char beg)
+ (while (re-search-forward regexp end t)
+ (setq count (1+ count)))))
+ count))
+
+(defun comint-args (string begin end)
+ ;; From STRING, return the args depending on the range specified in the text
+ ;; from BEGIN to END. If BEGIN is nil, assume all args. Ignore leading `:'.
+ ;; Range can be x-y, x-, -y, where x/y can be [0-9], *, ^, $.
+ (save-match-data
+ (if (null begin)
+ (comint-arguments string 0 nil)
+ (let* ((range (buffer-substring
+ (if (eq (char-after begin) ?:) (1+ begin) begin) end))
+ (nth (cond ((string-match "^[*^]" range) 1)
+ ((string-match "^-" range) 0)
+ ((string-equal range "$") nil)
+ (t (string-to-number range))))
+ (mth (cond ((string-match "[-*$]$" range) nil)
+ ((string-match "-" range)
+ (string-to-number (substring range (match-end 0))))
+ (t nth))))
+ (comint-arguments string nth mth)))))
+
+;; Return a list of arguments from ARG. Break it up at the
+;; delimiters in comint-delimiter-argument-list. Returned list is backwards.
+(defun comint-delim-arg (arg)
+ (if (null comint-delimiter-argument-list)
+ (list arg)
+ (let ((args nil)
+ (pos 0)
+ (len (length arg)))
+ (while (< pos len)
+ (let ((char (aref arg pos))
+ (start pos))
+ (if (memq char comint-delimiter-argument-list)
+ (while (and (< pos len) (eq (aref arg pos) char))
+ (setq pos (1+ pos)))
+ (while (and (< pos len)
+ (not (memq (aref arg pos)
+ comint-delimiter-argument-list)))
+ (setq pos (1+ pos))))
+ (setq args (cons (substring arg start pos) args))))
+ args)))
+
+(defun comint-arguments (string nth mth)
+ "Return from STRING the NTH to MTH arguments.
+NTH and/or MTH can be nil, which means the last argument.
+Returned arguments are separated by single spaces.
+We assume whitespace separates arguments, except within quotes.
+Also, a run of one or more of a single character
+in `comint-delimiter-argument-list' is a separate argument.
+Argument 0 is the command name."
+ (let ((argpart "[^ \n\t\"'`]+\\|\\(\"[^\"]*\"\\|'[^']*'\\|`[^`]*`\\)")
+ (args ()) (pos 0)
+ (count 0)
+ beg str value quotes)
+ ;; Build a list of all the args until we have as many as we want.
+ (while (and (or (null mth) (<= count mth))
+ (string-match argpart string pos))
+ (if (and beg (= pos (match-beginning 0)))
+ ;; It's contiguous, part of the same arg.
+ (setq pos (match-end 0)
+ quotes (or quotes (match-beginning 1)))
+ ;; It's a new separate arg.
+ (if beg
+ ;; Put the previous arg, if there was one, onto ARGS.
+ (setq str (substring string beg pos)
+ args (if quotes (cons str args)
+ (nconc (comint-delim-arg str) args))
+ count (1+ count)))
+ (setq quotes (match-beginning 1))
+ (setq beg (match-beginning 0))
+ (setq pos (match-end 0))))
+ (if beg
+ (setq str (substring string beg pos)
+ args (if quotes (cons str args)
+ (nconc (comint-delim-arg str) args))
+ count (1+ count)))
+ (let ((n (or nth (1- count)))
+ (m (if mth (1- (- count mth)) 0)))
+ (mapconcat
+ (function (lambda (a) a)) (nthcdr n (nreverse (nthcdr m args))) " "))))
+\f