You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
12 KiB
12 KiB
Completion configuration using ivy, counsel and friends
selectrum
(use-package selectrum
:ensure t
:init
(defun jao-selectrum--ord-refine (&rest args)
(let ((completion-styles '(orderless)))
(apply #'selectrum-refine-candidates-using-completions-styles args)))
(defun jao-selectrum-orderless ()
(interactive)
(setq selectrum-refine-candidates-function #'jao-selectrum--ord-refine)
(setq selectrum-highlight-candidates-function #'orderless-highlight-matches)
(setq orderless-skip-highlighting (lambda () selectrum-is-active)))
:config
;; https://github.com/raxod502/selectrum/wiki/Ido,-icomplete(fido)-emulation
(defun selectrum-fido-backward-updir ()
"Delete char before or go up directory, like `ido-mode'."
(interactive)
(if (and (eq (char-before) ?/)
(eq (selectrum--get-meta 'category) 'file))
(save-excursion
(goto-char (1- (point)))
(when (search-backward "/" (point-min) t)
(delete-region (1+ (point)) (point-max))))
(call-interactively 'backward-delete-char)))
(defun selectrum-fido-delete-char ()
"Delete char or maybe call `dired', like `ido-mode'."
(interactive)
(let ((end (point-max)))
(if (or (< (point) end) (not (eq (selectrum--get-meta 'category) 'file)))
(call-interactively 'delete-char)
(dired (file-name-directory (minibuffer-contents)))
(exit-minibuffer))))
(defun selectrum-fido-ret ()
"Exit minibuffer or enter directory, like `ido-mode'."
(interactive)
(let* ((dir (and (eq (selectrum--get-meta 'category) 'file)
(file-name-directory (minibuffer-contents))))
(current (selectrum-get-current-candidate))
(probe (and dir current
(expand-file-name (directory-file-name current) dir))))
(if (and probe (file-directory-p probe) (not (string= current "./")))
(selectrum-insert-current-candidate)
(selectrum-select-current-candidate))))
;; (define-key selectrum-minibuffer-map (kbd "RET") 'selectrum-fido-ret)
(define-key selectrum-minibuffer-map (kbd "DEL") 'selectrum-fido-backward-updir)
(define-key selectrum-minibuffer-map (kbd "C-d") 'selectrum-fido-delete-char)
:custom ((selectrum-complete-in-buffer t)
;; (selectrum-display-action '(display-buffer-at-bottom))
(selectrum-extend-current-candidate-highlight t)
(selectrum-fix-vertical-window-height nil)
(selectrum-max-window-height 20)
(selectrum-show-indices nil)
(selectrum-count-style 'current/matches))
:bind (("C-R" . selectrum-repeat)))
ivy
(use-package ivy
:ensure t
:demand t
:custom
((ivy-count-format "(%d/%d) ")
(ivy-do-completion-in-region t)
(ivy-height 20)
(ivy-re-builders-alist '((counsel-ag . ivy--regex)
(counsel-rg . ivy--regex)
(counsel-yank-pop . ivy--regex)
(swiper . ivy--regex)
(swiper-isearch . ivy--regex)
(t . ivy--regex-fuzzy)))
(ivy-use-virtual-buffers t)
(ivy-virtual-abbreviate 'abbreviate)
(ivy-wrap t))
:config
;; used by ivy--regex-fuzzy to order results
(use-package flx :ensure t)
;; Try C-o in the minibuffer
(use-package ivy-hydra
:after ivy
:ensure t
:init (setq ivy-read-action-function #'ivy-hydra-read-action))
(add-to-list 'ivy-initial-inputs-alist
'(gnus-summary-move-article . ""))
:bind (("C-R" . ivy-resume)
("C-x b" . ivy-switch-buffer)
("C-c v" . ivy-push-view)
("C-c V" . ivy-pop-view))
:diminish)
counsel
(use-package counsel
:ensure t
:custom ((counsel-describe-function-function 'helpful-callable)
(counsel-describe-variable-function 'helpful-variable)
(counsel-find-file-at-point t)
(counsel-linux-app-format-function
#'counsel-linux-app-format-function-name-pretty)
(counsel-mode-override-describe-bindings nil)
(counsel-recentf-include-xdg-list t))
:config
:bind (("C-s" . swiper-isearch)
("C-S-s" . isearch-forward)
("M-x" . counsel-M-x)
("C-x f" . counsel-find-file)
("C-c k" . counsel-ag)
("C-c K" . counsel-rg)
("C-c l" . counsel-locate)
("C-c b" . counsel-git)
("C-c i" . counsel-imenu)
("C-c G" . counsel-search)
("s-r" . counsel-linux-app))
:diminish)
counsel add-ons
notmuch
(use-package counsel-notmuch
:ensure t
:config (with-eval-after-load "gnus-group"
(define-key gnus-group-mode-map "Gg" 'counsel-notmuch)))
recoll
(require 'jao-recoll)
(defvar jao-counsel-recoll--history nil)
(defun jao-counsel-recoll--function (str)
(let ((xs (counsel-recoll-function str)))
(cl-remove-if-not (lambda (x) (string-prefix-p "file://" x)) xs)))
(defun jao-counsel-recoll (&optional initial-input)
(interactive)
(counsel-require-program "recoll")
(ivy-read "recoll: " 'jao-counsel-recoll--function
:initial-input initial-input
:dynamic-collection t
:history 'jao-counsel-recoll--history
:action (lambda (x)
(when (string-match "file://\\(.*\\)\\'" x)
(let ((file-name (match-string 1 x)))
(if (string-match "pdf$" x)
(jao-open-doc file-name)
(find-file file-name)))))
:unwind #'counsel-delete-process
:caller 'jao-counsel-recoll))
(defun jao-counsel-recoll--recoll (_s) (jao-recoll ivy-text))
(ivy-set-actions 'jao-counsel-recoll
'(("x" jao-counsel-recoll--recoll "List in buffer")))
(global-set-key (kbd "C-c R") #'jao-counsel-recoll)
ivy rich
(use-package ivy-rich
:after (ivy counsel)
:ensure t
:custom ((ivy-rich-path-style 'relative)
(ivy-rich-parse-remote-buffer nil)
(ivy-rich-parse-remote-file-path nil))
:config
(ivy-rich-modify-columns
'ivy-switch-buffer
'((ivy-rich-candidate (:width 80))
(ivy-rich-switch-buffer-indicators (:face jao-themes-f00))
(ivy-rich-switch-buffer-project (:width 15))
(ivy-rich-switch-buffer-major-mode (:width 15 :face jao-themes-f12)))))
cmap
(jao-load-path "cmap")
(use-package cmap
:demand t
:bind (("C-;" . cmap-cmap)
("C-'" . cmap-default)))
prompter
(defun jao-cmap--hide-help ()
(when-let ((w (get-buffer-window (help-buffer))))
(with-selected-window w (kill-buffer-and-window))))
(defun jao-cmap--prompter (keymap)
(let ((display-buffer-alist '(("*Help*"
(display-buffer-at-bottom)
(window-parameters (mode-line-format . none))
(window-height . fit-window-to-buffer)))))
(let ((inhibit-message t))
(describe-keymap keymap))))
(defun jao-cmap--prompter-done ()
(save-current-buffer (jao-cmap--hide-help)))
(setq cmap-prompter #'jao-cmap--prompter)
(setq cmap-prompter-done #'jao-cmap--prompter-done)
minibuffer actions
(defun jao-cmap--completion-metadata ()
(completion-metadata
(buffer-substring-no-properties (field-beginning) (point))
minibuffer-completion-table
minibuffer-completion-predicate))
(defun jao-cmap--completion-category ()
(completion-metadata-get (jao-cmap--completion-metadata) 'category))
(defmacro cmap-define-keymap (v d &rest b)
`(defvar ,v (cmap-keymap ,@b) ,d))
(cmap-define-keymap jao-cmap-buffer-map
"Keymap for buffer actions."
("k" . kill-buffer)
("b" . switch-to-buffer)
("o" . switch-to-buffer-other-window)
("z" . bury-buffer)
("q" . kill-buffer-and-window)
("=" . ediff-buffers))
;; (cmap-define-keymap espotify-item-keymap
;; "Actions for Spotify search results"
;; ("a" espotify--play-album)
;; ("h" espotify--show-info))
(defvar jao-cmap--smaps
'((command . cmap-command-map)
;; (espotify-search-item . espotify-item-keymap)
(function . cmap-function-map)
(variable . cmap-variable-map)
(face . cmap-face-map)
(buffer . jao-cmap-buffer-map)
(consult-buffer . jao-cmap-buffer-map)))
(defun jao-cmap-target-minibuffer-candidate ()
(when (minibuffer-window-active-p (selected-window))
(let ((cand (ivy-state-current ivy-last))
(cat (jao-cmap--completion-category)))
(when-let (m (alist-get cat jao-cmap--smaps))
(cons m cand)))))
(add-to-list 'cmap-targets #'jao-cmap-target-minibuffer-candidate)
url / video actions
(defvar jao-cmap-video-url-rx
(format "^https?://\\(?:www\\.\\)?%s/.+"
(regexp-opt '("youtu.be"
"youtube.com"
"blip.tv"
"vimeo.com"
"infoq.com")
t))
"A regular expression matching URLs that point to video streams")
(defun jao-cmap--play-video (player url)
(interactive "sURL: ")
(let ((cmd (format "%s %s" player (shell-quote-argument url))))
(start-process-shell-command player nil cmd)))
(defun jao-cmap-mpv (&optional url)
"Play video stream with mpv"
(interactive "sURL: ")
(jao-cmap--play-video "mpv" url))
(defun jao-cmap-vlc (&optional url)
"Play video stream with vlc"
(interactive "sURL: ")
(jao-cmap--play-video "vlc" url))
(defun jao-cmap-target-w3m-url ()
(when-let (url (or (thing-at-point-url-at-point)
(w3m-anchor)
w3m-current-url))
(cons 'cmap-url-map url)))
(defun jao-cmap-kill (&optional x)
"Save to kill ring"
(interactive "s")
(kill-new x))
(defun jao-cmap-url (url)
"Browse URL, externally if we're already in emacs-w3m"
(if (derived-mode-p 'w3m-mode)
(jao-browse-with-external-browser url)
(browse-url url)))
(define-key cmap-url-map [return] #'jao-cmap-url)
(define-key cmap-url-map "f" #'browse-url-firefox)
(define-key cmap-url-map "w" #'jao-cmap-kill)
(defun jao-cmap-target-video-url ()
(when-let (url (jao-cmap-target-w3m-url))
(when (string-match-p jao-cmap-video-url-rx (cdr url))
(cons 'jao-cmap-video-url-map (cdr url)))))
(cmap-define-keymap jao-cmap-video-url-map
"Actions on URLs pointing to remote video streams."
("v" . jao-cmap-vlc)
([return] . jao-cmap-mpv))
(add-to-list 'cmap-targets #'jao-cmap-target-w3m-url)
(add-to-list 'cmap-targets #'jao-cmap-target-video-url)
hooks
(with-eval-after-load "exwm"
(add-to-list 'exwm-input-global-keys '([?\s-r] . counsel-linux-app)))
(with-eval-after-load "espotify"
(require 'ivy-spotify)
(defalias 'jao-spotify-album #'ivy-spotify-album)
(defalias 'jao-spotify-track #'ivy-spotify-track)
(defalias 'jao-spotify-artist #'ivy-spotify-artist)
(defalias 'jao-spotify-playlist #'ivy-spotify-playlist))
startup
(ivy-mode 1)
(counsel-mode 1)
(ivy-rich-mode 1)
(ivy-rich-project-root-cache-mode 1)