summary refs log tree commit diff stats
path: root/lisp/+eshell.el
blob: 1f8677c6d66ffa9645602c1e67da58f9382d8656 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
;;; +eshell.el -*- lexical-binding: t; -*-

;;; Code:

;; https://karthinks.com/software/jumping-directories-in-eshell/
(defun eshell/z (&optional regexp)
  "Navigate to a previously visited directory in eshell, or to
any directory proferred by `consult-dir'."
  (let ((eshell-dirs (delete-dups
                      (mapcar 'abbreviate-file-name
                              (ring-elements eshell-last-dir-ring)))))
    (cond
     ((and (not regexp) (featurep 'consult-dir))
      (let* ((consult-dir--source-eshell `(:name "Eshell"
                                                 :narrow ?e
                                                 :category file
                                                 :face consult-file
                                                 :items ,eshell-dirs))
             (consult-dir-sources (cons consult-dir--source-eshell
                                        consult-dir-sources)))
        (eshell/cd (substring-no-properties
                    (consult-dir--pick "Switch directory: ")))))
     (t (eshell/cd (if regexp (eshell-find-previous-directory regexp)
                     (completing-read "cd: " eshell-dirs)))))))

;;; Start and quit

(defun +eshell-quit-or-delete-char (arg)
  "Delete the character to the right, or quit eshell on an empty line."
  (interactive "p")
  (if (and (eolp) (looking-back eshell-prompt-regexp))
      (eshell-life-is-too-much)
    (delete-forward-char arg)))

;;; Insert previous arguments
;; Record arguments

(defvar eshell-arg-history nil)
(defvar eshell-arg-history-index nil)
(add-to-list 'savehist-additional-variables 'eshell-arg-history)

(defun eshell-record-args (&rest _)
  "Record unique arguments onto the front of `eshell-arg-history'."
  (setq eshell-arg-history
        (cl-loop with history = eshell-arg-history
                 for arg in (reverse eshell-last-arguments)
                 do (setq history (cons arg (remove arg history)))
                 finally return history)))

(defun eshell-insert-prev-arg ()
  "Insert an argument from `eshell-arg-history' at point."
  (interactive)
  (if (eq last-command 'eshell-insert-prev-arg)
      (progn
        (let ((pos (point)))
          (eshell-backward-argument 1)
          (delete-region (point) pos))
        (if-let ((text (nth eshell-arg-history-index
                            eshell-arg-history)))
            (progn
              (insert text)
              (cl-incf eshell-arg-history-index))
          (insert (cl-first eshell-arg-history))
          (setq eshell-arg-history-index 1)))
    (insert (cl-first eshell-arg-history))
    (setq eshell-arg-history-index 1)))

;;;###autoload
(define-minor-mode eshell-arg-hist-mode
  "Minor mode to enable argument history, like bash/zsh with M-."
  :lighter "$."
  :keymap (let ((map (make-sparse-keymap)))
            (define-key map (kbd "M-.") #'eshell-insert-prev-arg)
            map)
  (if eshell-arg-hist-mode
      (add-hook 'eshell-post-command-hook #'eshell-record-args nil t)
    (remove-hook 'eshell-post-command-hook #'eshell-record-args t)))

;;;###autoload
(defmacro +eshell-eval-after-load (&rest forms)
  "Execute FORMS after Eshell is loaded.
If Eshell is already loaded in the session, immediately execute
forms.

I wrote this because Eshell doesn't properly do loading or
something, it's really annoying to work with."
  (declare (indent 0))
  `(progn
       (defun +eshell@setup ()
         "Setup the Eshell session."
         ,@forms)
       (when (featurep 'eshell)
         `(dolist (buf (buffer-list))
            (with-current-buffer buf
              (when (derived-mode-p 'eshell-mode)
                (+eshell@setup)))))
       '(add-hook 'eshell-mode-hook #'+eshell@setup)))

(provide '+eshell)
;;; +eshell.el ends here