diff options
| author | Juri Linkov | 2009-11-23 20:30:33 +0000 |
|---|---|---|
| committer | Juri Linkov | 2009-11-23 20:30:33 +0000 |
| commit | 0d62bcea27b6e413bfa3ad14b96f289bb65fcc5e (patch) | |
| tree | f1b6ddd3fdb7287d7bd9fe8f206785250606735a | |
| parent | b593f1055a64feec5ee98d6c850c705435136840 (diff) | |
| download | emacs-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/NEWS | 5 | ||||
| -rw-r--r-- | lisp/ChangeLog | 15 | ||||
| -rw-r--r-- | lisp/comint.el | 196 |
3 files changed, 216 insertions, 0 deletions
| @@ -281,6 +281,11 @@ the command asynchronously without the need to manually add ampersand to | |||
| 281 | the end of the command. Its output appears in the buffer `*Async Shell | 281 | the end of the command. Its output appears in the buffer `*Async Shell |
| 282 | Command*'. | 282 | Command*'. |
| 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' | ||
| 286 | and `comint-history-isearch-backward-regexp' start Isearch in the input history | ||
| 287 | regardless 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 @@ | |||
| 1 | 2009-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 | |||
| 1 | 2009-11-23 Michael Albinus <michael.albinus@gmx.de> | 16 | 2009-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. | ||
| 1337 | If t, usual Isearch keys like `C-r' and `C-M-r' in comint mode search | ||
| 1338 | in the input history. | ||
| 1339 | If `dwim', Isearch keys search in the input history only when initial | ||
| 1340 | point position is at the comint command line. When starting Isearch | ||
| 1341 | from other parts of the comint buffer, they search in the comint buffer. | ||
| 1342 | If 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. | ||
| 1366 | Intended 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. | ||
| 1473 | If there are no search errors, this function displays an overlay with | ||
| 1474 | the Isearch prompt which replaces the original comint prompt. | ||
| 1475 | Otherwise, 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. | ||
| 1500 | Move point to the first history element for a forward search, | ||
| 1501 | or 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. | ||
| 1514 | Save `comint-input-ring-index' to the additional state parameter | ||
| 1515 | in 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. | ||
| 1521 | Go 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. |
| 1331 | Quotes are single and double." | 1527 | Quotes are single and double." |