aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuri Linkov2009-11-23 20:30:33 +0000
committerJuri Linkov2009-11-23 20:30:33 +0000
commit0d62bcea27b6e413bfa3ad14b96f289bb65fcc5e (patch)
treef1b6ddd3fdb7287d7bd9fe8f206785250606735a
parentb593f1055a64feec5ee98d6c850c705435136840 (diff)
downloademacs-0d62bcea27b6e413bfa3ad14b96f289bb65fcc5e.tar.gz
emacs-0d62bcea27b6e413bfa3ad14b96f289bb65fcc5e.zip
Implement Isearch in comint input history. (Bug#3746)
* comint.el (comint-mode): Add `comint-history-isearch-setup' to `isearch-mode-hook'. (comint-history-isearch): New defcustom. (comint-history-isearch-backward) (comint-history-isearch-backward-regexp): New commands. (comint-history-isearch-message-overlay): New buffer-local variable. (comint-history-isearch-setup, comint-history-isearch-end) (comint-goto-input, comint-history-isearch-search) (comint-history-isearch-message, comint-history-isearch-wrap) (comint-history-isearch-push-state) (comint-history-isearch-pop-state): New functions.
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/ChangeLog15
-rw-r--r--lisp/comint.el196
3 files changed, 216 insertions, 0 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 543d6612578..27f3b9868d8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -281,6 +281,11 @@ the command asynchronously without the need to manually add ampersand to
281the end of the command. Its output appears in the buffer `*Async Shell 281the end of the command. Its output appears in the buffer `*Async Shell
282Command*'. 282Command*'.
283 283
284*** Isearch searches in the comint/shell input history when the new variable
285`comint-history-isearch' is non-nil. New commands `comint-history-isearch-backward'
286and `comint-history-isearch-backward-regexp' start Isearch in the input history
287regardless of the value of `comint-history-isearch'.
288
284+++ 289+++
285*** Autorevert Tail mode now works now for remote files. 290*** Autorevert Tail mode now works now for remote files.
286 291
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 70748be6673..96573b7508e 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,18 @@
12009-11-23 Juri Linkov <juri@jurta.org>
2
3 Implement Isearch in comint input history. (Bug#3746)
4 * comint.el (comint-mode): Add `comint-history-isearch-setup' to
5 `isearch-mode-hook'.
6 (comint-history-isearch): New defcustom.
7 (comint-history-isearch-backward)
8 (comint-history-isearch-backward-regexp): New commands.
9 (comint-history-isearch-message-overlay): New buffer-local variable.
10 (comint-history-isearch-setup, comint-history-isearch-end)
11 (comint-goto-input, comint-history-isearch-search)
12 (comint-history-isearch-message, comint-history-isearch-wrap)
13 (comint-history-isearch-push-state)
14 (comint-history-isearch-pop-state): New functions.
15
12009-11-23 Michael Albinus <michael.albinus@gmx.de> 162009-11-23 Michael Albinus <michael.albinus@gmx.de>
2 17
3 * net/tramp.el (tramp-shell-prompt-pattern): Use \r for carriage 18 * net/tramp.el (tramp-shell-prompt-pattern): Use \r for carriage
diff --git a/lisp/comint.el b/lisp/comint.el
index 37fddc5404e..c2db9c13a70 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -310,6 +310,7 @@ the function `comint-truncate-buffer' is on `comint-output-filter-functions'."
310 :type 'integer 310 :type 'integer
311 :group 'comint) 311 :group 'comint)
312 312
313;; FIXME: this should be defcustom
313(defvar comint-input-ring-size 150 314(defvar comint-input-ring-size 150
314 "Size of input history ring.") 315 "Size of input history ring.")
315 316
@@ -446,6 +447,8 @@ executed once when the buffer is created."
446 (define-key map [C-up] 'comint-previous-input) 447 (define-key map [C-up] 'comint-previous-input)
447 (define-key map [C-down] 'comint-next-input) 448 (define-key map [C-down] 'comint-next-input)
448 (define-key map "\er" 'comint-previous-matching-input) 449 (define-key map "\er" 'comint-previous-matching-input)
450 ;; FIXME: maybe M-r better to be bound to Isearch comint history?
451 ;; (define-key map "\er" 'comint-history-isearch-backward-regexp)
449 (define-key map "\es" 'comint-next-matching-input) 452 (define-key map "\es" 'comint-next-matching-input)
450 (define-key map [?\C-c ?\M-r] 'comint-previous-matching-input-from-input) 453 (define-key map [?\C-c ?\M-r] 'comint-previous-matching-input-from-input)
451 (define-key map [?\C-c ?\M-s] 'comint-next-matching-input-from-input) 454 (define-key map [?\C-c ?\M-s] 'comint-next-matching-input-from-input)
@@ -668,6 +671,7 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
668 (make-local-variable 'font-lock-defaults) 671 (make-local-variable 'font-lock-defaults)
669 (setq font-lock-defaults '(nil t)) 672 (setq font-lock-defaults '(nil t))
670 (add-hook 'change-major-mode-hook 'font-lock-defontify nil t) 673 (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
674 (add-hook 'isearch-mode-hook 'comint-history-isearch-setup nil t)
671 ;; This behavior is not useful in comint buffers, and is annoying 675 ;; This behavior is not useful in comint buffers, and is annoying
672 (set (make-local-variable 'next-line-add-newlines) nil)) 676 (set (make-local-variable 'next-line-add-newlines) nil))
673 677
@@ -1326,6 +1330,198 @@ A useful command to bind to SPC. See `comint-replace-by-expanded-history'."
1326 (comint-replace-by-expanded-history) 1330 (comint-replace-by-expanded-history)
1327 (self-insert-command arg)) 1331 (self-insert-command arg))
1328 1332
1333;; Isearch in comint input history
1334
1335(defcustom comint-history-isearch nil
1336 "Non-nil to Isearch in input history only, not in comint buffer output.
1337If t, usual Isearch keys like `C-r' and `C-M-r' in comint mode search
1338in the input history.
1339If `dwim', Isearch keys search in the input history only when initial
1340point position is at the comint command line. When starting Isearch
1341from other parts of the comint buffer, they search in the comint buffer.
1342If nil, Isearch operates on the whole comint buffer."
1343 :type '(choice (const :tag "Don't search in input history" nil)
1344 (const :tag "When point is on command line initially, search history" dwim)
1345 (const :tag "Always search in input history" t))
1346 :group 'comint
1347 :version "23.2")
1348
1349(defun comint-history-isearch-backward ()
1350 "Search for a string backward in input history using Isearch."
1351 (interactive)
1352 (let ((comint-history-isearch t))
1353 (isearch-backward)))
1354
1355(defun comint-history-isearch-backward-regexp ()
1356 "Search for a regular expression backward in input history using Isearch."
1357 (interactive)
1358 (let ((comint-history-isearch t))
1359 (isearch-backward-regexp)))
1360
1361(defvar comint-history-isearch-message-overlay nil)
1362(make-variable-buffer-local 'comint-history-isearch-message-overlay)
1363
1364(defun comint-history-isearch-setup ()
1365 "Set up a comint for using Isearch to search the input history.
1366Intended to be added to `isearch-mode-hook' in `comint-mode'."
1367 (when (or (eq comint-history-isearch t)
1368 (and (eq comint-history-isearch 'dwim)
1369 ;; Point is at command line.
1370 (comint-after-pmark-p)))
1371 (setq isearch-message-prefix-add "history ")
1372 (set (make-local-variable 'isearch-search-fun-function)
1373 'comint-history-isearch-search)
1374 (set (make-local-variable 'isearch-message-function)
1375 'comint-history-isearch-message)
1376 (set (make-local-variable 'isearch-wrap-function)
1377 'comint-history-isearch-wrap)
1378 (set (make-local-variable 'isearch-push-state-function)
1379 'comint-history-isearch-push-state)
1380 (add-hook 'isearch-mode-end-hook 'comint-history-isearch-end nil t)))
1381
1382(defun comint-history-isearch-end ()
1383 "Clean up the comint after terminating Isearch in comint."
1384 (if comint-history-isearch-message-overlay
1385 (delete-overlay comint-history-isearch-message-overlay))
1386 (setq isearch-message-prefix-add nil)
1387 (setq isearch-search-fun-function nil)
1388 (setq isearch-message-function nil)
1389 (setq isearch-wrap-function nil)
1390 (setq isearch-push-state-function nil)
1391 (remove-hook 'isearch-mode-end-hook 'comint-history-isearch-end t))
1392
1393(defun comint-goto-input (pos)
1394 "Put input history item of the absolute history position POS."
1395 ;; If leaving the edit line, save partial unfinished input.
1396 (if (null comint-input-ring-index)
1397 (setq comint-stored-incomplete-input
1398 (funcall comint-get-old-input)))
1399 (setq comint-input-ring-index pos)
1400 (comint-delete-input)
1401 (if (and pos (not (ring-empty-p comint-input-ring)))
1402 (insert (ring-ref comint-input-ring pos))
1403 ;; Restore partial unfinished input.
1404 (when (> (length comint-stored-incomplete-input) 0)
1405 (insert comint-stored-incomplete-input))))
1406
1407(defun comint-history-isearch-search ()
1408 "Return the proper search function, for Isearch in input history."
1409 (cond
1410 (isearch-word
1411 (if isearch-forward 'word-search-forward 'word-search-backward))
1412 (t
1413 (lambda (string bound noerror)
1414 (let ((search-fun
1415 ;; Use standard functions to search within comint text
1416 (cond
1417 (isearch-regexp
1418 (if isearch-forward 're-search-forward 're-search-backward))
1419 (t
1420 (if isearch-forward 'search-forward 'search-backward))))
1421 found)
1422 ;; Avoid lazy-highlighting matches in the comint prompt when
1423 ;; searching forward. Lazy-highlight calls this lambda with the
1424 ;; bound arg, so skip the comint prompt.
1425 (if (and bound isearch-forward (< (point) (comint-line-beginning-position)))
1426 (goto-char (comint-line-beginning-position)))
1427 (or
1428 ;; 1. First try searching in the initial comint text
1429 (funcall search-fun string
1430 (if isearch-forward bound (comint-line-beginning-position))
1431 noerror)
1432 ;; 2. If the above search fails, start putting next/prev history
1433 ;; elements in the comint successively, and search the string
1434 ;; in them. Do this only when bound is nil (i.e. not while
1435 ;; lazy-highlighting search strings in the current comint text).
1436 (unless bound
1437 (condition-case nil
1438 (progn
1439 (while (not found)
1440 (cond (isearch-forward
1441 ;; Signal an error here explicitly, because
1442 ;; `comint-next-input' doesn't signal an error.
1443 (when (null comint-input-ring-index)
1444 (error "End of history; no next item"))
1445 (comint-next-input 1)
1446 (goto-char (comint-line-beginning-position)))
1447 (t
1448 ;; Signal an error here explicitly, because
1449 ;; `comint-previous-input' doesn't signal an error.
1450 (when (eq comint-input-ring-index
1451 (1- (ring-length comint-input-ring)))
1452 (error "Beginning of history; no preceding item"))
1453 (comint-previous-input 1)
1454 (goto-char (point-max))))
1455 (setq isearch-barrier (point) isearch-opoint (point))
1456 ;; After putting the next/prev history element, search
1457 ;; the string in them again, until comint-next-input
1458 ;; or comint-previous-input raises an error at the
1459 ;; beginning/end of history.
1460 (setq found (funcall search-fun string
1461 (unless isearch-forward
1462 ;; For backward search, don't search
1463 ;; in the comint prompt
1464 (comint-line-beginning-position))
1465 noerror)))
1466 ;; Return point of the new search result
1467 (point))
1468 ;; Return nil on the error "no next/preceding item"
1469 (error nil)))))))))
1470
1471(defun comint-history-isearch-message (&optional c-q-hack ellipsis)
1472 "Display the input history search prompt.
1473If there are no search errors, this function displays an overlay with
1474the Isearch prompt which replaces the original comint prompt.
1475Otherwise, it displays the standard Isearch message returned from
1476`isearch-message'."
1477 (if (not (and isearch-success (not isearch-error)))
1478 ;; Use standard function `isearch-message' when not in comint prompt,
1479 ;; or search fails, or has an error (like incomplete regexp).
1480 ;; This function displays isearch message in the echo area,
1481 ;; so it's possible to see what is wrong in the search string.
1482 (isearch-message c-q-hack ellipsis)
1483 ;; Otherwise, put the overlay with the standard isearch prompt over
1484 ;; the initial comint prompt.
1485 (if (overlayp comint-history-isearch-message-overlay)
1486 (move-overlay comint-history-isearch-message-overlay
1487 (save-excursion (forward-line 0) (point))
1488 (comint-line-beginning-position))
1489 (setq comint-history-isearch-message-overlay
1490 (make-overlay (save-excursion (forward-line 0) (point))
1491 (comint-line-beginning-position)))
1492 (overlay-put comint-history-isearch-message-overlay 'evaporate t))
1493 (overlay-put comint-history-isearch-message-overlay
1494 'display (isearch-message-prefix c-q-hack ellipsis))
1495 ;; And clear any previous isearch message.
1496 (message "")))
1497
1498(defun comint-history-isearch-wrap ()
1499 "Wrap the input history search when search fails.
1500Move point to the first history element for a forward search,
1501or to the last history element for a backward search."
1502 (unless isearch-word
1503 ;; When `comint-history-isearch-search' fails on reaching the
1504 ;; beginning/end of the history, wrap the search to the first/last
1505 ;; input history element.
1506 (if isearch-forward
1507 (comint-goto-input (1- (ring-length comint-input-ring)))
1508 (comint-goto-input nil))
1509 (setq isearch-success t))
1510 (goto-char (if isearch-forward (comint-line-beginning-position) (point-max))))
1511
1512(defun comint-history-isearch-push-state ()
1513 "Save a function restoring the state of input history search.
1514Save `comint-input-ring-index' to the additional state parameter
1515in the search status stack."
1516 `(lambda (cmd)
1517 (comint-history-isearch-pop-state cmd ,comint-input-ring-index)))
1518
1519(defun comint-history-isearch-pop-state (cmd hist-pos)
1520 "Restore the input history search state.
1521Go to the history element by the absolute history position HIST-POS."
1522 (comint-goto-input hist-pos))
1523
1524
1329(defun comint-within-quotes (beg end) 1525(defun comint-within-quotes (beg end)
1330 "Return t if the number of quotes between BEG and END is odd. 1526 "Return t if the number of quotes between BEG and END is odd.
1331Quotes are single and double." 1527Quotes are single and double."