随手写的eshell util

(defun eshell-list-eshell-buffers ()
  (interactive)
  (let* ((eshell-buffers 
          (delq nil (mapcar (lambda (buf)
                              (when (eq 'eshell-mode (buffer-local-value 'major-mode buf))
                                (let* ((buf-name (buffer-name buf))
                                       (buf-dir (buffer-local-value 'default-directory buf)))
                                  (cl-list* buf-dir buf-name))))
                            (buffer-list)))))
    eshell-buffers))

(defun eshell-switch-to-buffer ()
  (interactive)
  (let* ((eshell-buffers (eshell-list-eshell-buffers))
         (eshell-buffers-dirs (mapcar #'car eshell-buffers))
         (buf-dir (completing-read "Switch to eshell buffer: " eshell-buffers-dirs nil t))
         (buf (assoc-default buf-dir eshell-buffers)))
    (switch-to-buffer buf)))

大家觉得好用可以拿去用

2 个赞

几个小的代码建议:

  1. eshell-list-eshell-buffers 不需要(interactive)
  2. eshell-list-eshell-buffers 里,可以把(let* ((eshell-buffers EXPR)) eshell-buffers) 直接改写为EXPR
  3. 看到你用了几次buffer-*函数,可以用with-current-buffer,然后直接引用变量名。
  4. (cl-list* a b) 等价于 (cons a b)
  5. (eq MODE major-mode) 约等于 (derived-mode-p MODE)
  6. eshell-list-eshell-buffers的λ中,看到你用了buf-name,可以直接用buf,因为switch-to-buffer可以直接接受buffer实例。
  7. (when (let* ((buf-name ...) (buf-dir ...)) ...)),并且逻辑上来说buf-namebuf-dir不为nil,所以可以试试when-let
  8. (delq nil (mapcar (λ ... (when-let ... EXPR)) ...))可以改写成(mapcan (λ ... (when-let ... (list EXPR))))。这里可以理解为,每次调用λ,会把结果列表append到上一次的结果列表里面去。
  9. completing-read接受alist作为collection(只用其car,忽略其cdr),所以不用mapcar #‘car,直接把eshell-buffers给进去。

另外,如何区分多个不同的,且default-directory在同一个文件夹的eshell buffer?

6 个赞
(defun campania/eshell-list-eshell-buffers ()
  (mapcan (lambda (buf)
            (with-current-buffer buf
              (when (derived-mode-p 'eshell-mode)
                (list (cons (buffer-name) default-directory))))) 
          (buffer-list)))

(defun campania/eshell-buffer-annotation-fn (str)
  (let* ((dir-name (assoc-default str minibuffer-completion-table)))
    (concat "\t\t" dir-name)))

(defun campania/eshell-switch-to-buffer ()
  (interactive)
  (let* ((eshell-buffers (campania/eshell-list-eshell-buffers))
         (completion-extra-properties 
          '(:annotation-function campania/eshell-buffer-annotation-fn))
         (buf-name (completing-read "Switch to eshell buffer: " eshell-buffers)))
    (switch-to-buffer buf-name)))

照你说的改了一下,谢谢!

1 个赞

看到你用了cl-flet,不知道你注意到docstring里提到没有,cl-flet定义一个函数有简易写法,不用带λ。

(cl-flet ((foo (arg1 arg2) (+ arg1 arg2 42)))
  (foo 1 2))

或者把cl-letf替换成let,然后把底下的#‘aux换成aux

或者也可以直接省掉let / cl-flet,直接把λ作为mapcan的第一个参数。

3 个赞

(゚∀゚) ty again

自己用了一天感觉挺好使的