al-eshell.el 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. ;;; al-eshell.el --- Additional functionality for eshell
  2. ;; Copyright © 2013-2016 Alex Kost
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;;
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Code:
  16. (require 'em-dirs)
  17. (require 'em-unix)
  18. (require 'em-prompt)
  19. (defun al/eshell-kill-whole-line (arg)
  20. "Similar to `kill-whole-line', but respect eshell prompt."
  21. (interactive "p")
  22. (if (< (point) eshell-last-output-end)
  23. (kill-whole-line arg)
  24. (kill-region eshell-last-output-end
  25. (progn (forward-line arg) (point)))))
  26. ;;;###autoload
  27. (defun al/eshell-cd (arg)
  28. "Start eshell and change directory there to the current one.
  29. ARG has the same meaning as in `eshell'"
  30. (interactive "P")
  31. (let ((dir default-directory))
  32. (eshell arg)
  33. (eshell/cd dir)))
  34. (declare-function Info-find-node "info" t)
  35. (declare-function Info-menu "info" t)
  36. (defun al/eshell/info (&rest args)
  37. "Run `info' command on NAME.
  38. NAME is the car of ARGS.
  39. This function is intended to be used as a substitution for
  40. `eshell/info'. It does the following:
  41. info => go to top info window;
  42. info NAME => if NAME is a file '*.info', visit it;
  43. info NAME => otherwise go to top info node and then menu item NAME."
  44. (require 'info)
  45. (let* ((name (car args))
  46. (file (and (stringp name)
  47. (string-match "\\.info" name)
  48. (expand-file-name name))))
  49. (if (and file (file-exists-p file))
  50. (Info-find-node file "Top")
  51. (Info-directory)
  52. (Info-menu name))))
  53. ;;; Prompt
  54. ;; Idea from <http://www.emacswiki.org/emacs/EshellPrompt>.
  55. ;; TODO improve regexp
  56. (defvar al/eshell-prompt-regexp "^[#$] "
  57. "Regexp for `eshell-prompt-regexp'.")
  58. (defmacro al/with-face (str &rest properties)
  59. `(propertize ,str 'face (list ,@properties)))
  60. (defun al/eshell-prompt ()
  61. "Function for `eshell-prompt-function'."
  62. (format "%s %s%s%s %s\n%s "
  63. (al/with-face (format-time-string "%H:%M" (current-time))
  64. 'font-lock-comment-face)
  65. (eshell/whoami)
  66. (al/with-face "@"
  67. 'escape-glyph)
  68. (system-name)
  69. (al/with-face (abbreviate-file-name (eshell/pwd))
  70. 'dired-directory)
  71. (al/with-face (if (= (user-uid) 0) "#" "$")
  72. 'comint-highlight-prompt)))
  73. ;;; Input (command) line
  74. (defun al/eshell-input-at-point ()
  75. "Return eshell input from the current input (command) line.
  76. Return nil, if the current line is not the input line."
  77. (when (save-excursion
  78. (beginning-of-line)
  79. (looking-at eshell-prompt-regexp))
  80. (buffer-substring-no-properties
  81. (save-excursion (eshell-bol) (point))
  82. (line-end-position))))
  83. ;;;###autoload
  84. (defun al/eshell-send-input-maybe ()
  85. "Call `eshell-send-input' if the point is on the command line."
  86. (interactive)
  87. (when (< (point) eshell-last-output-end)
  88. (let ((input (al/eshell-input-at-point)))
  89. (if (null input)
  90. (user-error (substitute-command-keys "\
  91. You don't want to do \"\\[al/eshell-send-input-maybe]\" here"))
  92. (goto-char eshell-last-output-end)
  93. (delete-region eshell-last-output-end (point-max))
  94. (insert input))))
  95. (eshell-send-input))
  96. ;;; History
  97. (require 'em-hist)
  98. ;;;###autoload
  99. (defun al/eshell-previous-matching-input-from-input (arg)
  100. "Search backwards through input history for match for current input.
  101. Unlike `eshell-previous-matching-input-from-input', the matching
  102. input is not forced to begin with the current input."
  103. (interactive "p")
  104. (unless (memq last-command '(al/eshell-previous-matching-input-from-input
  105. al/eshell-next-matching-input-from-input))
  106. ;; Starting a new search.
  107. (setq eshell-matching-input-from-input-string
  108. (buffer-substring (save-excursion (eshell-bol) (point))
  109. (point))
  110. eshell-history-index nil))
  111. (eshell-previous-matching-input
  112. (regexp-quote eshell-matching-input-from-input-string)
  113. arg))
  114. ;;;###autoload
  115. (defun al/eshell-next-matching-input-from-input (arg)
  116. "Search forwards through input history for match for current input."
  117. (interactive "p")
  118. (al/eshell-previous-matching-input-from-input (- arg)))
  119. (provide 'al-eshell)
  120. ;;; al-eshell.el ends here