ido-mini/ido-mini.el

238 lines
9.2 KiB
EmacsLisp

;; ;; thanks to wilfredh -
;; ;; https://gist.github.com/Wilfred/31e8e0b24e3820c24850920444dd941d
;; (defun wh/ido-switch-buffer-with-filename ()
;; "Switch to a buffer with ido, including the filename in the prompt."
;; (interactive)
;; (let* ((bufs (buffer-list))
;; (bufs-with-paths
;; (--map (with-current-buffer it
;; (if (buffer-file-name)
;; (format "%s <%s>" (buffer-name) (buffer-file-name))
;; (buffer-name)))
;; bufs))
;; (chosen-index
;; (-elem-index
;; (ido-completing-read
;; "Switch to buffer: " bufs-with-paths)
;; bufs-with-paths)))
;; (switch-to-buffer (nth chosen-index bufs))))
;; (defun im/buffer-dc-alist ()
;; "Return an alist of buffer names and buffer-display-count
;; values."
;; (-zip (im/buffer-names)
;; (--map (with-current-buffer it
;; buffer-display-count)
;; (buffer-list))))
;; (defun im/buffer-dc-alist-sorted ()
;; "Return alist created by `im/buffer-dc-alist', sorted by
;; buffer-display-count values."
;; (--sort (> (cdr it) (cdr other))
;; (im/buffer-dc-alist)))
;; (defun im/buffer-list-dc-sorted ()
;; "Like `buffer-list' but sorted by buffer-display-count
;; values."
;; (-map 'car (im/buffer-dc-alist-sorted)))
;; TODO - make all operations on buffer list and recentf-list -
;; sorting, addition of paths, coloring into their own single
;; functions, and the functions user-definable via "-function"
;; variables.
;; TODO - colors!
;; - dired buffers - major-mode
;; - unsaved buffers - buffer-modified-p
;; - buffers modified outside emacs - verify-visited-file-modtime
;; - buffers with deleted files - buffer-file-name -> file-exists-p
;; - and maybe the matched substring in the candidates
;; TODO - clean input history, do not store file paths
;; TODO - C-j to create buffer with the search string as name.
;; add variables to
;; - toggle displaying paths with buffer names
(defface im/unsaved-file
'((t :inherit font-lock-type-face)))
(defvar im/use-paths nil
"If non-nil, display file paths of the associated files of
buffers, where applicable (see function `im/add-paths').
Additionally, completion will search for buffer names as well as
their file paths.
Users may also find it useful to set this to nil and to enable
buffer uniquifying via `toggle-uniquify-buffer-names'.")
(defvar im/buffer-list-functions nil
"List of functions run sequentially over the output
of `(buffer-list)', with the result of one being the input of the
next (using `->list'). Each should accept exactly one argument.
`ido-mini' uses the resulting list for candidates.")
(defvar im/recentf-list-functions nil
"List of functions run sequentially over `recentf-list', with
the result of one being the input of the next (using `->list').
Each should accept exactly one argument. `ido-mini' uses the
resulting list for candidates.")
(defun im/buffer-names ()
"Return a list of the name of all buffers returned
by (buffer-list)."
(-map 'buffer-name (buffer-list)))
(defun ->list (var functions)
"Assuming FUNCTIONS is a list of functions (FN1 FN2 FN3),
return the result of (FN3 (FN2 (FN1 VAR)))"
(dolist (fn functions)
(setq var (funcall fn var)))
var)
;; (->list 1 '((lambda (a) (+ a 1))
;; (lambda (a) (+ a 2))
;; (lambda (a) (+ a 3)))) ;; => 7
(defun im/buffers-clean (buffer-names)
"Remove buffers whose names start with a space."
(cl-flet ((leading-space-p
(el)
(string-match-p "^ " el)))
(-remove #'leading-space-p buffer-names)))
(defun im/buffers-bury-visible (buffer-names)
"Put visible buffers at the end of list, in reverse order of
appearance (e.g. (vb1 b1 vb2 b2 ...) becomes (b1 b2 ... vb2
vb1))"
(let* ((bufs-wins-alist (-zip buffer-names
(-map 'get-buffer-window-list
buffer-names)))
(bufs-with-wins (-filter 'cdr bufs-wins-alist))
(bufs-wo-wins (-remove 'cdr bufs-wins-alist)))
(append
(-map 'car bufs-wo-wins)
(reverse (-map 'car bufs-with-wins)))))
(defun im/buffers-color (buffer-names)
(-map (lambda (buffer-name)
(with-current-buffer buffer-name
(cond ;; ((and (buffer-file-name)
;; (buffer-modified-p))
;; (propertize ))
((buffer-file-name)
(propertize buffer-name 'face 'font-lock-type-face))
((equal major-mode 'dired-mode)
(propertize buffer-name 'face 'dired-directory))
((string-match-p "^\\*" buffer-name)
(propertize buffer-name 'face 'italic))
(t buffer-name))))
(im/buffer-names)))
(defun im/recentf-bury-visited (recentf-list)
"Returns the contents of `recentf-list', with files being
visited by a buffer placed at the end of the list."
(append
(-remove #'get-file-buffer recentf-list)
(-filter #'get-file-buffer recentf-list)))
(defun im/recentf-color (recentf-list)
"Color recentf-list."
(-map (lambda (el) (propertize el 'face 'ido-virtual))
recentf-list))
(ido-completing-read
"Buffer:"
(append
(->list (im/buffer-names)
'(im/buffers-clean im/buffers-bury-visible im/buffers-color))
(->list recentf-list '(im/recentf-bury-visited
im/recentf-color))))
(defun im/prep-buffer-list ()
"Return a list of buffer names using `buffer-list', processed
the way ido-switch-buffer does."
(cl-flet ((leading-space-p
(el)
(string-match-p "^ " el)))
(let* ((bufs (im/buffer-names))
;; Remove buffers whose names start with a space
(bufs-main (-remove #'leading-space-p
bufs))
(bufs-space (-filter #'leading-space-p
bufs))
;; Put visible buffers at the end of list, in reverse order of appearance
;; (e.g. (vb1 b1 vb2 b2 ...) becomes (b1 b2 ... vb2 vb1))
(bufs-wins-alist (-zip bufs-main
(-map 'get-buffer-window-list
bufs-main)))
(bufs-with-wins (-filter 'cdr bufs-wins-alist))
(bufs-wo-wins (-remove 'cdr bufs-wins-alist)))
(append
(-map 'car bufs-wo-wins)
(reverse (-map 'car bufs-with-wins))))))
(defun im/recentf-list ()
"Returns the contents of `recentf-list', with files being
visited by a buffer placed at the end of the list."
(append
(-remove #'get-file-buffer recentf-list)
(-filter #'get-file-buffer recentf-list)))
(defun im/add-paths (&optional buflist)
"Add paths to a list of buffer names. If BUFLIST is nil or
omitted, use output from im/prep-buffer-list."
(let ((bufs (if buflist buflist (im/prep-buffer-list))))
(if im/use-paths
(--map (with-current-buffer it
(if (buffer-file-name)
(format "%s <%s>" (buffer-name) (buffer-file-name))
(buffer-name)))
(im/prep-buffer-list))
bufs)))
(defun im/color-recentf ()
"Color output from im/recentf-list."
(-map (lambda (el)
(propertize el 'face 'ido-virtual))
;; recentf-list
(im/recentf-list)))
(defun im/color-buffer-names ()
""
(-map (lambda (buffer)
(if (buffer-modified-p)
(propertize buffer 'face 'ido-indicator)))))
;; (defun im/clean)
(defun ido-mini ()
"A helm-mini replacement using Ido. Switch to a buffer or a
recentf entry with ido. If `im/use-paths' is non-nil,
search for and display the whole file path instead of just the
file name.
Using ido-vertical in conjunction may be beneficial.
Based off code from wilfredh -
https://gist.github.com/Wilfred/31e8e0b24e3820c24850920444dd941d"
(interactive)
(let*
((bufs (im/prep-buffer-list))
(bufs-with-paths (im/add-paths bufs))
(recentf-list-colored (im/color-recentf))
(bufs-and-recentf (append bufs-with-paths
recentf-list-colored))
(chosen-index
(-elem-index (ido-completing-read "Switch to buffer: "
bufs-and-recentf
nil nil nil
'ido-buffer-history)
bufs-and-recentf)))
;; is the chosen candidate in the buffer-list or recentf-list?
(if (< chosen-index (length bufs))
(switch-to-buffer (nth chosen-index
bufs))
(find-file (nth (- chosen-index (length bufs))
(im/recentf-list))))))
;; pipeline
;; recentf-list -> sorted recentf -> color
;; \
;; combine -> ido-completing-read -> select from sorted buffer/recentf list
;; /
;; (buffer-list) -> buffer names -> sort -> add paths -> color
;; | | |
;; (im/buffer-names) | (im/add-paths)
;; (im/prep-buffer-list)