+(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, find the next or Nth next 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.
+\(Previous history elements are earlier commands.)
+With prefix argument N, search for Nth previous match.
+If N is negative, find the next or Nth next match."
+ (interactive "p")
+ (comint-previous-matching-input-from-input (- arg)))
+
+
+(defun comint-replace-by-expanded-history ()
+ "Expand input command history references before point.
+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.
+
+See also `comint-magic-space'."
+ (interactive)
+ (save-excursion
+ (let ((toend (- (save-excursion (end-of-line nil) (point)) (point)))
+ (start (progn (comint-bol nil) (point))))
+ (while (re-search-forward
+ "[!^]" (save-excursion (end-of-line nil) (- (point) toend)) t)
+ ;; 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)
+ (goto-char (match-beginning 0))
+ (cond ((or (= (preceding-char) ?\\)
+ (comint-within-quotes start (point)))
+ ;; The history is quoted, or we're in quotes.
+ (goto-char (match-end 0)))
+ ((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))
+ ((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 (message "Not found")
+ (goto-char (match-end 0))
+ (ding))
+ (setq comint-input-ring-index pos)
+ (message "History item: %d" (1+ pos))
+ (replace-match
+ (comint-args (ring-ref comint-input-ring pos)
+ (match-beginning 4) (match-end 4))
+ t t))))
+ ((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 (search-forward old pos t)
+ (replace-match new t t)
+ (message "Not found")
+ (ding))))
+ (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)))))
+
+(defun comint-delim-arg (arg)
+ ;; Return a list of arguments from ARG. If there's a quote in there, just
+ ;; a list of the arg, otherwise try and break up using characters in
+ ;; comint-delimiter-argument-list. Returned list is backwards.
+ (if (or (null comint-delimiter-argument-list)
+ (string-match "[\"\'\`]" arg))
+ (list arg)
+ (let ((not-delim (format "[^%s]+" (mapconcat
+ (function (lambda (d) (regexp-quote d)))
+ comint-delimiter-argument-list "")))
+ (delim-str (mapconcat (function (lambda (d)
+ (concat (regexp-quote d) "+")))
+ comint-delimiter-argument-list "\\|"))
+ (args ()) (pos 0))
+ (while (or (eq pos (string-match not-delim arg pos))
+ (eq pos (string-match delim-str arg pos)))
+ (setq pos (match-end 0)
+ args (cons (substring arg (match-beginning 0) 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. Arguments are assumed to be
+delimited by whitespace. Strings comprising characters in the variable
+`comint-delimiter-argument-list' are treated as delimiters and arguments.
+Argument 0 is the command name."
+ (let ((arg "\\(\\S \\|\\(\"[^\"]*\"\\|\'[^\']*\'\\|\`[^\`]*\`\\)\\)+")
+ (args ()) (pos 0) (str nil))
+ ;; We build a list of all the args. Unnecessary, but more efficient, when
+ ;; ranges of args are required, than picking out one by one and recursing.
+ (while (string-match arg string pos)
+ (setq pos (match-end 0)
+ str (substring string (match-beginning 0) pos)
+ args (nconc (comint-delim-arg str) args)))
+ (let ((n (or nth (1- (length args))))
+ (m (if mth (1- (- (length args) mth)) 0)))
+ (mapconcat
+ (function (lambda (a) a)) (nthcdr n (nreverse (nthcdr m args))) " "))))
+\f