summaryrefslogtreecommitdiff
path: root/ibuffer.el
blob: 888e2696ea97fc1b5e9ef085cd3a44ef17c8a97f (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
;;; -*- lexical-binding: t; -*-

(require 'ibuffer)
(require 'ibuf-ext)

(setq ibuffer-expert t)
(setq ibuffer-display-summary nil)

(setq ibuffer-show-empty-filter-groups nil)

;;; Bindings related to buffers

;;;; Quickly switch to the last buffer.

;;;###autoload
(defun durand-switch-to-last-buffer (&optional arg)
  "Switch to the last buffer.

The last buffer is given by `other-buffer'.

If ARG is non-nil, then display the last buffer in a new window."
  (interactive "P")
  (cond
   (arg (switch-to-buffer-other-window nil))
   ((switch-to-buffer nil))))

;;;###autoload
(defun durand-switch-to-last-buffer-other-window ()
  "Switch to the last buffer in a new window."
  (interactive)
  (switch-to-buffer-other-window nil))

;;;###autoload
(defun switch-to-buffer-same-mode (&optional arg)
  "Switch to a buffer with the same major mode as the current
   buffer.
If the optional ARG is non-nil, then produce an IBUFFER buffer
  listing all buffers of the same mode as the current buffer."
  (interactive "P")
  (cond
   ((null arg)
    (let* ((mode (buffer-local-value 'major-mode (current-buffer)))
           (def (buffer-name
                 (car
                  (delete nil
                          (mapcar
                           (lambda (buf)
                             (and
                              (provided-mode-derived-p
                               (buffer-local-value 'major-mode buf)
                               mode)
                              (not (= (aref (buffer-name buf) 0) 32))
                              (not (eq buf (current-buffer)))
                              buf))
                           (buffer-list)))))))
      (switch-to-buffer
       (read-buffer (format
                     "Switch to buffer with major mode %S:"
                     (buffer-local-value 'major-mode (current-buffer)))
                    def t
                    (lambda (name-or-cons)
                      (provided-mode-derived-p
                       (buffer-local-value
                        'major-mode
                        (cond ((consp name-or-cons)
                               (cdr name-or-cons))
                              ((get-buffer name-or-cons))))
                       mode))))))
   ((ibuffer
     nil
     (format "*Buffers for %S*"
             (buffer-local-value 'major-mode (current-buffer)))
     (list (cons 'used-mode
                 (buffer-local-value 'major-mode (current-buffer))))))))

;;;###autoload
(defvar durand-clear-passlist nil
  "The list of buffers that should not be deleted \
automatically.")

;; from dashboard.el
(defvar dashboard-buffer-name)

(cond
 ((null dashboard-buffer-name)
  (setq dashboard-buffer-name "")))

(setq durand-clear-passlist
      (list dashboard-buffer-name
            "*Group*"
            ".newsrc-dribble"))

;;;###autoload
(defun durand-ibuffer-clear (&optional arg)
  "Kill every buffer except for those in `durand-clear-passlist'.
If the optional ARG is non-nil, then restrict the range to the
marked buffers."
  (interactive "P")
  (cond
   ((derived-mode-p 'ibuffer-mode))
   ((user-error "durand-ibuffer-clear should only be used in \
derived modes of `ibuffer-mode'.")))
  (cond
   ((null arg)
    (mapc (function
           (lambda (buffer)
             (cond
              ((durand-member (buffer-name buffer)
                              durand-clear-passlist
                              #'string=))
              ((kill-buffer buffer)))))
          (cons
           (current-buffer)
           (mapcar #'car (ibuffer-current-state-list))))
    (with-current-buffer dashboard-buffer-name
      (let ((inhibit-message t))
        (goto-char (point-max))
        (recenter -1))))
   (t
    (mapc (function
           (lambda (buffer-and-mark)
             (cond
              ((or (/= (cdr buffer-and-mark)
                       ibuffer-marked-char)
                   (durand-member (buffer-name (car buffer-and-mark))
                                  durand-clear-passlist
                                  #'string=)))
              ((kill-buffer (car buffer-and-mark))))))
          (cons
           (cons (current-buffer) 32)
           (ibuffer-current-state-list)))
    (ibuffer-update nil t))))

(define-key global-map (vector 24 2) #'ibuffer)
(define-key global-map (vector ?\s-h) #'ibuffer)
(define-key global-map (vector ?\M-\s-b) #'switch-to-buffer-same-mode)
(define-key global-map (vector ?\s-b) #'switch-to-buffer)
(define-key global-map (vector ?\s-B) #'switch-to-buffer-other-window)
(define-key global-map (vector ?\s-n) #'durand-switch-to-last-buffer)
(define-key global-map (vector ?\s-N) #'durand-switch-to-last-buffer-other-window)

(define-key ibuffer-mode-map (vector ?d) #'ibuffer-do-delete)
(define-key ibuffer-mode-map (vector ?D) #'ibuffer-mark-for-delete)
(define-key ibuffer-mode-map (vector ?c) #'durand-ibuffer-clear)

;;; filter for bongo

;;;###autoload
(define-ibuffer-filter durand-bongo
    "Group bongo buffers together."
  (:description "Bongo buffers together"
                :reader (read-string "no effect: "))
  (cond
   ((not (boundp 'durand-bongo-music-dir))
    (load-config "bongo.el")))
  (with-current-buffer buf
    (cond
     ((derived-mode-p 'dired-mode)
      (let ((bongo-dirs durand-bongo-music-dir)
            found)
        (while (and (not found)
                    (consp bongo-dirs))
          (cond
           ((file-in-directory-p default-directory (car bongo-dirs))
            (setq found t))
           (t (setq bongo-dirs (cdr bongo-dirs)))))
        found))
     ((derived-mode-p 'bongo-playlist-mode 'bongo-library-mode)))))

;;;###autoload
(define-ibuffer-filter durand-directory
    "Limit current view to buffers with directory a subdirectory of \
QUALIFIER.

For a buffer not associated with a file, this matches against the
value of `default-directory' in that buffer."
  (:description "directory name"
   :reader (read-from-minibuffer "Filter by directory name (regex): "))
  (ibuffer-aif (with-current-buffer buf (ibuffer-buffer-file-name))
      (let ((dirname (expand-file-name (file-name-directory it))))
        (when dirname
          (string-match-p
           (expand-file-name qualifier)
           dirname)))
    (when (with-current-buffer buf default-directory)
      (string-match-p (expand-file-name qualifier)
                      (expand-file-name
                       (with-current-buffer buf
                         default-directory))))))

;;;###autoload
(defun durand-bongo-set-filter ()
  "Set my custom filters."
  (interactive)
  (setq ibuffer-filter-groups
        (list (cons "Bongo" '((durand-bongo)))
              (cons "C" '((mode . c-mode)))
              (cons "ELisp" '((mode . emacs-lisp-mode)))
              (cons "EWW" '((mode . eww-mode)))
              (cons "Roman" '((mode . novel-read-mode)))))
  (let ((ibuf (get-buffer "*Ibuffer*")))
    (when ibuf
      (with-current-buffer ibuf
        ;; (pop-to-buffer ibuf)
        (ibuffer-update nil t)))))

(add-hook 'ibuffer-hook 'durand-bongo-set-filter 100)