summaryrefslogtreecommitdiff
path: root/tab-conf.el
blob: afe5047582110037f0efca12a049e64462a2277a (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
;;; tab-conf.el --- My configurations of the tabs -*- lexical-binding: t; -*-

(require 'tab-bar)

(setq tab-bar-format nil)

(define-key tab-switcher-mode-map (vector ?n) #'tab-switcher-next-or-first)
(define-key tab-switcher-mode-map (vector ?p) #'tab-switcher-prev-or-last)
(define-key tab-prefix-map (vector 'tab) #'tab-switcher)
(define-key tab-prefix-map (vector ?c) #'durand-tab-list)
(define-key tab-prefix-map (vector ?à) #'tab-close)

(define-key global-map (vector ?\s-t) #'durand-switch-tab-dwim)
(define-key global-map (vector ?\s-T) #'tab-switcher)

;;;###autoload
(defun durand-switch-tab-dwim (&optional arg)
  "Do what I mean if I want to switch tabs.

If there is only one tab, or if ARG is '(4), create another one,
prompting me for the buffer to display in the new tab.

If there are two tabs and ARG is not '(4) or '(16) or 0, just
switch between them.

If ARG is 0, then use `completing-read' to read an action from
`find-file-other-tab', `dired-other-tab', `tab-rename'.

If there are more than two tabs and if ARG is not '(4) or '(16)
or 0, then use `completing-read' to ask for a tab to switch to.

If ARG is '(16), then use `completing-read' to ask for a tab to
delete. The default is the current tab. However, if there is only
one tab, create another one, prompting me for the buffer to
display in the new tab."
  (interactive "P")
  (let ((tabs (seq-sort
               (lambda (t1 t2)
                 (cond
                  ((null (assoc 'time t1)))
                  ((null (assoc 'time t2)) nil)
                  (t (> (alist-get 'time t1)
                        (alist-get 'time t2)))))
               (tab-bar-tabs))))
    (cond
     ((equal arg 0)
      (let* ((action-list (list
                           (cons"f: file" 'find-file-other-tab)
                           (cons "d: dired" 'dired-other-tab)
                           (cons "r: rename" 'tab-rename)))
             (action (cdr
                      (assoc
                       (minibuffer-with-setup-hook 'durand-headlong-minibuffer-setup-hook
                         (completing-read "Choose an action: "
                                          action-list nil t))
                       action-list #'string=)))
             (current-prefix-arg nil))
        (call-interactively action)))
     ((or (equal arg (cons 4 nil))
          (null (cdr tabs)))
      (switch-to-buffer-other-tab (read-buffer "Switch to buffer in a new tab"
                                               (other-buffer))))
     ((and (cdr tabs)
           (null (cddr tabs))
           (not (or (equal arg (cons 4 nil))
                    (equal arg (cons 16 nil))
                    (equal arg 0))))
      (tab-bar-switch-to-tab (cdr (assoc 'name (cadr tabs)))))
     ((not (or (equal arg (cons 4 nil))
               (equal arg (cons 16 nil))
               (equal arg 0)))
      (tab-bar-switch-to-tab
       (completing-read (format
                         "Switch to tab by name (default %s): "
                         (cdr (assoc 'name (cadr tabs))))
                        (mapcar (lambda (tab)
                                  (cdr (assoc 'name tab)))
                                tabs)
                        nil nil nil nil
                        (cdr (assoc 'name (cadr tabs))))))
     ((equal arg (cons 16 nil))
      (tab-bar-close-tab-by-name
       (completing-read (format "Close tab (default %s) : "
                                (cdr (assoc 'name (car tabs))))
                        (mapcar (lambda (tab)
                                  (cdr (assoc 'name tab)))
                                tabs)
                        nil nil nil nil
                        (cdr (assoc 'name (car tabs)))))))))

;;;###autoload
(defun tab-switcher-first ()
  "Go to the first window configuration line."
  (interactive)
  (goto-char (point-min))
  (skip-chars-forward "[:space:]\n")
  (forward-char -1))

;;;###autoload
(defun tab-switcher-last ()
  "Go to the last window configuration line."
  (interactive)
  (goto-char (point-max))
  (skip-chars-backward "[:space:]\n")
  (goto-char (line-beginning-position))
  (skip-chars-forward "[:space:]")
  (forward-char -1))

;;;###autoload
(defun tab-switcher-next-or-first ()
  "Go to the next configuration line.
If the next line is not a configuration line, 
then go to the first configuration line."
  (interactive)
  (forward-line 1)
  (cond
   ((looking-at "^\\s-*$")
    (tab-switcher-first))
   (t (skip-chars-forward "[:space:]")
      (forward-char -1))))

;;;###autoload
(defun tab-switcher-prev-or-last ()
  "Go to the previous configuration line.
If the previous line is not a configuration line, 
then go to the last configuration line."
  (interactive)
  (forward-line -1)
  (cond
   ((looking-at "^\\s-*$")
    (tab-switcher-last))
   (t (skip-chars-forward "[:space:]")
      (forward-char -1))))

(defun durand-tab-list ()
  "List all tabs in the echo area."
  (interactive)
  (let* ((tabs (tab-bar-tabs))
         (str (mapconcat
               (lambda (tab)
                 (propertize
                  (cdr (assoc 'name (cdr tab)))
                  'face
                  (cond ((eq (car tab) 'current-tab)
                         'success)
                        ('default))))
               tabs
               " | ")))
    (message "%d tab%s: %s"
             (length tabs)
             (cond ((> (length tabs) 1) "s")
                   (""))
             str)))